diff --git a/modules/maintenance_group/controller/maintenance_group_controller.go b/modules/maintenance_group/controller/maintenance_group_controller.go new file mode 100644 index 0000000..970dd50 --- /dev/null +++ b/modules/maintenance_group/controller/maintenance_group_controller.go @@ -0,0 +1,161 @@ +package controller + +import ( + "net/http" + + "github.com/Caknoooo/go-gin-clean-starter/modules/maintenance_group/dto" + "github.com/Caknoooo/go-gin-clean-starter/modules/maintenance_group/service" + "github.com/Caknoooo/go-gin-clean-starter/pkg/constants" + "github.com/Caknoooo/go-gin-clean-starter/pkg/utils" + "github.com/gin-gonic/gin" + "github.com/samber/do" + "github.com/sirupsen/logrus" + "gorm.io/gorm" +) + +type ( + MaintenanceGroupController interface { + Create(ctx *gin.Context) + Update(ctx *gin.Context) + Delete(ctx *gin.Context) + GetById(ctx *gin.Context) + GetAll(ctx *gin.Context) + } + + maintenanceGroupController struct { + maintGroupService service.MaintenanceGroupService + db *gorm.DB + logger *logrus.Logger + } +) + +func NewMaintenanceGroupController(i *do.Injector, maintGroupService service.MaintenanceGroupService) MaintenanceGroupController { + db := do.MustInvokeNamed[*gorm.DB](i, constants.DB) + logger := do.MustInvokeNamed[*logrus.Logger](i, constants.LOGGER) + + return &maintenanceGroupController{ + maintGroupService: maintGroupService, + db: db, + logger: logger, + } +} + +// Create godoc +// @Summary Create a new maintenance group +// @Description Create a new maintenance group +// @Tags MaintenanceGroup +// @Accept json +// @Produce json +// @Param body body dto.MaintGroupCreateRequest true "Create payload" +// @Success 200 {object} dto.MaintGroupResponse +// @Failure 400 {object} map[string]interface{} +// @Router /maintenance-groups [post] +func (c *maintenanceGroupController) Create(ctx *gin.Context) { + var req dto.MaintGroupCreateRequest + if err := ctx.ShouldBind(&req); err != nil { + res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_DATA_FROM_BODY, err.Error(), nil) + ctx.AbortWithStatusJSON(http.StatusBadRequest, res) + return + } + + result, err := c.maintGroupService.Create(ctx.Request.Context(), req) + if err != nil { + res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_REGISTER_MG, err.Error(), nil) + ctx.JSON(http.StatusBadRequest, res) + return + } + + res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_REGISTER_MG, result) + ctx.JSON(http.StatusOK, res) +} + +// Update godoc +// @Summary Update maintenance group +// @Description Update maintenance group +// @Tags MaintenanceGroup +// @Accept json +// @Produce json +// @Param body body dto.MaintGroupUpdateRequest true "Update payload" +// @Success 200 {object} dto.MaintGroupResponse +// @Failure 400 {object} map[string]interface{} +// @Router /maintenance-groups [put] +func (c *maintenanceGroupController) Update(ctx *gin.Context) { + var req dto.MaintGroupUpdateRequest + if err := ctx.ShouldBind(&req); err != nil { + res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_DATA_FROM_BODY, err.Error(), nil) + ctx.AbortWithStatusJSON(http.StatusBadRequest, res) + return + } + id := ctx.Param("id") + result, err := c.maintGroupService.Update(ctx.Request.Context(), req, id) + if err != nil { + res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_UPDATE_MG, err.Error(), nil) + ctx.JSON(http.StatusBadRequest, res) + return + } + res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_UPDATE_MG, result) + ctx.JSON(http.StatusOK, res) +} + +// Delete godoc +// @Summary Delete maintenance group +// @Description Delete maintenance group +// @Tags MaintenanceGroup +// @Accept json +// @Produce json +// @Param id path string true "MaintenanceGroup ID" +// @Success 200 {object} map[string]interface{} +// @Failure 400 {object} map[string]interface{} +// @Router /maintenance-groups/{id} [delete] +func (c *maintenanceGroupController) Delete(ctx *gin.Context) { + id := ctx.Param("id") + if err := c.maintGroupService.Delete(ctx.Request.Context(), id); err != nil { + res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_DELETE_MG, err.Error(), nil) + ctx.AbortWithStatusJSON(http.StatusBadRequest, res) + return + } + res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_DELETE_MG, nil) + ctx.JSON(http.StatusOK, res) +} + +// GetById godoc +// @Summary Get maintenance group by ID +// @Description Get maintenance group by ID +// @Tags MaintenanceGroup +// @Accept json +// @Produce json +// @Param id path string true "MaintenanceGroup ID" +// @Success 200 {object} dto.MaintGroupResponse +// @Failure 400 {object} map[string]interface{} +// @Router /maintenance-groups/{id} [get] +func (c *maintenanceGroupController) GetById(ctx *gin.Context) { + id := ctx.Param("id") + result, err := c.maintGroupService.GetById(ctx.Request.Context(), id) + if err != nil { + res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_MG, err.Error(), nil) + ctx.JSON(http.StatusBadRequest, res) + return + } + res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_GET_MG, result) + ctx.JSON(http.StatusOK, res) +} + +// GetAll godoc +// @Summary Get all maintenance groups +// @Description Get all maintenance groups +// @Tags MaintenanceGroup +// @Accept json +// @Produce json +// @Success 200 {array} dto.MaintGroupResponse +// @Failure 400 {object} map[string]interface{} +// @Router /maintenance-groups [get] +func (c *maintenanceGroupController) GetAll(ctx *gin.Context) { + // result, err := c.maintGroupService.GetAll(ctx.Request.Context()) + // if err != nil { + // res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_LIST_MG, err.Error(), nil) + // ctx.JSON(http.StatusBadRequest, res) + // return + // } + // res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_GET_LIST_MG, result) + // ctx.JSON(http.StatusOK, res) +} diff --git a/modules/maintenance_group/dto/maintenance_group_dto.go b/modules/maintenance_group/dto/maintenance_group_dto.go new file mode 100644 index 0000000..2dbff4b --- /dev/null +++ b/modules/maintenance_group/dto/maintenance_group_dto.go @@ -0,0 +1,118 @@ +package dto + +import ( + "errors" + + "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" +) + +const ( + // Failed + MESSAGE_FAILED_GET_DATA_FROM_BODY = "failed get data from body" + MESSAGE_FAILED_REGISTER_MG = "failed create maintenance group" + MESSAGE_FAILED_GET_LIST_MG = "failed get list maintenance group" + MESSAGE_FAILED_TOKEN_NOT_VALID = "token not valid" + MESSAGE_FAILED_TOKEN_NOT_FOUND = "token not found" + MESSAGE_FAILED_GET_MG = "failed get maintenance group" + MESSAGE_FAILED_LOGIN = "failed login" + MESSAGE_FAILED_UPDATE_MG = "failed update maintenance group" + MESSAGE_FAILED_DELETE_MG = "failed delete maintenance group" + MESSAGE_FAILED_PROSES_REQUEST = "failed proses request" + MESSAGE_FAILED_DENIED_ACCESS = "denied access" + MESSAGE_FAILED_VERIFY_EMAIL = "failed verify email" + MESSAGE_FAILED_CREATE_MG = "failed create maintenance group" + + // Success + MESSAGE_SUCCESS_REGISTER_MG = "success create maintenance group" + MESSAGE_SUCCESS_GET_LIST_MG = "success get list maintenance group" + MESSAGE_SUCCESS_GET_MG = "success get maintenance group" + MESSAGE_SUCCESS_LOGIN = "success login" + MESSAGE_SUCCESS_UPDATE_MG = "success update maintenance group" + MESSAGE_SUCCESS_DELETE_MG = "success delete maintenance group" + MESSAGE_SEND_VERIFICATION_EMAIL_SUCCESS = "success send verification email" + MESSAGE_SUCCESS_VERIFY_EMAIL = "success verify email" + MESSAGE_SUCCESS_CREATE_MENU = "success create menu" +) + +var ( + ErrInteralServer = errors.New("internal server error") + ErrCreateMG = errors.New("failed to create maintenance group") + ErrGetMGById = errors.New("failed to get maintenance group by id") + ErrGetMGByEmail = errors.New("failed to get maintenance group by email") + ErrEmailAlreadyExists = errors.New("email already exist") + ErrUpdateMG = errors.New("failed to update maintenance group") + ErrMGNotFound = errors.New("maintenance group not found") + ErrEmailNotFound = errors.New("email not found") + ErrDeleteMG = errors.New("failed to delete maintenance group") + ErrTokenInvalid = errors.New("token invalid") + ErrTokenExpired = errors.New("token expired") + ErrAccountAlreadyVerified = errors.New("account already verified") + ErrCodeCodeExists = errors.New("code already exists") + ErrNameAlreadyExists = errors.New("name already exists") +) + +type ( + MaintGroupCreateRequest struct { + Code string `json:"code" form:"code" binding:"required,min=2,max=50"` + Name string `json:"name" form:"name" binding:"required,min=2,max=100"` + Description string `json:"description" form:"description" binding:"omitempty"` + ClientID string `json:"client_id" form:"client_id" binding:"required,uuid4"` + MaintenanceGroupRoles []MaintenanceGroupRole `json:"maintenance_group_roles" form:"maintenance_group_roles" binding:"required,dive,required"` + } + + MaintenanceGroupRole struct { + RoleID string `json:"role_id" form:"role_id" binding:"required,uuid4"` + Level *int `json:"level" form:"level" binding:"required"` + MaintenanceGroupRoleUsers []MaintenanceGroupRoleUser `json:"maintenance_group_role_users" form:"maintenance_group_role_users" binding:"required,dive,required"` + } + + MaintenanceGroupRoleUser struct { + UserID string `json:"user_id" form:"user_id" binding:"required,uuid4"` + } + + MaintGroupResponse struct { + ID string `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Description string `json:"description"` + Client dto.ClientResponse `json:"client"` + MaintenanceGroupRoles *[]MaintenanceGroupRoleResponse `json:"maintenance_group_roles"` + } + + MaintenanceGroupRoleResponse struct { + ID string `json:"id"` + Role dto.RoleResponse `json:"role"` + Level *int `json:"level"` + MaintenanceGroupRoleUsers []MaintenanceGroupRoleUserResponse `json:"maintenance_group_role_users"` + } + + MaintenanceGroupRoleUserResponse struct { + ID string `json:"id"` + User dto.UserResponse `json:"user"` + } + + GetAllMaintenanceGroupResponse struct { + MaintenanceGroups []MaintGroupResponse `json:"maintenance_groups"` + dto.PaginationResponse + } + + MaintGroupUpdateRequest struct { + Code *string `json:"code" form:"code" binding:"omitempty,min=2,max=50"` + Name *string `json:"name" form:"name" binding:"omitempty,min=2,max=100"` + Description *string `json:"description" form:"description" binding:"omitempty"` + ClientID *string `json:"client_id" form:"client_id" binding:"omitempty,uuid4"` + MaintenanceGroupRoles *[]MaintenanceGroupRoleUpdate `json:"maintenance_group_roles" form:"maintenance_group_roles" binding:"omitempty,dive"` + } + + MaintenanceGroupRoleUpdate struct { + ID *string `json:"id" form:"id" binding:"omitempty,uuid4"` + RoleID *string `json:"role_id" form:"role_id" binding:"omitempty,uuid4"` + MaintenanceGroupRoleUsers *[]MaintenanceGroupRoleUser `json:"maintenance_group_role_users" form:"maintenance_group_role_users" binding:"omitempty,dive"` + Level *int `json:"level" form:"level" binding:"omitempty"` + } + + MaintenanceGroupRoleUserUpdate struct { + ID *string `json:"id" form:"id" binding:"omitempty,uuid4"` + UserID *string `json:"user_id" form:"user_id" binding:"omitempty,uuid4"` + } +) diff --git a/modules/maintenance_group/query/maintenance_group_query.go b/modules/maintenance_group/query/maintenance_group_query.go new file mode 100644 index 0000000..b3d8b8c --- /dev/null +++ b/modules/maintenance_group/query/maintenance_group_query.go @@ -0,0 +1 @@ +package query \ No newline at end of file diff --git a/modules/maintenance_group/repository/group_role_repository.go b/modules/maintenance_group/repository/group_role_repository.go new file mode 100644 index 0000000..6fb522c --- /dev/null +++ b/modules/maintenance_group/repository/group_role_repository.go @@ -0,0 +1,106 @@ +package repository + +import ( + "context" + + "github.com/Caknoooo/go-gin-clean-starter/database/entities" + "gorm.io/gorm" +) + +type ( + MaintGroupRepository interface { + Create(ctx context.Context, tx *gorm.DB, maintGroup entities.M_MaintenanceGroup) (entities.M_MaintenanceGroup, error) + GetById(ctx context.Context, tx *gorm.DB, maintGroupId string) (entities.M_MaintenanceGroup, error) + GetByName(ctx context.Context, tx *gorm.DB, name string) (entities.M_MaintenanceGroup, error) + GetByCode(ctx context.Context, tx *gorm.DB, code string) (entities.M_MaintenanceGroup, error) + Update(ctx context.Context, tx *gorm.DB, maintGroup entities.M_MaintenanceGroup) (entities.M_MaintenanceGroup, error) + Delete(ctx context.Context, tx *gorm.DB, maintGroupId string) error + } + + maintGroupRepository struct { + db *gorm.DB + } +) + +// GetByCode implements MaintGroupRepository. +func (m *maintGroupRepository) GetByCode(ctx context.Context, tx *gorm.DB, code string) (entities.M_MaintenanceGroup, error) { + if tx == nil { + tx = m.db + } + var maintGroup entities.M_MaintenanceGroup + if err := tx.WithContext(ctx).Where("code = ?", code).First(&maintGroup).Error; err != nil { + return entities.M_MaintenanceGroup{}, err + } + return maintGroup, nil +} + +// Create implements MaintGroupRepository. +func (m *maintGroupRepository) Create(ctx context.Context, tx *gorm.DB, maintGroup entities.M_MaintenanceGroup) (entities.M_MaintenanceGroup, error) { + if tx == nil { + tx = m.db + } + + if err := tx.WithContext(ctx).Create(&maintGroup).Error; err != nil { + return entities.M_MaintenanceGroup{}, err + } + return maintGroup, nil +} + +// Delete implements MaintGroupRepository. +func (m *maintGroupRepository) Delete(ctx context.Context, tx *gorm.DB, maintGroupId string) error { + if tx == nil { + tx = m.db + } + if err := tx.WithContext(ctx).Delete(&entities.M_MaintenanceGroup{}, "id = ?", maintGroupId).Error; err != nil { + return err + } + return nil +} + +// GetById implements MaintGroupRepository. +func (m *maintGroupRepository) GetById(ctx context.Context, tx *gorm.DB, maintGroupId string) (entities.M_MaintenanceGroup, error) { + if tx == nil { + tx = m.db + } + var maintGroup entities.M_MaintenanceGroup + if err := tx.WithContext(ctx). + Preload("Client"). + Preload("MaintenanceGroupRoles"). + Preload("MaintenanceGroupRoles.Role"). + Preload("MaintenanceGroupRoles.MaintenanceGroupRoleUsers"). + Preload("MaintenanceGroupRoles.MaintenanceGroupRoleUsers.User"). + First(&maintGroup, "id = ?", maintGroupId).Error; err != nil { + return entities.M_MaintenanceGroup{}, err + } + return maintGroup, nil +} + +// GetByName implements MaintGroupRepository. +func (m *maintGroupRepository) GetByName(ctx context.Context, tx *gorm.DB, name string) (entities.M_MaintenanceGroup, error) { + if tx == nil { + tx = m.db + } + var maintGroup entities.M_MaintenanceGroup + if err := tx.WithContext(ctx).Where("name = ?", name).First(&maintGroup).Error; err != nil { + return entities.M_MaintenanceGroup{}, err + } + return maintGroup, nil +} + +// Update implements MaintGroupRepository. +func (m *maintGroupRepository) Update(ctx context.Context, tx *gorm.DB, maintGroup entities.M_MaintenanceGroup) (entities.M_MaintenanceGroup, error) { + if tx == nil { + tx = m.db + } + if err := tx.WithContext(ctx).Updates(&maintGroup).Error; err != nil { + return entities.M_MaintenanceGroup{}, err + } + + return maintGroup, nil +} + +func NewMaintGroupRepository(db *gorm.DB) MaintGroupRepository { + return &maintGroupRepository{ + db: db, + } +} diff --git a/modules/maintenance_group/repository/maintenance_group_role_repository.go b/modules/maintenance_group/repository/maintenance_group_role_repository.go new file mode 100644 index 0000000..41c5e01 --- /dev/null +++ b/modules/maintenance_group/repository/maintenance_group_role_repository.go @@ -0,0 +1,119 @@ +package repository + +import ( + "context" + + "github.com/Caknoooo/go-gin-clean-starter/database/entities" + "gorm.io/gorm" +) + +type ( + MaintGroupRoleRepository interface { + Create(ctx context.Context, tx *gorm.DB, maintGroupRole entities.M_MaintenanceGroupRole) (entities.M_MaintenanceGroupRole, error) + GetById(ctx context.Context, tx *gorm.DB, maintGroupId string) (entities.M_MaintenanceGroupRole, error) + FindByMaintGroupId(ctx context.Context, tx *gorm.DB, maintGroupId string) ([]entities.M_MaintenanceGroupRole, error) + Update(ctx context.Context, tx *gorm.DB, maintGroupRole entities.M_MaintenanceGroupRole) (entities.M_MaintenanceGroupRole, error) + Delete(ctx context.Context, tx *gorm.DB, maintGroupRoleId string) error + DeleteByIds(ctx context.Context, tx *gorm.DB, maintGroupRoleIds []string) error + DeleteByMaintGroupId(ctx context.Context, tx *gorm.DB, maintGroupId string) error + } + + maintGroupRoleRepository struct { + db *gorm.DB + } +) + +// DeleteByIds implements MaintGroupRoleRepository. +func (m *maintGroupRoleRepository) DeleteByIds(ctx context.Context, tx *gorm.DB, maintGroupRoleIds []string) error { + if tx == nil { + tx = m.db + } + + if len(maintGroupRoleIds) == 0 { + return nil // Tidak ada data yang perlu dihapus + } + + if err := tx.WithContext(ctx). + Where("id IN ?", maintGroupRoleIds). + Delete(&entities.M_MaintenanceGroupRole{}).Error; err != nil { + return err + } + + return nil +} + +// FindByMaintGroupId implements MaintGroupRoleRepository. +func (m *maintGroupRoleRepository) FindByMaintGroupId(ctx context.Context, tx *gorm.DB, maintGroupId string) ([]entities.M_MaintenanceGroupRole, error) { + if tx == nil { + tx = m.db + } + var maintGroupRoles []entities.M_MaintenanceGroupRole + if err := tx.Where("maintenance_group_id = ?", maintGroupId).Find(&maintGroupRoles).Error; err != nil { + tx.Rollback() + return nil, err + } + return maintGroupRoles, nil +} + +// DeleteByMaintGroupId implements MaintGroupRoleRepository. +func (m *maintGroupRoleRepository) DeleteByMaintGroupId(ctx context.Context, tx *gorm.DB, maintGroupId string) error { + if tx == nil { + tx = m.db + } + if err := tx.WithContext(ctx).Delete(&entities.M_MaintenanceGroupRole{}, "maintenance_group_id = ?", maintGroupId).Error; err != nil { + return err + } + return nil +} + +// Create implements MaintGroupRoleRepository. +func (m *maintGroupRoleRepository) Create(ctx context.Context, tx *gorm.DB, maintGroupRole entities.M_MaintenanceGroupRole) (entities.M_MaintenanceGroupRole, error) { + if tx == nil { + tx = m.db + } + + if err := tx.WithContext(ctx).Create(&maintGroupRole).Error; err != nil { + return entities.M_MaintenanceGroupRole{}, err + } + return maintGroupRole, nil +} + +// Delete implements MaintGroupRoleRepository. +func (m *maintGroupRoleRepository) Delete(ctx context.Context, tx *gorm.DB, maintGroupRoleId string) error { + if tx == nil { + tx = m.db + } + if err := tx.WithContext(ctx).Delete(&entities.M_MaintenanceGroupRole{}, "id = ?", maintGroupRoleId).Error; err != nil { + return err + } + return nil +} + +// GetById implements MaintGroupRoleRepository. +func (m *maintGroupRoleRepository) GetById(ctx context.Context, tx *gorm.DB, maintGroupRoleId string) (entities.M_MaintenanceGroupRole, error) { + if tx == nil { + tx = m.db + } + var maintGroupRole entities.M_MaintenanceGroupRole + if err := tx.WithContext(ctx).First(&maintGroupRole, "id = ?", maintGroupRoleId).Error; err != nil { + return entities.M_MaintenanceGroupRole{}, err + } + return maintGroupRole, nil +} + +// Update implements MaintGroupRoleRepository. +func (m *maintGroupRoleRepository) Update(ctx context.Context, tx *gorm.DB, maintGroupRole entities.M_MaintenanceGroupRole) (entities.M_MaintenanceGroupRole, error) { + if tx == nil { + tx = m.db + } + if err := tx.WithContext(ctx).Updates(&maintGroupRole).Error; err != nil { + return entities.M_MaintenanceGroupRole{}, err + } + return maintGroupRole, nil +} + +func NewMaintGroupRoleRepository(db *gorm.DB) MaintGroupRoleRepository { + return &maintGroupRoleRepository{ + db: db, + } +} diff --git a/modules/maintenance_group/repository/maintenance_group_role_user_repository.go b/modules/maintenance_group/repository/maintenance_group_role_user_repository.go new file mode 100644 index 0000000..f348df7 --- /dev/null +++ b/modules/maintenance_group/repository/maintenance_group_role_user_repository.go @@ -0,0 +1,119 @@ +package repository + +import ( + "context" + + "github.com/Caknoooo/go-gin-clean-starter/database/entities" + "gorm.io/gorm" +) + +type ( + MaintGroupRoleUserRepository interface { + Create(ctx context.Context, tx *gorm.DB, maintGroupRoleUser entities.M_MaintenanceGroupRoleUser) (entities.M_MaintenanceGroupRoleUser, error) + GetById(ctx context.Context, tx *gorm.DB, maintGroupId string) (entities.M_MaintenanceGroupRoleUser, error) + FindByRoleId(ctx context.Context, tx *gorm.DB, maintGroupId string) ([]entities.M_MaintenanceGroupRoleUser, error) + Update(ctx context.Context, tx *gorm.DB, maintGroupRoleUser entities.M_MaintenanceGroupRoleUser) (entities.M_MaintenanceGroupRoleUser, error) + Delete(ctx context.Context, tx *gorm.DB, maintGroupId string) error + DeleteByMaintGroupRoleID(ctx context.Context, tx *gorm.DB, maintGroupRoleId string) error + DeleteByRoleIdAndUserIds(ctx context.Context, tx *gorm.DB, maintGroupRoleId string, userIds []string) error + } + + maintGroupRoleUserRepository struct { + db *gorm.DB + } +) + +// DeleteByRoleIdAndUserIds implements MaintGroupRoleUserRepository. +func (m *maintGroupRoleUserRepository) DeleteByRoleIdAndUserIds(ctx context.Context, tx *gorm.DB, maintGroupRoleId string, userIds []string) error { + if tx == nil { + tx = m.db + } + + if len(userIds) == 0 { + return nil // Tidak ada data yang perlu dihapus + } + + if err := tx.WithContext(ctx). + Where("maintenance_group_role_id = ? AND user_id IN ?", maintGroupRoleId, userIds). + Delete(&entities.M_MaintenanceGroupRoleUser{}).Error; err != nil { + return err + } + + return nil +} + +// FindByRoleId implements MaintGroupRoleUserRepository. +func (m *maintGroupRoleUserRepository) FindByRoleId(ctx context.Context, tx *gorm.DB, maintGroupId string) ([]entities.M_MaintenanceGroupRoleUser, error) { + if tx == nil { + tx = m.db + } + var maintGroupRoleUsers []entities.M_MaintenanceGroupRoleUser + if err := tx.Where("maintenance_group_role_id = ?", maintGroupId).Find(&maintGroupRoleUsers).Error; err != nil { + tx.Rollback() + return nil, err + } + return maintGroupRoleUsers, nil +} + +// DeleteByMaintGroupRoleID implements MaintGroupRoleUserRepository. +func (m *maintGroupRoleUserRepository) DeleteByMaintGroupRoleID(ctx context.Context, tx *gorm.DB, maintGroupRoleId string) error { + if tx == nil { + tx = m.db + } + if err := tx.WithContext(ctx).Delete(&entities.M_MaintenanceGroupRoleUser{}, "maintenance_group_role_id = ?", maintGroupRoleId).Error; err != nil { + return err + } + return nil +} + +// Create implements MaintGroupRoleUserRepository. +func (m *maintGroupRoleUserRepository) Create(ctx context.Context, tx *gorm.DB, maintGroupRoleUser entities.M_MaintenanceGroupRoleUser) (entities.M_MaintenanceGroupRoleUser, error) { + if tx == nil { + tx = m.db + } + + if err := tx.WithContext(ctx).Create(&maintGroupRoleUser).Error; err != nil { + return entities.M_MaintenanceGroupRoleUser{}, err + } + return maintGroupRoleUser, nil +} + +// Delete implements MaintGroupRoleUserRepository. +func (m *maintGroupRoleUserRepository) Delete(ctx context.Context, tx *gorm.DB, maintGroupId string) error { + if tx == nil { + tx = m.db + } + if err := tx.WithContext(ctx).Delete(&entities.M_MaintenanceGroupRoleUser{}, "id = ?", maintGroupId).Error; err != nil { + return err + } + return nil +} + +// GetById implements MaintGroupRoleUserRepository. +func (m *maintGroupRoleUserRepository) GetById(ctx context.Context, tx *gorm.DB, maintGroupId string) (entities.M_MaintenanceGroupRoleUser, error) { + if tx == nil { + tx = m.db + } + var maintGroupRoleUser entities.M_MaintenanceGroupRoleUser + if err := tx.WithContext(ctx).First(&maintGroupRoleUser, "id = ?", maintGroupId).Error; err != nil { + return entities.M_MaintenanceGroupRoleUser{}, err + } + return maintGroupRoleUser, nil +} + +// Update implements MaintGroupRoleUserRepository. +func (m *maintGroupRoleUserRepository) Update(ctx context.Context, tx *gorm.DB, maintGroup entities.M_MaintenanceGroupRoleUser) (entities.M_MaintenanceGroupRoleUser, error) { + if tx == nil { + tx = m.db + } + if err := tx.WithContext(ctx).Updates(&maintGroup).Error; err != nil { + return entities.M_MaintenanceGroupRoleUser{}, err + } + return maintGroup, nil +} + +func NewMaintGroupRoleUserRepository(db *gorm.DB) MaintGroupRoleUserRepository { + return &maintGroupRoleUserRepository{ + db: db, + } +} diff --git a/modules/maintenance_group/routes.go b/modules/maintenance_group/routes.go new file mode 100644 index 0000000..49d30fe --- /dev/null +++ b/modules/maintenance_group/routes.go @@ -0,0 +1,24 @@ +package maintenancegroup + +import ( + "github.com/Caknoooo/go-gin-clean-starter/middlewares" + "github.com/Caknoooo/go-gin-clean-starter/modules/auth/service" + "github.com/Caknoooo/go-gin-clean-starter/modules/maintenance_group/controller" + "github.com/Caknoooo/go-gin-clean-starter/pkg/constants" + "github.com/gin-gonic/gin" + "github.com/samber/do" +) + +func RegisterRoutes(server *gin.Engine, injector *do.Injector) { + maintenanceGroupController := do.MustInvoke[controller.MaintenanceGroupController](injector) + jwtService := do.MustInvokeNamed[service.JWTService](injector, constants.JWTService) + + maintenanceGroupRoutes := server.Group("/api/v1/maintenance-groups") + { + maintenanceGroupRoutes.POST("", middlewares.Authenticate(jwtService), maintenanceGroupController.Create) + maintenanceGroupRoutes.GET("", middlewares.Authenticate(jwtService), maintenanceGroupController.GetAll) + maintenanceGroupRoutes.GET("/:id", middlewares.Authenticate(jwtService), maintenanceGroupController.GetById) + maintenanceGroupRoutes.PUT("/:id", middlewares.Authenticate(jwtService), maintenanceGroupController.Update) + maintenanceGroupRoutes.DELETE("/:id", middlewares.Authenticate(jwtService), maintenanceGroupController.Delete) + } +} diff --git a/modules/maintenance_group/service/maintenance_group_service.go b/modules/maintenance_group/service/maintenance_group_service.go new file mode 100644 index 0000000..2c35963 --- /dev/null +++ b/modules/maintenance_group/service/maintenance_group_service.go @@ -0,0 +1,365 @@ +package service + +import ( + "context" + + "github.com/Caknoooo/go-gin-clean-starter/database/entities" + "github.com/Caknoooo/go-gin-clean-starter/modules/maintenance_group/dto" + "github.com/Caknoooo/go-gin-clean-starter/modules/maintenance_group/repository" + staticDto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" + "github.com/google/uuid" + "gorm.io/gorm" +) + +type MaintenanceGroupService interface { + Create(ctx context.Context, maintGroup dto.MaintGroupCreateRequest) (dto.MaintGroupCreateRequest, error) + GetById(ctx context.Context, maintGroupId string) (dto.MaintGroupResponse, error) + GetByName(ctx context.Context, name string) (dto.MaintGroupResponse, error) + GetByCode(ctx context.Context, code string) (dto.MaintGroupResponse, error) + // GetAll(ctx context.Context) ([]dto.MaintGroupResponse, error) + Update(ctx context.Context, maintGroup dto.MaintGroupUpdateRequest, maintGroupId string) (dto.MaintGroupResponse, error) + Delete(ctx context.Context, maintGroupId string) error +} + +type maintenanceGroupService struct { + maintGroupRepo repository.MaintGroupRepository + maintGroupRoleRepo repository.MaintGroupRoleRepository + maintGroupRoleUserRepo repository.MaintGroupRoleUserRepository + db *gorm.DB +} + +// Create implements MaintenanceGroupService. +func (m *maintenanceGroupService) Create(ctx context.Context, req dto.MaintGroupCreateRequest) (dto.MaintGroupCreateRequest, error) { + tx := m.db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + clientUUID, err := uuid.Parse(req.ClientID) + if err != nil { + tx.Rollback() + return dto.MaintGroupCreateRequest{}, err + } + + maintGroup := entities.M_MaintenanceGroup{ + Code: req.Code, + Name: req.Name, + Description: req.Description, + ClientID: clientUUID, + } + createdGroup, err := m.maintGroupRepo.Create(ctx, tx, maintGroup) + if err != nil { + tx.Rollback() + return dto.MaintGroupCreateRequest{}, err + } + + for _, roleReq := range req.MaintenanceGroupRoles { + roleUUID, err := uuid.Parse(roleReq.RoleID) + if err != nil { + tx.Rollback() + return dto.MaintGroupCreateRequest{}, err + } + role := entities.M_MaintenanceGroupRole{ + MaintenanceGroupID: createdGroup.ID, + RoleID: roleUUID, + Level: roleReq.Level, + } + createdRole, err := m.maintGroupRoleRepo.Create(ctx, tx, role) + if err != nil { + tx.Rollback() + return dto.MaintGroupCreateRequest{}, err + } + for _, userReq := range roleReq.MaintenanceGroupRoleUsers { + userUUID, err := uuid.Parse(userReq.UserID) + if err != nil { + tx.Rollback() + return dto.MaintGroupCreateRequest{}, err + } + user := entities.M_MaintenanceGroupRoleUser{ + MaintenanceGroupRoleID: createdRole.ID, + UserID: userUUID, + } + _, err = m.maintGroupRoleUserRepo.Create(ctx, tx, user) + if err != nil { + tx.Rollback() + return dto.MaintGroupCreateRequest{}, err + } + } + } + + err = tx.Commit().Error + if err != nil { + tx.Rollback() + return dto.MaintGroupCreateRequest{}, err + } + return req, nil +} + +// Delete implements MaintenanceGroupService. +func (m *maintenanceGroupService) Delete(ctx context.Context, maintGroupId string) error { + tx := m.db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + err := m.maintGroupRepo.Delete(ctx, tx, maintGroupId) + if err != nil { + tx.Rollback() + return err + } + err = tx.Commit().Error + if err != nil { + tx.Rollback() + return err + } + return nil +} + +// GetAll implements MaintenanceGroupService. +// func (m *maintenanceGroupService) GetAll(ctx context.Context) ([]dto.MaintGroupResponse, error) { +// groups, err := m.maintGroupRepo.GetAll(ctx, m.db) +// if err != nil { +// return nil, err +// } +// var responses []dto.MaintGroupResponse +// for _, group := range groups { +// responses = append(responses, dto.MaintGroupResponse{ +// ID: group.ID.String(), +// Code: group.Code, +// Name: group.Name, +// Description: group.Description, +// ClientID: group.ClientID.String(), +// // MaintenanceGroupRoles: ... +// }) +// } +// return responses, nil +// } + +// GetByCode implements MaintenanceGroupService. +func (m *maintenanceGroupService) GetByCode(ctx context.Context, code string) (dto.MaintGroupResponse, error) { + panic("unimplemented") +} + +// GetById implements MaintenanceGroupService. +func (m *maintenanceGroupService) GetById(ctx context.Context, maintGroupId string) (dto.MaintGroupResponse, error) { + group, err := m.maintGroupRepo.GetById(ctx, m.db, maintGroupId) + if err != nil { + return dto.MaintGroupResponse{}, err + } + + // Mapping client + client := staticDto.ClientResponse{ + ID: group.Client.ID.String(), + Name: group.Client.Name, + } + + var roles []dto.MaintenanceGroupRoleResponse + for _, role := range group.MaintenanceGroupRoles { + // Mapping role + roleResp := staticDto.RoleResponse{ + ID: role.RoleID.String(), + Name: role.Role.Name, // pastikan entity Role ada field Name + } + + var users []dto.MaintenanceGroupRoleUserResponse + for _, user := range role.MaintenanceGroupRoleUsers { + userResp := staticDto.UserResponse{ + ID: user.User.ID.String(), + Name: user.User.Name, // pastikan entity User ada field Name + } + users = append(users, dto.MaintenanceGroupRoleUserResponse{ + ID: user.ID.String(), + User: userResp, + }) + } + + roles = append(roles, dto.MaintenanceGroupRoleResponse{ + ID: role.ID.String(), + Role: roleResp, + Level: role.Level, + MaintenanceGroupRoleUsers: users, + }) + } + + return dto.MaintGroupResponse{ + ID: group.ID.String(), + Code: group.Code, + Name: group.Name, + Description: group.Description, + Client: client, + MaintenanceGroupRoles: &roles, + }, nil +} + +// GetByName implements MaintenanceGroupService. +func (m *maintenanceGroupService) GetByName(ctx context.Context, name string) (dto.MaintGroupResponse, error) { + panic("unimplemented") +} + +// Update implements MaintenanceGroupService. +func (m *maintenanceGroupService) Update(ctx context.Context, req dto.MaintGroupUpdateRequest, maintGroupId string) (dto.MaintGroupResponse, error) { + tx := m.db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + group, err := m.maintGroupRepo.GetById(ctx, tx, maintGroupId) + if err != nil { + tx.Rollback() + return dto.MaintGroupResponse{}, err + } + if req.Code != nil { + group.Code = *req.Code + } + if req.Name != nil { + group.Name = *req.Name + } + if req.Description != nil { + group.Description = *req.Description + } + if req.ClientID != nil { + clientUUID, err := uuid.Parse(*req.ClientID) + if err != nil { + tx.Rollback() + return dto.MaintGroupResponse{}, err + } + group.ClientID = clientUUID + } + updatedGroup, err := m.maintGroupRepo.Update(ctx, tx, group) + if err != nil { + tx.Rollback() + return dto.MaintGroupResponse{}, err + } + + if req.MaintenanceGroupRoles != nil { + // 1. Ambil semua role lama via repo + oldRoles, err := m.maintGroupRoleRepo.FindByMaintGroupId(ctx, tx, group.ID.String()) + if err != nil { + tx.Rollback() + return dto.MaintGroupResponse{}, err + } + oldRoleIDs := map[string]bool{} + for _, r := range oldRoles { + oldRoleIDs[r.ID.String()] = true + } + + // 2. Upsert roles via repo + newRoleIDs := map[string]bool{} + for _, roleReq := range *req.MaintenanceGroupRoles { + + if roleReq.ID != nil { + newRoleIDs[*roleReq.ID] = true + role := entities.M_MaintenanceGroupRole{ + ID: uuid.MustParse(*roleReq.ID), + MaintenanceGroupID: group.ID, + RoleID: uuid.MustParse(*roleReq.RoleID), + Level: roleReq.Level, + } + if _, err := m.maintGroupRoleRepo.Update(ctx, tx, role); err != nil { + tx.Rollback() + return dto.MaintGroupResponse{}, err + } + } else { + role := entities.M_MaintenanceGroupRole{ + MaintenanceGroupID: group.ID, + RoleID: uuid.MustParse(*roleReq.RoleID), + Level: roleReq.Level, + } + if _, err := m.maintGroupRoleRepo.Create(ctx, tx, role); err != nil { + tx.Rollback() + return dto.MaintGroupResponse{}, err + } + } + } + + // 3. Hapus role lama yang tidak ada di request via repo + var toDelete []string + for oldID := range oldRoleIDs { + if !newRoleIDs[oldID] { + toDelete = append(toDelete, oldID) + } + } + if len(toDelete) > 0 { + if err := m.maintGroupRoleRepo.DeleteByIds(ctx, tx, toDelete); err != nil { + tx.Rollback() + return dto.MaintGroupResponse{}, err + } + } + + // 4. Untuk setiap role, lakukan upsert pada users via repo + for _, roleReq := range *req.MaintenanceGroupRoles { + var roleID uuid.UUID + if roleReq.ID != nil { + roleID = uuid.MustParse(*roleReq.ID) + } else { + // Handle ambil ID role baru jika perlu + continue + } + oldUsers, err := m.maintGroupRoleUserRepo.FindByRoleId(ctx, tx, roleID.String()) + if err != nil { + tx.Rollback() + return dto.MaintGroupResponse{}, err + } + oldUserIDs := map[string]bool{} + for _, u := range oldUsers { + oldUserIDs[u.UserID.String()] = true + } + newUserIDs := map[string]bool{} + if roleReq.MaintenanceGroupRoleUsers != nil { + for _, userReq := range *roleReq.MaintenanceGroupRoleUsers { + if userReq.UserID != "" { + newUserIDs[userReq.UserID] = true + userUUID := uuid.MustParse(userReq.UserID) + if !oldUserIDs[userReq.UserID] { + user := entities.M_MaintenanceGroupRoleUser{ + MaintenanceGroupRoleID: roleID, + UserID: userUUID, + } + if _, err := m.maintGroupRoleUserRepo.Create(ctx, tx, user); err != nil { + tx.Rollback() + return dto.MaintGroupResponse{}, err + } + } + } + } + } + var toDeleteUser []string + for oldID := range oldUserIDs { + if !newUserIDs[oldID] { + toDeleteUser = append(toDeleteUser, oldID) + } + } + if len(toDeleteUser) > 0 { + if err := m.maintGroupRoleUserRepo.DeleteByRoleIdAndUserIds(ctx, tx, roleID.String(), toDeleteUser); err != nil { + tx.Rollback() + return dto.MaintGroupResponse{}, err + } + } + } + } + + err = tx.Commit().Error + if err != nil { + tx.Rollback() + return dto.MaintGroupResponse{}, err + } + + result, err := m.GetById(ctx, updatedGroup.ID.String()) + if err != nil { + return dto.MaintGroupResponse{}, err + } + return result, nil +} + +func NewMaintenanceGroupService(maintGroupRepo repository.MaintGroupRepository, maintGroupRoleRepo repository.MaintGroupRoleRepository, maintGroupRoleUserRepo repository.MaintGroupRoleUserRepository, db *gorm.DB) MaintenanceGroupService { + return &maintenanceGroupService{ + maintGroupRepo: maintGroupRepo, + maintGroupRoleRepo: maintGroupRoleRepo, + maintGroupRoleUserRepo: maintGroupRoleUserRepo, + db: db, + } +}