diff --git a/internal/users/delivery/http/handler/handler.go b/internal/users/delivery/http/handler/handler.go index dcccfe2..f13ca39 100644 --- a/internal/users/delivery/http/handler/handler.go +++ b/internal/users/delivery/http/handler/handler.go @@ -2,6 +2,7 @@ package handler import ( "context" + "errors" "net/http" "strconv" "time" @@ -17,6 +18,7 @@ type ( Handlers interface { CreateUser(c echo.Context) error UpdateUser(c echo.Context) error + UpdateUserStatus(c echo.Context) error } handlers struct { @@ -25,6 +27,15 @@ type ( } ) +const ( + BooleanTextTrue = "true" + BooleanTextFalse = "false" +) + +var ( + ErrInvalidIsActive = errors.New("invalid is_active") +) + func NewHandlers(uc usecases.Usecase, log *zerolog.Logger) Handlers { return &handlers{uc, log} } @@ -133,3 +144,49 @@ func (h *handlers) UpdateUser(c echo.Context) error { return c.JSON(http.StatusOK, dtos.NewResponse(http.StatusOK, dtos.MsgSuccess, nil)) } + +func (h *handlers) UpdateUserStatus(c echo.Context) error { + var ( + ctx, cancel = context.WithTimeout(c.Request().Context(), time.Duration(30*time.Second)) + payload dtos.UpdateUserStatusPayload + ) + defer cancel() + + 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()), + ) + } + + switch c.QueryParam("is_active") { + case BooleanTextFalse: + payload.IsActive = false + case BooleanTextTrue: + payload.IsActive = true + default: + return c.JSON(http.StatusBadRequest, dtos.NewResponseError( + http.StatusBadRequest, + dtos.MsgFailed, + dtos.Text(http.StatusBadRequest), + ErrInvalidIsActive.Error()), + ) + } + + err = h.uc.UpdateUserStatus(ctx, &entities.UpdateUsers{UserID: userID, IsActive: payload.IsActive}) + 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 513d3d9..452fe5f 100644 --- a/internal/users/delivery/http/route/route.go +++ b/internal/users/delivery/http/route/route.go @@ -5,8 +5,9 @@ import ( "github.com/labstack/echo/v4" ) -func RouteUsers(version *echo.Group, ctrl handler.Handlers) { +func RouteUsers(version *echo.Group, handler handler.Handlers) { users := version.Group("users") - users.POST("", ctrl.CreateUser) - users.PATCH("/:id", ctrl.UpdateUser) + users.POST("", handler.CreateUser) + users.PATCH("/:id", handler.UpdateUser) + users.PUT("/:id", handler.UpdateUserStatus) } diff --git a/internal/users/dtos/update_user_status.go b/internal/users/dtos/update_user_status.go new file mode 100644 index 0000000..72f6d5a --- /dev/null +++ b/internal/users/dtos/update_user_status.go @@ -0,0 +1,6 @@ +package dtos + +type UpdateUserStatusPayload struct { + UserID int64 + IsActive bool +} diff --git a/internal/users/entities/update_users.go b/internal/users/entities/update_users.go index 5a46176..9b2ee6c 100644 --- a/internal/users/entities/update_users.go +++ b/internal/users/entities/update_users.go @@ -7,6 +7,7 @@ type UpdateUsers struct { Fullname string PhoneNumber string UserType string + IsActive bool UpdatedAt string UpdatedBy string } diff --git a/internal/users/repository/repository.go b/internal/users/repository/repository.go index 920613e..a433abe 100644 --- a/internal/users/repository/repository.go +++ b/internal/users/repository/repository.go @@ -2,6 +2,7 @@ package repository import ( "context" + "errors" "github.com/DoWithLogic/golang-clean-architecture/internal/users/entities" "github.com/DoWithLogic/golang-clean-architecture/internal/users/repository/repository_query" @@ -15,6 +16,7 @@ type ( SaveNewUser(context.Context, *entities.Users) (int64, error) UpdateUserByID(context.Context, *entities.UpdateUsers) error GetUserByID(context.Context, int64, entities.LockingOpt) (entities.Users, error) + UpdateUserStatusByID(context.Context, *entities.Users) error } repository struct { @@ -23,6 +25,10 @@ type ( } ) +var ( + ErrUserNotFound = errors.New("user not found") +) + func NewRepository(conn database.SQLTxConn, log *zerolog.Logger) Repository { return &repository{conn, log} } @@ -86,7 +92,6 @@ func (repo *repository) GetUserByID(ctx context.Context, userID int64, lockOpt e &userData.IsActive, &userData.CreatedAt, } - } query := repository_query.GetUserByID @@ -102,5 +107,27 @@ func (repo *repository) GetUserByID(ctx context.Context, userID int64, lockOpt e return userData, err } + if userData.UserID != userID { + return userData, ErrUserNotFound + } + return userData, err } + +func (repo *repository) UpdateUserStatusByID(ctx context.Context, req *entities.Users) error { + args := custom.Array{ + req.IsActive, + req.UpdatedAt, + req.UpdatedBy, + req.UserID, + } + + err := new(database.SQL).Exec(repo.conn.ExecContext(ctx, repository_query.UpdateUserStatusByID, args...)).Scan(nil, nil) + if err != nil { + repo.log.Z().Err(err).Msg("[repository]UpdateUserStatusByID.ExecContext") + + return err + } + + return nil +} diff --git a/internal/users/repository/repository_query/repository_query.go b/internal/users/repository/repository_query/repository_query.go index b119845..49ff425 100644 --- a/internal/users/repository/repository_query/repository_query.go +++ b/internal/users/repository/repository_query/repository_query.go @@ -7,6 +7,8 @@ var ( InsertUsers string //go:embed users/update.sql UpdateUsers string + //go:embed users/update_status_by_id.sql + UpdateUserStatusByID string //go:embed users/select.sql GetUserByID string ) diff --git a/internal/users/repository/repository_query/users/update_status_by_id.sql b/internal/users/repository/repository_query/users/update_status_by_id.sql new file mode 100644 index 0000000..efcb56b --- /dev/null +++ b/internal/users/repository/repository_query/users/update_status_by_id.sql @@ -0,0 +1,5 @@ +UPDATE users SET + is_active = ?, + updated_at = ?, + updated_by = ? +WHERE id = ? \ No newline at end of file diff --git a/internal/users/usecase/usecase.go b/internal/users/usecase/usecase.go index 1ba6503..de57be2 100644 --- a/internal/users/usecase/usecase.go +++ b/internal/users/usecase/usecase.go @@ -2,6 +2,8 @@ package usecase import ( "context" + "fmt" + "time" "github.com/DoWithLogic/golang-clean-architecture/internal/users/entities" "github.com/DoWithLogic/golang-clean-architecture/internal/users/repository" @@ -14,6 +16,7 @@ type ( Usecase interface { CreateUser(context.Context, *entities.Users) (int64, error) UpdateUser(context.Context, *entities.UpdateUsers) error + UpdateUserStatus(context.Context, *entities.UpdateUsers) error } usecase struct { @@ -66,3 +69,26 @@ func (uc *usecase) UpdateUser(ctx context.Context, updateData *entities.UpdateUs return nil }(uc.dbTx) } + +func (uc *usecase) UpdateUserStatus(ctx context.Context, req *entities.UpdateUsers) error { + userDetail, err := uc.repo.GetUserByID(ctx, req.UserID, entities.LockingOpt{}) + if err != nil { + uc.log.Z().Err(err).Msg("[usecase]UpdateUserStatus.GetUserByID") + return err + } + + fmt.Println("user_id", userDetail.UserID) + + updateStatusArgs := &entities.Users{ + UserID: userDetail.UserID, + IsActive: req.IsActive, + UpdatedAt: time.Now().Format("2006-01-02 15:04:05"), + UpdatedBy: "martin", + } + + if err := uc.repo.UpdateUserStatusByID(ctx, updateStatusArgs); err != nil { + uc.log.Z().Err(err).Msg("[usecase]UpdateUserStatus.UpdateUserStatusByID") + } + + return nil +}