From f7eab339b6e7b0767dfe0a62fa5f01bd04038c92 Mon Sep 17 00:00:00 2001 From: Habib Fatkhul Rohman Date: Fri, 21 Nov 2025 13:55:42 +0700 Subject: [PATCH] feat: add bulk user creation functionality with request handling and repository integration --- modules/user/controller/user_controller.go | 19 ++++++++++ modules/user/dto/user_dto.go | 4 ++ modules/user/repository/user_repository.go | 12 ++++++ modules/user/routes.go | 1 + modules/user/service/user_service.go | 43 ++++++++++++++++++++++ 5 files changed, 79 insertions(+) diff --git a/modules/user/controller/user_controller.go b/modules/user/controller/user_controller.go index 5f275ff..426397a 100644 --- a/modules/user/controller/user_controller.go +++ b/modules/user/controller/user_controller.go @@ -37,6 +37,7 @@ type ( AddUserWarehouse(ctx *gin.Context) ReplaceUserWarehouses(ctx *gin.Context) RemoveUserWarehouse(ctx *gin.Context) + BulkCreate(ctx *gin.Context) } userController struct { @@ -45,6 +46,24 @@ type ( } ) +// BulkCreate implements UserController. +func (c *userController) BulkCreate(ctx *gin.Context) { + var req dto.BulkCreateUserRequest + if err := ctx.ShouldBindJSON(&req); err != nil { + res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_DATA_FROM_BODY, err.Error(), nil) + ctx.AbortWithStatusJSON(http.StatusBadRequest, res) + return + } + err := c.userService.BulkCreate(ctx.Request.Context(), req) + if err != nil { + res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_PROSES_REQUEST, err.Error(), nil) + ctx.JSON(http.StatusBadRequest, res) + return + } + res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_PROSES_REQUEST, nil) + ctx.JSON(http.StatusOK, res) +} + // SwitchRole implements UserController. func (c *userController) SwitchRole(ctx *gin.Context) { userId := ctx.Param("id") diff --git a/modules/user/dto/user_dto.go b/modules/user/dto/user_dto.go index e454df5..0971a6f 100644 --- a/modules/user/dto/user_dto.go +++ b/modules/user/dto/user_dto.go @@ -64,6 +64,10 @@ type ( LocationID uuid.UUID `json:"location_id" form:"location_id" binding:"omitempty,uuid4"` } + BulkCreateUserRequest struct { + Users []UserCreateRequest `json:"users" binding:"required,dive"` + } + UserResponse struct { ID string `json:"id"` Name string `json:"name"` diff --git a/modules/user/repository/user_repository.go b/modules/user/repository/user_repository.go index 94c3fe5..0fe6639 100644 --- a/modules/user/repository/user_repository.go +++ b/modules/user/repository/user_repository.go @@ -28,6 +28,7 @@ type ( AddUserWarehouses(ctx context.Context, tx *gorm.DB, userId string, warehouseIds []string) error AddUserWarehouse(ctx context.Context, tx *gorm.DB, userId string, warehouseId string) error RemoveUserWarehouse(ctx context.Context, tx *gorm.DB, userId string, warehouseId string) error + BulkCreate(ctx context.Context, tx *gorm.DB, users []entities.M_User) error } userRepository struct { @@ -35,6 +36,17 @@ type ( } ) +// BulkCreate implements UserRepository. +func (r *userRepository) BulkCreate(ctx context.Context, tx *gorm.DB, users []entities.M_User) error { + if tx == nil { + tx = r.db + } + if err := tx.WithContext(ctx).Create(&users).Error; err != nil { + return err + } + return nil +} + // GetUserWarehouses implements UserRepository. func (r *userRepository) GetUserWarehouses(ctx context.Context, tx *gorm.DB, userId string) ([]entities.MWarehouseEntity, error) { if tx == nil { diff --git a/modules/user/routes.go b/modules/user/routes.go index c65eb45..cda9eeb 100644 --- a/modules/user/routes.go +++ b/modules/user/routes.go @@ -16,6 +16,7 @@ func RegisterRoutes(server *gin.Engine, injector *do.Injector) { userRoutes := server.Group("/api/v1/users") { userRoutes.POST("", middlewares.Authenticate(jwtService), userController.Create) + userRoutes.POST("/bulk-create", middlewares.Authenticate(jwtService), userController.BulkCreate) // userRoutes.POST("/login", userController.Login) // userRoutes.POST("/verify-email", userController.VerifyEmail) userRoutes.GET("", middlewares.Authenticate(jwtService), userController.GetAllUser) diff --git a/modules/user/service/user_service.go b/modules/user/service/user_service.go index 72cf134..bc52dc6 100644 --- a/modules/user/service/user_service.go +++ b/modules/user/service/user_service.go @@ -41,6 +41,7 @@ type UserService interface { AssignWarehousesReplace(ctx context.Context, userId string, warehouseIds []string) error AssignWarehouse(ctx context.Context, userId string, warehouseId string) error RemoveWarehouse(ctx context.Context, userId string, warehouseId string) error + BulkCreate(ctx context.Context, req dto.BulkCreateUserRequest) error } type userService struct { @@ -52,6 +53,48 @@ type userService struct { db *gorm.DB } +// BulkCreate implements UserService. +func (s *userService) BulkCreate(ctx context.Context, req dto.BulkCreateUserRequest) error { + users := make([]entities.M_User, len(req.Users)) + + for i, r := range req.Users { + hashedPassword, err := utils.HashPassword(r.Password) + if err != nil { + return err + } + users[i] = entities.M_User{ + Username: r.Username, + Email: r.Email, + Password: hashedPassword, + Name: r.Name, + Gender: r.Gender, + Address: r.Address, + Phone: r.Phone, + PhotoUrl: r.PhotoUrl, + ClientID: r.ClientID, + MaintenanceGroupUserID: r.MaintenanceGroupUserID, + LocationID: r.LocationID, + } + } + + tx := s.db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + err := s.userRepository.BulkCreate(ctx, tx, users) + if err != nil { + tx.Rollback() + return err + } + if err := tx.Commit().Error; err != nil { + return err + } + return nil +} + // GetUserWarehouses implements UserService. func (s *userService) GetUserWarehouses(ctx context.Context, userId string) ([]dto.UserResponse, error) { user, err := s.userRepository.GetUserById(ctx, s.db, userId)