Skip to content

Commit

Permalink
Merge pull request #15 from codermuss/ft/bg_tasks
Browse files Browse the repository at this point in the history
Ft/bg tasks
  • Loading branch information
codermuss authored Aug 4, 2024
2 parents 3575318 + d801092 commit 888b748
Show file tree
Hide file tree
Showing 44 changed files with 1,131 additions and 95 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode/launch.json
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ server:

mock:
mockgen -package mockdb -destination db/mock/store.go github.com/mustafayilmazdev/musarchive/db/sqlc Store
mockgen -package mockdb -destination worker/mock/distributor.go github.com/mustafayilmazdev/musarchive/worker TaskDistributor

locale:
musale --json=locales/assets/en.json --output=locales/localekeys.go -p=localization

.PHONY: postgres migrateup1 migrateup migratedown migratedown1 new_migration test sqlc server mock locale
redis:
docker run --name redis -p 6379:6379 -d redis:7.4-alpine

.PHONY: postgres migrateup1 migrateup migratedown migratedown1 new_migration test sqlc server mock locale redis
2 changes: 1 addition & 1 deletion api/category_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func TestGetCategories(t *testing.T) {
store := mockdb.NewMockStore(ctrl)
tc.buildStubs(store)

server := newTestServer(t, store)
server := newTestServer(t, store, nil)
recorder := httptest.NewRecorder()

url := "/v1/categories/index"
Expand Down
14 changes: 14 additions & 0 deletions api/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/google/uuid"

db "github.com/mustafayilmazdev/musarchive/db/sqlc"
localization "github.com/mustafayilmazdev/musarchive/locales"
"github.com/mustafayilmazdev/musarchive/util"
)

