From 8adfd3e711b83a5ad0ed03de8b04d8edd7e99cfa Mon Sep 17 00:00:00 2001 From: martinyonatann Date: Sun, 24 Sep 2023 21:28:03 +0700 Subject: [PATCH] update user endpoint --- .../users/delivery/http/handler/handler.go | 62 ++++++++++++++++++- internal/users/delivery/http/route/route.go | 1 + internal/users/dtos/update_users.go | 32 ++++++++++ internal/users/entities/update_users.go | 3 +- internal/users/repository/repository.go | 25 ++++---- .../repository_query/users/select.sql | 2 +- .../repository_query/users/update.sql | 11 ++-- 7 files changed, 113 insertions(+), 23 deletions(-) create mode 100644 internal/users/dtos/update_users.go diff --git a/internal/users/delivery/http/handler/handler.go b/internal/users/delivery/http/handler/handler.go index 36bc087..dcccfe2 100644 --- a/internal/users/delivery/http/handler/handler.go +++ b/internal/users/delivery/http/handler/handler.go @@ -3,6 +3,7 @@ package handler import ( "context" "net/http" + "strconv" "time" "github.com/DoWithLogic/golang-clean-architecture/internal/users/dtos" @@ -71,5 +72,64 @@ func (h *handlers) CreateUser(c echo.Context) error { } func (h *handlers) UpdateUser(c echo.Context) error { - return nil + var ( + ctx, cancel = context.WithTimeout(c.Request().Context(), time.Duration(30*time.Second)) + payload dtos.UpdateUserPayload + ) + defer cancel() + + h.log.Z().Info().Msg("[handlers]UpdateUser") + + userID, err := strconv.ParseInt(c.Param("id"), 10, 64) + if err != nil { + h.log.Z().Err(err).Msg("[handlers]UpdateUser.ParseParam") + + return c.JSON(http.StatusBadRequest, dtos.NewResponseError( + http.StatusBadRequest, + dtos.MsgFailed, + dtos.Text(http.StatusBadRequest), + err.Error()), + ) + } + + if err := c.Bind(&payload); err != nil { + h.log.Z().Err(err).Msg("[handlers]UpdateUser.Bind") + + return c.JSON(http.StatusBadRequest, dtos.NewResponseError( + http.StatusBadRequest, + dtos.MsgFailed, + dtos.Text(http.StatusBadRequest), + err.Error()), + ) + } + + if err := payload.Validate(); err != nil { + h.log.Z().Err(err).Msg("[handlers]UpdateUser.Validate") + + return c.JSON(http.StatusBadRequest, dtos.NewResponseError( + http.StatusBadRequest, + dtos.MsgFailed, + dtos.Text(http.StatusBadRequest), + err.Error()), + ) + } + + updateArgs := &entities.UpdateUsers{ + UserID: userID, + Fullname: payload.Fullname, + PhoneNumber: payload.Fullname, + UserType: payload.UserType, + } + + err = h.uc.UpdateUser(ctx, updateArgs) + if err != nil { + return c.JSON(http.StatusBadRequest, dtos.NewResponseError( + http.StatusInternalServerError, + dtos.MsgFailed, + dtos.Text(http.StatusInternalServerError), + err.Error()), + ) + } + + return c.JSON(http.StatusOK, dtos.NewResponse(http.StatusOK, dtos.MsgSuccess, nil)) } diff --git a/internal/users/delivery/http/route/route.go b/internal/users/delivery/http/route/route.go index 73d84ea..513d3d9 100644 --- a/internal/users/delivery/http/route/route.go +++ b/internal/users/delivery/http/route/route.go @@ -8,4 +8,5 @@ import ( func RouteUsers(version *echo.Group, ctrl handler.Handlers) { users := version.Group("users") users.POST("", ctrl.CreateUser) + users.PATCH("/:id", ctrl.UpdateUser) } diff --git a/internal/users/dtos/update_users.go b/internal/users/dtos/update_users.go new file mode 100644 index 0000000..0fbfa55 --- /dev/null +++ b/internal/users/dtos/update_users.go @@ -0,0 +1,32 @@ +package dtos + +import ( + "errors" + + "github.com/DoWithLogic/golang-clean-architecture/internal/users/entities" + "github.com/invopop/validation" +) + +type UpdateUserPayload struct { + Fullname string `json:"fullname"` + PhoneNumber string `json:"phone_number"` + UserType string `json:"user_type"` +} + +func (cup UpdateUserPayload) Validate() error { + var validationFields []*validation.FieldRules + + if cup.UserType != "" && (cup.UserType != entities.UserTypePremium && cup.UserType != entities.UserTypeRegular) { + return errors.New("invalid user_type") + } + + if cup.Fullname != "" { + validationFields = append(validationFields, validation.Field(&cup.Fullname, validation.Required, validation.Length(0, 50))) + } + + if cup.PhoneNumber != "" { + validationFields = append(validationFields, validation.Field(&cup.PhoneNumber, validation.Required, validation.Length(0, 13))) + } + + return validation.ValidateStruct(&cup, validationFields...) +} diff --git a/internal/users/entities/update_users.go b/internal/users/entities/update_users.go index 4cd6346..5a46176 100644 --- a/internal/users/entities/update_users.go +++ b/internal/users/entities/update_users.go @@ -7,17 +7,16 @@ type UpdateUsers struct { Fullname string PhoneNumber string UserType string - IsActive bool UpdatedAt string UpdatedBy string } func NewUpdateUsers(data UpdateUsers) *UpdateUsers { return &UpdateUsers{ + UserID: data.UserID, Fullname: data.Fullname, PhoneNumber: data.PhoneNumber, UserType: UserTypeRegular, - IsActive: true, UpdatedAt: time.Now().Format("2006-01-02 15:04:05"), UpdatedBy: "martin", } diff --git a/internal/users/repository/repository.go b/internal/users/repository/repository.go index 7dd4d39..920613e 100644 --- a/internal/users/repository/repository.go +++ b/internal/users/repository/repository.go @@ -14,7 +14,7 @@ type ( Repository interface { SaveNewUser(context.Context, *entities.Users) (int64, error) UpdateUserByID(context.Context, *entities.UpdateUsers) error - GetUserByID(context.Context, int64, entities.LockingOpt) (*entities.Users, error) + GetUserByID(context.Context, int64, entities.LockingOpt) (entities.Users, error) } repository struct { @@ -50,16 +50,15 @@ func (repo *repository) SaveNewUser(ctx context.Context, user *entities.Users) ( func (repo *repository) UpdateUserByID(ctx context.Context, user *entities.UpdateUsers) error { args := custom.Array{ - user.UserID, - user.Fullname, - user.PhoneNumber, - user.UserType, - user.IsActive, + user.Fullname, user.Fullname, + user.PhoneNumber, user.PhoneNumber, + user.UserType, user.UserType, user.UpdatedAt, user.UpdatedBy, + user.UserID, } - err := new(database.SQL).Exec(repo.conn.ExecContext(ctx, repository_query.InsertUsers, args...)).Scan(nil, nil) + err := new(database.SQL).Exec(repo.conn.ExecContext(ctx, repository_query.UpdateUsers, args...)).Scan(nil, nil) if err != nil { repo.log.Z().Err(err).Msg("[repository]UpdateUserByID.ExecContext") @@ -69,9 +68,9 @@ func (repo *repository) UpdateUserByID(ctx context.Context, user *entities.Updat return nil } -func (repo *repository) GetUserByID(ctx context.Context, userID int64, lockOpt entities.LockingOpt) (userData *entities.Users, err error) { +func (repo *repository) GetUserByID(ctx context.Context, userID int64, lockOpt entities.LockingOpt) (userData entities.Users, err error) { if err := lockOpt.Validate(); err != nil { - return nil, err + return userData, err } args := custom.Array{ @@ -85,7 +84,7 @@ func (repo *repository) GetUserByID(ctx context.Context, userID int64, lockOpt e &userData.PhoneNumber, &userData.UserType, &userData.IsActive, - userData.CreatedAt, + &userData.CreatedAt, } } @@ -93,14 +92,14 @@ func (repo *repository) GetUserByID(ctx context.Context, userID int64, lockOpt e query := repository_query.GetUserByID if lockOpt.ForUpdate { - query += "FOR UPDATE;" + query += " FOR UPDATE;" } else if lockOpt.ForUpdateNoWait { - query += "FOR UPDATE NO WAIT;" + query += " FOR UPDATE NO WAIT;" } if err = new(database.SQL).Query(repo.conn.QueryContext(ctx, query, args...)).Scan(row); err != nil { repo.log.Z().Err(err).Msg("[repository]GetUserByID.QueryContext") - return nil, err + return userData, err } return userData, err diff --git a/internal/users/repository/repository_query/users/select.sql b/internal/users/repository/repository_query/users/select.sql index b21952b..2e5d1f6 100644 --- a/internal/users/repository/repository_query/users/select.sql +++ b/internal/users/repository/repository_query/users/select.sql @@ -6,4 +6,4 @@ SELECT u.is_active, u.created_at FROM users u -WHERE u.id = $1 +WHERE u.id = ? diff --git a/internal/users/repository/repository_query/users/update.sql b/internal/users/repository/repository_query/users/update.sql index b6ca092..069b5aa 100644 --- a/internal/users/repository/repository_query/users/update.sql +++ b/internal/users/repository/repository_query/users/update.sql @@ -1,8 +1,7 @@ UPDATE users SET - fullname = CASE WHEN $2 != '' THEN $2 ELSE fullname END, - phone_number = CASE WHEN $3 != '' THEN $3 ELSE phone_number END, - user_type = CASE WHEN $4 != '' THEN $4 ELSE user_type END, - is_active = CASE WHEN $5 IS NULL THEN $5 ELSE user_type END, + fullname = CASE WHEN ? != '' THEN ? ELSE fullname END, + phone_number = CASE WHEN ? != '' THEN ? ELSE phone_number END, + user_type = CASE WHEN ? != '' THEN ? ELSE user_type END, updated_at = ?, - created_by = ? -WHERE id = $1 \ No newline at end of file + updated_by = ? +WHERE id = ? \ No newline at end of file