package controller import ( "net/http" "github.com/Caknoooo/go-gin-clean-starter/modules/role/dto" "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" "github.com/samber/do" "github.com/sirupsen/logrus" "gorm.io/gorm" ) type ( RoleController interface { CreateRole(ctx *gin.Context) GetRoles(ctx *gin.Context) GetRoleByID(ctx *gin.Context) UpdateRole(ctx *gin.Context) DeleteRole(ctx *gin.Context) AssignPermissionsToRole(ctx *gin.Context) RemovePermissionsFromRole(ctx *gin.Context) AssignRolesToUser(ctx *gin.Context) RemoveRolesFromUser(ctx *gin.Context) GetRolesByUserID(ctx *gin.Context) AssignMenusToRole(ctx *gin.Context) RemoveMenusFromRole(ctx *gin.Context) } roleController struct { roleService service.RoleService db *gorm.DB } ) // AssignMenusToRole godoc // @Summary Assign menus to role // @Description Assign menus to a role by role ID. // @Tags Roles // @Accept json // @Produce json // @Param id path string true "Role ID" // @Param body body dto.AssignMenuRequest true "Assign menus payload" // @Success 200 {object} map[string]interface{} // @Failure 400 {object} map[string]interface{} // @Router /roles/{id}/assign-menus [post] func (r *roleController) AssignMenusToRole(ctx *gin.Context) { id := ctx.Param("id") var req dto.AssignMenuRequest 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 } if err := r.roleService.AssignMenusToRole(ctx.Request.Context(), id, req.MenuID); err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_ASSIGN_MENU, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_ASSIGN_MENU, nil) ctx.JSON(http.StatusOK, res) } // RemoveMenusFromRole godoc // @Summary Remove menus from role // @Description Remove menus from a role by role ID. // @Tags Roles // @Accept json // @Produce json // @Param id path string true "Role ID" // @Param body body dto.RemoveMenuRequest true "Remove menus payload" // @Success 200 {object} map[string]interface{} // @Failure 400 {object} map[string]interface{} // @Router /roles/{id}/remove-menus [post] func (r *roleController) RemoveMenusFromRole(ctx *gin.Context) { id := ctx.Param("id") var req dto.RemoveMenuRequest 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 } if err := r.roleService.RemoveMenusFromRole(ctx.Request.Context(), id, req.MenuID); err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_REMOVE_MENU, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_REMOVE_MENU, nil) ctx.JSON(http.StatusOK, res) } // AssignPermissionsToRole godoc // @Summary Assign permissions to role // @Description Assign permissions to a role by role ID. // @Tags Roles // @Accept json // @Produce json // @Param id path string true "Role ID" // @Param body body dto.AssignPermissionRequest true "Assign permissions payload" // @Success 200 {object} map[string]interface{} // @Failure 400 {object} map[string]interface{} // @Router /roles/{id}/permissions [post] func (r *roleController) AssignPermissionsToRole(ctx *gin.Context) { var req dto.AssignPermissionRequest roleId := ctx.Param("id") 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 } if err := r.roleService.AssignPermissionsToRole(ctx.Request.Context(), roleId, req.PermissionID); err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_ASSIGN_PERMISSION, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_ASSIGN_PERMISSION, nil) ctx.JSON(http.StatusOK, res) } // AssignRolesToUser godoc // @Summary Assign roles to user // @Description Assign roles to a user by user ID. // @Tags Roles // @Accept json // @Produce json // @Param id path string true "User ID" // @Param body body dto.AssignRoleRequest true "Assign roles payload" // @Success 200 {object} map[string]interface{} // @Failure 400 {object} map[string]interface{} // @Router /users/{id}/assign-roles [post] func (r *roleController) AssignRolesToUser(ctx *gin.Context) { var req dto.AssignRoleRequest userId := ctx.Param("id") 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 } if err := r.roleService.AssignRolesToUser(ctx.Request.Context(), userId, req.RoleID); err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_ASSIGN_ROLE, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_ASSIGN_ROLE, nil) ctx.JSON(http.StatusOK, res) } // CreateRole godoc // @Summary Create a new role // @Description Create a new role. // @Tags Roles // @Accept json // @Produce json // @Param body body dto.RoleCreateRequest true "Role create payload" // @Success 200 {object} utils.Response // @Failure 400 {object} map[string]interface{} // @Router /roles [post] func (r *roleController) CreateRole(ctx *gin.Context) { var role dto.RoleCreateRequest if err := ctx.ShouldBind(&role); err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_DATA_FROM_BODY, err.Error(), nil) ctx.AbortWithStatusJSON(http.StatusBadRequest, res) return } result, err := r.roleService.CreateRole(ctx.Request.Context(), role) if err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_REGISTER_ROLE, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_REGISTER_ROLE, result) ctx.JSON(http.StatusOK, res) } // DeleteRole godoc // @Summary Delete a role // @Description Delete a role by ID. // @Tags Roles // @Accept json // @Produce json // @Param id path string true "Role ID" // @Success 200 {object} map[string]interface{} // @Failure 400 {object} map[string]interface{} // @Router /roles/{id} [delete] func (r *roleController) DeleteRole(ctx *gin.Context) { var roleID string = ctx.Param("id") err := r.roleService.DeleteRole(ctx.Request.Context(), roleID) if err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_DELETE_ROLE, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_DELETE_ROLE, nil) ctx.JSON(http.StatusOK, res) } // GetRoleByID godoc // @Summary Get role by ID // @Description Get details of a role by ID. // @Tags Roles // @Accept json // @Produce json // @Param id path string true "Role ID" // @Success 200 {object} utils.Response // @Failure 400 {object} map[string]interface{} // @Router /roles/{id} [get] func (r *roleController) GetRoleByID(ctx *gin.Context) { var roleID string = ctx.Param("id") result, err := r.roleService.GetRoleByID(ctx.Request.Context(), roleID) if err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_ROLE, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_GET_ROLE, result) ctx.JSON(http.StatusOK, res) } // GetRoles godoc // @Summary Get all roles // @Description Get paginated list of roles. Supports filtering and pagination. // @Tags Roles // @Accept json // @Produce json // @Param name query string false "Filter by name (partial match)" // @Param page query int false "Page number (default: 1)" // @Param page_size query int false "Page size (default: 10)" // @Success 200 {array} utils.ResponseWithPagination // @Failure 400 {object} map[string]interface{} // @Router /roles [get] func (r *roleController) GetRoles(ctx *gin.Context) { // clientId := ctx.MustGet("client_id").(string) // logrus.Info("Client ID: ", clientId) getAll := ctx.Query("get_all") var filter = &query.RoleFilter{ ClientID: ctx.Query("client_id"), Name: ctx.Query("name"), } if getAll == "true" { // Ambil semua data tanpa paginasi roles, err := r.roleService.GetAll(ctx.Request.Context()) if err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_LIST_ROLE, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } // Tidak perlu ToUserResponses, karena sudah []dto.UserResponse res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_GET_LIST_ROLE, roles) ctx.JSON(http.StatusOK, res) return } // logrus.Info("Filter: ", filter) filter.BindPagination(ctx) ctx.ShouldBindQuery(filter) roles, total, err := pagination.PaginatedQueryWithIncludable[query.M_Role](r.db, filter) if err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_ROLE, err.Error(), nil) 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, roleResponses, paginationResponse) ctx.JSON(http.StatusOK, response) } // GetRolesByUserID godoc // @Summary Get roles by user ID // @Description Get all roles assigned to a user by user ID. // @Tags Roles // @Accept json // @Produce json // @Param id path string true "User ID" // @Success 200 {array} utils.ResponseWithPagination // @Failure 400 {object} map[string]interface{} // @Router /users/{id}/roles [get] func (r *roleController) GetRolesByUserID(ctx *gin.Context) { userId := ctx.Param("id") logrus.Info("Fetching roles for User ID: ", userId) roles, err := r.roleService.GetRolesByUserID(ctx.Request.Context(), userId) if err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_ROLE, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_GET_ROLE, roles) ctx.JSON(http.StatusOK, res) } // RemovePermissionsFromRole godoc // @Summary Remove permissions from role // @Description Remove permissions from a role by role ID. // @Tags Roles // @Accept json // @Produce json // @Param id path string true "Role ID" // @Param body body dto.RemovePermissionRequest true "Remove permissions payload" // @Success 200 {object} map[string]interface{} // @Failure 400 {object} map[string]interface{} // @Router /roles/{id}/permissions [post] func (r *roleController) RemovePermissionsFromRole(ctx *gin.Context) { var req dto.RemovePermissionRequest roleId := ctx.Param("id") 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 } if err := r.roleService.RemovePermissionsFromRole(ctx.Request.Context(), roleId, req.PermissionID); err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_REMOVE_ROLE, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_REMOVE_ROLE, nil) ctx.JSON(http.StatusOK, res) } // RemoveRolesFromUser godoc // @Summary Remove roles from user // @Description Remove roles from a user by user ID. // @Tags Roles // @Accept json // @Produce json // @Param id path string true "User ID" // @Param body body dto.RemoveRoleRequest true "Remove roles payload" // @Success 200 {object} map[string]interface{} // @Failure 400 {object} map[string]interface{} // @Router /users/{id}/remove-roles [post] func (r *roleController) RemoveRolesFromUser(ctx *gin.Context) { var req dto.RemoveRoleRequest userId := ctx.Param("id") 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 } if err := r.roleService.RemoveRolesFromUser(ctx.Request.Context(), userId, req.RoleID); err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_REMOVE_ROLE, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_REMOVE_ROLE, nil) ctx.JSON(http.StatusOK, res) } // UpdateRole godoc // @Summary Update a role // @Description Update a role by ID. // @Tags Roles // @Accept json // @Produce json // @Param id path string true "Role ID" // @Param body body dto.RoleUpdateRequest true "Role update payload" // @Success 200 {object} utils.Response // @Failure 400 {object} map[string]interface{} // @Router /roles/{id} [put] func (r *roleController) UpdateRole(ctx *gin.Context) { var req dto.RoleUpdateRequest 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 } roleId := ctx.Param("id") result, err := r.roleService.UpdateRole(ctx.Request.Context(), roleId, req) if err != nil { res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_UPDATE_ROLE, err.Error(), nil) ctx.JSON(http.StatusBadRequest, res) return } res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_UPDATE_ROLE, result) ctx.JSON(http.StatusOK, res) } func NewRoleController(injector *do.Injector, rs service.RoleService) RoleController { db := do.MustInvokeNamed[*gorm.DB](injector, constants.DB) return &roleController{ roleService: rs, 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, }, } }