Expand All @@ -32,6 +33,7 @@ func newUserResponse(user db.User) UserResponse {
Username: user.Username,
FullName: user.FullName,
Email: user.Email,
Role: user.Role,
Avatar: user.Avatar,
BirthDate: user.BirthDate,
PasswordChangedAt: user.PasswordChangedAt,
Expand All @@ -40,6 +42,7 @@ func newUserResponse(user db.User) UserResponse {
}

func (server *Server) LoginUser(ctx *gin.Context) {
locale := ctx.Query(util.Locale)
var req loginUserRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
BuildResponse(ctx, BaseResponse{
Expand Down Expand Up @@ -85,6 +88,17 @@ func (server *Server) LoginUser(ctx *gin.Context) {
return
}

if !user.IsEmailVerified {
BuildResponse(ctx, BaseResponse{
Code: http.StatusUnauthorized,
Message: ResponseMessage{
Type: ERROR,
Content: server.lm.Translate(locale, localization.User_VerifyEmail),
},
})
return
}

accessToken, accessPayload, err := server.tokenMaker.CreateToken(int(user.ID), user.Role, server.config.AccessTokenDuration)
if err != nil {
BuildResponse(ctx, BaseResponse{
Expand Down
2 changes: 1 addition & 1 deletion api/login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func TestLoginUserAPI(t *testing.T) {
store := mockdb.NewMockStore(ctrl)
tc.buildStubs(store)

server := newTestServer(t, store)
server := newTestServer(t, store, nil)
recorder := httptest.NewRecorder()

// Marshal body data to JSON
Expand Down
7 changes: 4 additions & 3 deletions api/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,23 @@ import (
db "github.com/mustafayilmazdev/musarchive/db/sqlc"
localization "github.com/mustafayilmazdev/musarchive/locales"
"github.com/mustafayilmazdev/musarchive/util"
"github.com/mustafayilmazdev/musarchive/worker"
"github.com/rs/zerolog/log"
"github.com/stretchr/testify/require"
)

func newTestServer(t *testing.T, store db.Store) *Server {
func newTestServer(t *testing.T, store db.Store, taskDistributor worker.TaskDistributor) *Server {
config := util.Config{
TokenSymetricKey: util.RandomString(32),
AccessTokenDuration: time.Minute,
}

// Initialize the LocalizationManager singleton
if err := localization.Initialize("../" + util.LocalizationPath + util.DefaultLocale + util.LocalizationType); err != nil {
if err := localization.Initialize("../locales/assets/"); err != nil {

log.Fatal().Msg("Can not load localization")
}
server, err := NewServer(config, store)
server, err := NewServer(config, store, taskDistributor)
require.NoError(t, err)
return server
}
Expand Down
2 changes: 1 addition & 1 deletion api/middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func TestAuthMiddleware(t *testing.T) {
tc := testCases[i]

t.Run(tc.name, func(t *testing.T) {
server := newTestServer(t, nil)
server := newTestServer(t, nil, nil)
authPath := "/auth"
server.Router.GET(
authPath,
Expand Down
4 changes: 2 additions & 2 deletions api/post_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func TestCreatePostAPI(t *testing.T) {
store := mockdb.NewMockStore(ctrl)
tc.buildStubs(store)

server := newTestServer(t, store)
server := newTestServer(t, store, nil)
recorder := httptest.NewRecorder()

data, err := json.Marshal(tc.body)
Expand Down Expand Up @@ -303,7 +303,7 @@ func TestGetPostsAPI(t *testing.T) {
store := mockdb.NewMockStore(ctrl)
tc.buildStubs(store)

server := newTestServer(t, store)
server := newTestServer(t, store, nil)
recorder := httptest.NewRecorder()

data, err := json.Marshal(tc.body)
Expand Down
34 changes: 30 additions & 4 deletions api/register.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package api

import (
"fmt"
"net/http"
"time"

"github.com/gin-gonic/gin"
"github.com/hibiken/asynq"
"github.com/jackc/pgx/v5/pgtype"

db "github.com/mustafayilmazdev/musarchive/db/sqlc"
localization "github.com/mustafayilmazdev/musarchive/locales"
"github.com/mustafayilmazdev/musarchive/util"
"github.com/mustafayilmazdev/musarchive/worker"
)

type registerUserRequest struct {
Expand All @@ -34,6 +35,11 @@ type UserResponse struct {
CreatedAt time.Time `json:"created_at"`
}

type RegisterResponse struct {
User UserResponse `json:"user"`
Profile db.Profile `json:"profile"`
}

func (server *Server) RegisterUser(ctx *gin.Context) {

localeValue := ctx.Query("locale")
Expand Down Expand Up @@ -71,8 +77,13 @@ func (server *Server) RegisterUser(ctx *gin.Context) {
BirthDate: req.BirthDate,
}
argAfterCreate := func(user db.User) error {
fmt.Println("after create triggered")
return nil
taskPayload := &worker.PayloadSendVerifyEmail{Username: user.Username, Locale: localeValue}
opts := []asynq.Option{
asynq.MaxRetry(10),
asynq.ProcessIn(10 * time.Second),
asynq.Queue(worker.QueueCritical),
}
return server.taskDistributor.DistributeTaskSendVerifyEmail(ctx, taskPayload, opts...)
}

arg := db.RegisterUserTxParams{
Expand Down Expand Up @@ -105,9 +116,24 @@ func (server *Server) RegisterUser(ctx *gin.Context) {
return
}

registerResponse := RegisterResponse{
User: UserResponse{
ID: userAndProfile.User.ID,
Username: userAndProfile.User.Username,
FullName: userAndProfile.User.FullName,
Email: userAndProfile.User.Email,
Role: userAndProfile.User.Role,
Avatar: userAndProfile.User.Avatar,
BirthDate: userAndProfile.User.BirthDate,
PasswordChangedAt: userAndProfile.User.PasswordChangedAt,
CreatedAt: userAndProfile.User.CreatedAt,
},
Profile: userAndProfile.Profile,
}

BuildResponse(ctx, BaseResponse{
Code: http.StatusOK,
Data: userAndProfile,
Data: registerResponse,
Message: ResponseMessage{
Type: SUCCESS,
Content: server.lm.Translate(localeValue, localization.User_RegisterSuccess),
Expand Down
78 changes: 46 additions & 32 deletions api/register_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@ import (
mockdb "github.com/mustafayilmazdev/musarchive/db/mock"
db "github.com/mustafayilmazdev/musarchive/db/sqlc"
"github.com/mustafayilmazdev/musarchive/util"
mockwk "github.com/mustafayilmazdev/musarchive/worker/mock"
"github.com/stretchr/testify/require"
)

// Custom matcher for comparing InsertUserParams with hashed password
type eqCreateUserParamsMatcher struct {
arg db.InsertUserParams
arg db.RegisterUserTxParams
password string
}

func (e eqCreateUserParamsMatcher) Matches(x interface{}) bool {
arg, ok := x.(db.InsertUserParams)
arg, ok := x.(db.RegisterUserTxParams)
if !ok {
return false
}
Expand All @@ -39,8 +40,8 @@ func (e eqCreateUserParamsMatcher) Matches(x interface{}) bool {
}

e.arg.HashedPassword = arg.HashedPassword
var leftValue db.InsertUserParams = e.arg
var rightValue db.InsertUserParams = arg
var leftValue db.InsertUserParams = e.arg.InsertUserParams
var rightValue db.InsertUserParams = arg.InsertUserParams
result := reflect.DeepEqual(leftValue, rightValue)
return result
}
Expand All @@ -50,7 +51,7 @@ func (e eqCreateUserParamsMatcher) String() string {
}

// Helper function to create the custom matcher
func EqCreateUserParams(arg db.InsertUserParams, password string) gomock.Matcher {
func EqCreateUserParams(arg db.RegisterUserTxParams, password string) gomock.Matcher {
return eqCreateUserParamsMatcher{arg, password}
}

Expand All @@ -60,7 +61,7 @@ func TestCreateUserAPI(t *testing.T) {
testCases := []struct {
name string
body gin.H
buildStubs func(store *mockdb.MockStore)
buildStubs func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor)
checkResponse func(recoder *httptest.ResponseRecorder)
}{
{
Expand All @@ -74,19 +75,27 @@ func TestCreateUserAPI(t *testing.T) {
"role": user.Role,
"birth_date": user.BirthDate,
},
buildStubs: func(store *mockdb.MockStore) {
arg := db.InsertUserParams{
buildStubs: func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor) {
argUser := db.InsertUserParams{
Username: user.Username,
FullName: user.FullName,
Email: user.Email,
Avatar: user.Avatar,
BirthDate: user.BirthDate,
Role: user.Role,
}
store.EXPECT().
InsertUser(gomock.Any(), EqCreateUserParams(arg, password)).
Times(1).
Return(user, nil)
argAfterCreate := func(user db.User) error {
fmt.Println("after create triggered")
return nil
}
arg := db.RegisterUserTxParams{
InsertUserParams: argUser,
AfterCreate: argAfterCreate,
}
store.EXPECT().RegisterUserTx(gomock.Any(), EqCreateUserParams(arg, password)).Times(1).Return(db.RegisterUserTxResult{
User: user,
Profile: db.Profile{},
}, nil)
require.Equal(t, user.Role, util.Standard)
},
checkResponse: func(recorder *httptest.ResponseRecorder) {
Expand All @@ -102,11 +111,11 @@ func TestCreateUserAPI(t *testing.T) {
"full_name": user.FullName,
"email": user.Email,
},
buildStubs: func(store *mockdb.MockStore) {
buildStubs: func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor) {
store.EXPECT().
InsertUser(gomock.Any(), gomock.Any()).
RegisterUserTx(gomock.Any(), gomock.Any()).
Times(1).
Return(db.User{}, sql.ErrConnDone)
Return(db.RegisterUserTxResult{}, sql.ErrConnDone)
},
checkResponse: func(recorder *httptest.ResponseRecorder) {
require.Equal(t, http.StatusInternalServerError, recorder.Code)
Expand All @@ -120,7 +129,7 @@ func TestCreateUserAPI(t *testing.T) {
"full_name": user.FullName,
"email": user.Email,
},
buildStubs: func(store *mockdb.MockStore) {
buildStubs: func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor) {
store.EXPECT().
InsertUser(gomock.Any(), gomock.Any()).
Times(0)
Expand All @@ -137,11 +146,11 @@ func TestCreateUserAPI(t *testing.T) {
"full_name": user.FullName,
"email": user.Email,
},
buildStubs: func(store *mockdb.MockStore) {
buildStubs: func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor) {
store.EXPECT().
InsertUser(gomock.Any(), gomock.Any()).
RegisterUserTx(gomock.Any(), gomock.Any()).
Times(1).
Return(db.User{}, db.ErrUniqueViolation)
Return(db.RegisterUserTxResult{}, db.ErrUniqueViolation)
},
checkResponse: func(recorder *httptest.ResponseRecorder) {
require.Equal(t, http.StatusForbidden, recorder.Code)
Expand All @@ -155,7 +164,7 @@ func TestCreateUserAPI(t *testing.T) {
"full_name": user.FullName,
"email": "invalid-email",
},
buildStubs: func(store *mockdb.MockStore) {
buildStubs: func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor) {
store.EXPECT().
InsertUser(gomock.Any(), gomock.Any()).
Times(0)
Expand All @@ -172,7 +181,7 @@ func TestCreateUserAPI(t *testing.T) {
"full_name": user.FullName,
"email": user.Email,
},
buildStubs: func(store *mockdb.MockStore) {
buildStubs: func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor) {
store.EXPECT().
InsertUser(gomock.Any(), gomock.Any()).
Times(0)
Expand All @@ -188,11 +197,15 @@ func TestCreateUserAPI(t *testing.T) {
tc := testCases[i]

t.Run(tc.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
store := mockdb.NewMockStore(ctrl)
tc.buildStubs(store)
server := newTestServer(t, store)

storeCtrl := gomock.NewController(t)
defer storeCtrl.Finish()
store := mockdb.NewMockStore(storeCtrl)
taskCtrl := gomock.NewController(t)
defer taskCtrl.Finish()
taskDistributor := mockwk.NewMockTaskDistributor(taskCtrl)
tc.buildStubs(store, taskDistributor)
server := newTestServer(t, store, taskDistributor)
recorder := httptest.NewRecorder()
// Marshal body data to JSON
data, err := json.Marshal(tc.body)
Expand Down Expand Up @@ -228,6 +241,7 @@ func RandomUser(t *testing.T) (user db.User, password string) {
Valid: true,
Time: util.DateFixed(),
},
IsEmailVerified: true,
PasswordChangedAt: util.DateFixed(),
CreatedAt: util.DateFixed(),
}
Expand All @@ -248,13 +262,13 @@ func requireBodyMatchUser(t *testing.T, body *bytes.Buffer, expectedUser db.User
require.NoError(t, err)

// Unmarshal the Data field into a db.User
var gotUser db.User
err = json.Unmarshal(dataBytes, &gotUser)
var registerUserTxResult db.RegisterUserTxResult
err = json.Unmarshal(dataBytes, &registerUserTxResult)
require.NoError(t, err)

// Compare the expected and actual user fields
require.Equal(t, expectedUser.Username, gotUser.Username)
require.Equal(t, expectedUser.FullName, gotUser.FullName)
require.Equal(t, expectedUser.Email, gotUser.Email)
require.Empty(t, gotUser.HashedPassword)
require.Equal(t, expectedUser.Username, registerUserTxResult.User.Username)
require.Equal(t, expectedUser.FullName, registerUserTxResult.User.FullName)
require.Equal(t, expectedUser.Email, registerUserTxResult.User.Email)
require.Empty(t, registerUserTxResult.User.HashedPassword)
}
Loading

0 comments on commit 888b748

Please sign in to comment.