From 82579efe365f35650d5cf5877d56bc118e85a757 Mon Sep 17 00:00:00 2001 From: Habib Fatkhul Rohman Date: Fri, 31 Oct 2025 11:27:29 +0700 Subject: [PATCH] feat(role): Refactor role handling to include client details in responses and update API routes --- modules/role/controller/role_controller.go | 28 ++++- modules/role/dto/role_dto.go | 21 ++-- modules/role/query/role_query.go | 18 ++- modules/role/repository/role_repository.go | 2 + modules/role/service/role_service.go | 138 ++++++++++++--------- 5 files changed, 136 insertions(+), 71 deletions(-) diff --git a/modules/role/controller/role_controller.go b/modules/role/controller/role_controller.go index 7a308c1..c253967 100644 --- a/modules/role/controller/role_controller.go +++ b/modules/role/controller/role_controller.go @@ -7,6 +7,7 @@ import ( "github.com/Caknoooo/go-gin-clean-starter/modules/role/query" "github.com/Caknoooo/go-gin-clean-starter/modules/role/service" "github.com/Caknoooo/go-gin-clean-starter/pkg/constants" + pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" "github.com/Caknoooo/go-gin-clean-starter/pkg/utils" "github.com/Caknoooo/go-pagination" "github.com/gin-gonic/gin" @@ -45,7 +46,7 @@ type ( // @Param body body dto.AssignPermissionRequest true "Assign permissions payload" // @Success 200 {object} map[string]interface{} // @Failure 400 {object} map[string]interface{} -// @Router /roles/{id}/assign-permissions [post] +// @Router /roles/{id}/permissions [post] func (r *roleController) AssignPermissionsToRole(ctx *gin.Context) { var req dto.AssignPermissionRequest roleId := ctx.Param("id") @@ -189,7 +190,6 @@ func (r *roleController) GetRoles(ctx *gin.Context) { } // logrus.Info("Filter: ", filter) filter.BindPagination(ctx) - ctx.ShouldBindQuery(filter) roles, total, err := pagination.PaginatedQueryWithIncludable[query.M_Role](r.db, filter) @@ -198,9 +198,14 @@ func (r *roleController) GetRoles(ctx *gin.Context) { ctx.JSON(http.StatusBadRequest, res) return } + // Di GetRoles: + var roleResponses []dto.RoleResponse + for _, role := range roles { + roleResponses = append(roleResponses, mapRoleToResponse(role)) + } paginationResponse := pagination.CalculatePagination(filter.Pagination, total) - response := pagination.NewPaginatedResponse(http.StatusOK, dto.MESSAGE_SUCCESS_GET_LIST_ROLE, roles, paginationResponse) + response := pagination.NewPaginatedResponse(http.StatusOK, dto.MESSAGE_SUCCESS_GET_LIST_ROLE, roleResponses, paginationResponse) ctx.JSON(http.StatusOK, response) } @@ -238,7 +243,7 @@ func (r *roleController) GetRolesByUserID(ctx *gin.Context) { // @Param body body dto.RemovePermissionRequest true "Remove permissions payload" // @Success 200 {object} map[string]interface{} // @Failure 400 {object} map[string]interface{} -// @Router /roles/{id}/remove-permissions [post] +// @Router /roles/{id}/permissions [post] func (r *roleController) RemovePermissionsFromRole(ctx *gin.Context) { var req dto.RemovePermissionRequest roleId := ctx.Param("id") @@ -323,3 +328,18 @@ func NewRoleController(injector *do.Injector, rs service.RoleService) RoleContro db: db, } } + +func mapRoleToResponse(role query.M_Role) dto.RoleResponse { + return dto.RoleResponse{ + ID: role.ID, + Name: role.Name, + Description: role.Description, + IconUrl: role.IconUrl, + Type: role.Type, + HomeUrl: role.HomeUrl, + Client: pkgdto.IdNameResponse{ + ID: role.Client.ID.String(), + Name: role.Client.Name, + }, + } +} diff --git a/modules/role/dto/role_dto.go b/modules/role/dto/role_dto.go index de1b2fb..062dfcc 100644 --- a/modules/role/dto/role_dto.go +++ b/modules/role/dto/role_dto.go @@ -1,6 +1,10 @@ package dto -import "errors" +import ( + "errors" + + pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" +) const ( // Failed @@ -72,13 +76,14 @@ type RoleUpdateRequest struct { } type RoleResponse struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - IconUrl string `json:"icon_url"` - Type string `json:"type"` - HomeUrl string `json:"home_url"` - ClientID string `json:"client_id"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + IconUrl string `json:"icon_url"` + Type string `json:"type"` + HomeUrl string `json:"home_url"` + // ClientID string `json:"client_id"` + Client pkgdto.IdNameResponse `json:"client"` Permissions []RolePermissionsResponse `json:"permissions,omitempty"` } diff --git a/modules/role/query/role_query.go b/modules/role/query/role_query.go index d903485..a9f7749 100644 --- a/modules/role/query/role_query.go +++ b/modules/role/query/role_query.go @@ -2,15 +2,22 @@ package query import ( // "github.com/Caknoooo/go-gin-clean-starter/database/entities" + "github.com/Caknoooo/go-gin-clean-starter/database/entities" "github.com/Caknoooo/go-pagination" "gorm.io/gorm" ) type M_Role struct { - ID string `json:"id"` - Name string `json:"name"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + IconUrl string `json:"icon_url"` + Type string `json:"type"` + HomeUrl string `json:"home_url"` // Permissions []entities.M_Permissions `json:"permissions" gorm:"many2many:m_role_permissions;joinForeignKey:RoleID;JoinReferences:PermissionID"` - ClientID string `json:"client_id"` + ClientID string `json:"client_id"` + Client entities.M_Client `json:"client" gorm:"foreignKey:ClientID;references:ID"` + // Client pkgdto.IdNameResponse `json:"client"` } type RoleFilter struct { @@ -27,6 +34,11 @@ func (f *RoleFilter) ApplyFilters(query *gorm.DB) *gorm.DB { if f.ClientID != "" { query = query.Where("client_id = ?", f.ClientID) } + + query = query.Model(entities.M_Role{}). + Preload("Client", func(db *gorm.DB) *gorm.DB { + return db.Select("m_clients.id", "m_clients.name") + }) return query } diff --git a/modules/role/repository/role_repository.go b/modules/role/repository/role_repository.go index 9da8080..6365984 100644 --- a/modules/role/repository/role_repository.go +++ b/modules/role/repository/role_repository.go @@ -127,6 +127,7 @@ func (r *roleRepository) GetRoleByID(ctx context.Context, tx *gorm.DB, id string var role entities.M_Role if err := tx.WithContext(ctx). Where("id = ?", id). + Preload("Client"). Preload("Permissions"). First(&role).Error; err != nil { return entities.M_Role{}, err @@ -144,6 +145,7 @@ func (r *roleRepository) GetRolesByUserID(ctx context.Context, tx *gorm.DB, user Model(&entities.M_Role{}). Joins("JOIN m_user_roles ur ON ur.role_id = m_roles.id"). Where("ur.user_id = ?", userId). + Preload("Client"). Preload("Permissions"). Find(&roles).Error; err != nil { return nil, err diff --git a/modules/role/service/role_service.go b/modules/role/service/role_service.go index 9a325c4..41e460b 100644 --- a/modules/role/service/role_service.go +++ b/modules/role/service/role_service.go @@ -11,6 +11,7 @@ import ( "github.com/Caknoooo/go-gin-clean-starter/modules/role/repository" userDto "github.com/Caknoooo/go-gin-clean-starter/modules/user/dto" userService "github.com/Caknoooo/go-gin-clean-starter/modules/user/service" + pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" "github.com/google/uuid" "github.com/sirupsen/logrus" "gorm.io/gorm" @@ -182,15 +183,13 @@ func (r *roleService) CreateRole(ctx context.Context, req dto.RoleCreateRequest) if err != nil { return dto.RoleResponse{}, err } - return dto.RoleResponse{ - ID: createdRole.ID.String(), - Name: createdRole.Name, - Description: createdRole.Description, - IconUrl: createdRole.IconUrl, - Type: createdRole.Type, - HomeUrl: createdRole.HomeUrl, - ClientID: createdRole.ClientID.String(), - }, nil + + result, err := r.roleRepo.GetRoleByID(ctx, r.db, createdRole.ID.String()) + if err != nil { + return dto.RoleResponse{}, err + } + return ToRoleResponse(result), nil + } // DeleteRole implements RoleService. @@ -208,24 +207,7 @@ func (r *roleService) GetRoleByID(ctx context.Context, id string) (dto.RoleRespo return dto.RoleResponse{}, err } - var permissions []dto.RolePermissionsResponse - for _, p := range role.Permissions { - permissions = append(permissions, dto.RolePermissionsResponse{ - ID: p.ID.String(), - Name: p.Name, - }) - } - - return dto.RoleResponse{ - ID: role.ID.String(), - Name: role.Name, - Description: role.Description, - IconUrl: role.IconUrl, - Type: role.Type, - HomeUrl: role.HomeUrl, - ClientID: role.ClientID.String(), - Permissions: permissions, - }, nil + return ToRoleResponse(role), nil } // GetRoles implements RoleService. @@ -234,6 +216,44 @@ func (r *roleService) GetRoles(ctx context.Context, filter query.RoleFilter) ([] } // GetRolesByUserID implements RoleService. +// func (r *roleService) GetRolesByUserID(ctx context.Context, userId string) ([]dto.RoleResponse, error) { +// if _, err := r.userService.GetUserById(ctx, userId); err != nil { +// return nil, userDto.ErrUserNotFound +// } + +// roles, err := r.roleRepo.GetRolesByUserID(ctx, r.db, userId) +// if err != nil { +// logrus.Error("Error fetching roles for user ", userId, ": ", err) +// return nil, err +// } + +// logrus.Info("Fetched ", len(roles), " roles for user ", userId) + +// var responses []dto.RoleResponse +// for _, role := range roles { +// var permissions []dto.RolePermissionsResponse +// for _, p := range role.Permissions { +// permissions = append(permissions, dto.RolePermissionsResponse{ +// ID: p.ID.String(), +// Name: p.Name, +// }) +// } + +// responses = append(responses, dto.RoleResponse{ +// ID: role.ID.String(), +// Name: role.Name, +// Description: role.Description, +// IconUrl: role.IconUrl, +// Type: role.Type, +// HomeUrl: role.HomeUrl, +// ClientID: role.ClientID.String(), +// Permissions: permissions, +// }) +// } + +// return responses, nil +// } + func (r *roleService) GetRolesByUserID(ctx context.Context, userId string) ([]dto.RoleResponse, error) { if _, err := r.userService.GetUserById(ctx, userId); err != nil { return nil, userDto.ErrUserNotFound @@ -241,32 +261,12 @@ func (r *roleService) GetRolesByUserID(ctx context.Context, userId string) ([]dt roles, err := r.roleRepo.GetRolesByUserID(ctx, r.db, userId) if err != nil { - logrus.Error("Error fetching roles for user ", userId, ": ", err) return nil, err } - logrus.Info("Fetched ", len(roles), " roles for user ", userId) - var responses []dto.RoleResponse for _, role := range roles { - var permissions []dto.RolePermissionsResponse - for _, p := range role.Permissions { - permissions = append(permissions, dto.RolePermissionsResponse{ - ID: p.ID.String(), - Name: p.Name, - }) - } - - responses = append(responses, dto.RoleResponse{ - ID: role.ID.String(), - Name: role.Name, - Description: role.Description, - IconUrl: role.IconUrl, - Type: role.Type, - HomeUrl: role.HomeUrl, - ClientID: role.ClientID.String(), - Permissions: permissions, - }) + responses = append(responses, ToRoleResponse(role)) } return responses, nil @@ -400,15 +400,41 @@ func (r *roleService) UpdateRole(ctx context.Context, id string, req dto.RoleUpd return dto.RoleResponse{}, err } + result, err := r.roleRepo.GetRoleByID(ctx, r.db, updatedRole.ID.String()) + if err != nil { + return dto.RoleResponse{}, err + } + + return ToRoleResponse(result), nil +} + +func ToRoleResponse(role entities.M_Role) dto.RoleResponse { + var permissions []dto.RolePermissionsResponse + for _, p := range role.Permissions { + permissions = append(permissions, dto.RolePermissionsResponse{ + ID: p.ID.String(), + Name: p.Name, + }) + } + + var client pkgdto.IdNameResponse + if role.Client.ID != uuid.Nil { + client = pkgdto.IdNameResponse{ + ID: role.Client.ID.String(), + Name: role.Client.Name, + } + } + return dto.RoleResponse{ - ID: updatedRole.ID.String(), - Name: updatedRole.Name, - Description: updatedRole.Description, - IconUrl: updatedRole.IconUrl, - Type: updatedRole.Type, - HomeUrl: updatedRole.HomeUrl, - ClientID: updatedRole.ClientID.String(), - }, nil + ID: role.ID.String(), + Name: role.Name, + Description: role.Description, + IconUrl: role.IconUrl, + Type: role.Type, + HomeUrl: role.HomeUrl, + Client: client, + Permissions: permissions, + } } func NewRoleService(