From 4706d4ea81ef6d4ecfd2b00343ea6f83c6f3f804 Mon Sep 17 00:00:00 2001 From: AzenKain Date: Wed, 8 Apr 2026 14:23:17 +0700 Subject: [PATCH] UPDATE: Fix bug --- db/query/users.sql | 1 + internal/controllers/userController.go | 18 +++++++++- internal/gen/sqlc/users.sql.go | 1 + internal/services/userService.go | 49 +++++++++++++++++++++++--- 4 files changed, 63 insertions(+), 6 deletions(-) diff --git a/db/query/users.sql b/db/query/users.sql index 0705802..52f75a1 100644 --- a/db/query/users.sql +++ b/db/query/users.sql @@ -253,6 +253,7 @@ WHERE WHERE p.user_id = u.id AND ( p.full_name ILIKE '%' || sqlc.narg('search_text')::text || '%' OR + p.display_name ILIKE '%' || sqlc.narg('search_text')::text || '%' OR p.phone ILIKE '%' || sqlc.narg('search_text')::text || '%' ) ) diff --git a/internal/controllers/userController.go b/internal/controllers/userController.go index 441f426..a90a59f 100644 --- a/internal/controllers/userController.go +++ b/internal/controllers/userController.go @@ -260,7 +260,23 @@ func (h *UserController) ChangeRoleUser(c fiber.Ctx) error { Message: err.Error(), }) } - user, err := h.service.ChangeRoleUser(ctx, dto) + claimsVal := c.Locals("user_claims") + if claimsVal == nil { + return c.Status(fiber.StatusUnauthorized).JSON(response.CommonResponse{ + Status: false, + Message: "Unauthorized", + }) + } + + claims, ok := claimsVal.(*response.JWTClaims) + if !ok { + return c.Status(fiber.StatusUnauthorized).JSON(response.CommonResponse{ + Status: false, + Message: "Invalid user claims", + }) + } + + user, err := h.service.ChangeRoleUser(ctx, claims, dto) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(response.CommonResponse{ Status: false, diff --git a/internal/gen/sqlc/users.sql.go b/internal/gen/sqlc/users.sql.go index da8f525..3d5a9e0 100644 --- a/internal/gen/sqlc/users.sql.go +++ b/internal/gen/sqlc/users.sql.go @@ -410,6 +410,7 @@ WHERE WHERE p.user_id = u.id AND ( p.full_name ILIKE '%' || $6::text || '%' OR + p.display_name ILIKE '%' || $6::text || '%' OR p.phone ILIKE '%' || $6::text || '%' ) ) diff --git a/internal/services/userService.go b/internal/services/userService.go index 5c2cf75..2bbcf81 100644 --- a/internal/services/userService.go +++ b/internal/services/userService.go @@ -7,7 +7,9 @@ import ( "history-api/internal/gen/sqlc" "history-api/internal/models" "history-api/internal/repositories" + "history-api/pkg/constants" "history-api/pkg/convert" + "slices" "github.com/gofiber/fiber/v3" "github.com/jackc/pgx/v5/pgtype" @@ -23,7 +25,7 @@ type UserService interface { //admin DeleteUser(ctx context.Context, userId string) error - ChangeRoleUser(ctx context.Context, dto *request.ChangeRoleDto) (*response.UserResponse, error) + ChangeRoleUser(ctx context.Context, claims *response.JWTClaims, dto *request.ChangeRoleDto) (*response.UserResponse, error) RestoreUser(ctx context.Context, userId string) (*response.UserResponse, error) GetUserByID(ctx context.Context, userId string) (*response.UserResponse, error) SearchUser(ctx context.Context, dto *request.SearchUserDto) (*response.PaginatedResponse, error) @@ -77,7 +79,7 @@ func (u *userService) ChangePassword(ctx context.Context, userId string, dto *re return nil } -func (u *userService) ChangeRoleUser(ctx context.Context, dto *request.ChangeRoleDto) (*response.UserResponse, error) { +func (u *userService) ChangeRoleUser(ctx context.Context, claims *response.JWTClaims, dto *request.ChangeRoleDto) (*response.UserResponse, error) { userId, err := convert.StringToUUID(dto.UserID) if err != nil { return nil, fiber.NewError(fiber.StatusInternalServerError, err.Error()) @@ -91,13 +93,50 @@ func (u *userService) ChangeRoleUser(ctx context.Context, dto *request.ChangeRol return nil, fiber.NewError(fiber.StatusNotFound, "User not found") } - roleIdstr, err := u.roleRepo.GetByIDs(ctx, dto.Roles) + rolesFromDB, err := u.roleRepo.GetByIDs(ctx, dto.Roles) if err != nil { - return nil, fiber.NewError(fiber.StatusInternalServerError, err.Error()) + return nil, err } + + hasUserRole := false + hasAdminRole := false + hasBannedRole := false + + for _, r := range rolesFromDB { + if r.Name == constants.USER.String() { + hasUserRole = true + } + if r.Name == constants.ADMIN.String() { + hasAdminRole = true + } + if r.Name == constants.BANNED.String() { + hasBannedRole = true + } + } + + if !hasUserRole { + return nil, fiber.NewError(fiber.StatusNotFound, "User must have the USER role") + } + + if slices.Contains(claims.Roles, constants.MOD) && !slices.Contains(claims.Roles, constants.ADMIN) { + if hasAdminRole { + return nil, fiber.NewError(fiber.StatusForbidden, "MOD cannot assign ADMIN role to any user") + } + isTargetAdmin := false + for _, r := range user.Roles { + if r.Name == string(constants.ADMIN) { + isTargetAdmin = true + break + } + } + if isTargetAdmin && hasBannedRole { + return nil, fiber.NewError(fiber.StatusForbidden, "MOD cannot assign BANNED role to an ADMIN user") + } + } + user.Roles = make([]*models.RoleSimple, 0) roleIdList := make([]pgtype.UUID, 0) - for _, role := range roleIdstr { + for _, role := range rolesFromDB { roleID, err := convert.StringToUUID(role.ID) if err != nil { continue