package user import ( "RenewCMS/api/pkg/access" "RenewCMS/api/pkg/apperr" validator "RenewCMS/api/pkg/validator" "RenewCMS/internal/domain/role" domain "RenewCMS/internal/domain/user" "RenewCMS/internal/infrastructure/useCases" "encoding/json" "errors" "net/http" "strconv" "github.com/go-chi/chi/v5" ) type RoleHandler struct { ChangeUserRoleUseCase *useCases.ChangeUserRoleUseCase } type ChangeRoleRequest struct { RoleID uint32 `json:"role_id" validate:"required"` } func NewRoleHandler(changeRole *useCases.ChangeUserRoleUseCase) *RoleHandler { return &RoleHandler{ChangeUserRoleUseCase: changeRole} } func userListItemOf(entry useCases.DirectoryEntry) userListItem { return userListItem{entry.ID, entry.Kind, entry.Username, entry.DisplayName, entry.Email, entry.Role, entry.Status, entry.CreatedAt} } func writeNoStoreJSON(w http.ResponseWriter, status int, payload any) { body, err := json.Marshal(payload) if err != nil { http.Error(w, "Internal server error", http.StatusInternalServerError) return } w.Header().Set("Cache-Control", "no-store") w.WriteHeader(status) _, _ = w.Write(body) } func (h *RoleHandler) Change(w http.ResponseWriter, r *http.Request) { targetID, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 32) if err != nil { http.Error(w, apperr.IdUint32ErrorMessage, http.StatusBadRequest) return } var request ChangeRoleRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest) return } if err := validator.Validate.Struct(request); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } changed, err := h.ChangeUserRoleUseCase.ChangeRole(r.Context(), useCases.ChangeUserRoleCommand{ Caller: access.CallerOf(r), TargetID: uint32(targetID), RoleID: request.RoleID, }) if err != nil { writeChangeRoleError(w, err) return } writeNoStoreJSON(w, http.StatusOK, userListItemOf(changed)) } func writeChangeRoleError(w http.ResponseWriter, err error) { if writeRoleRefusal(w, err) { return } switch { case errors.Is(err, role.ErrOwnRole): http.Error(w, apperr.OwnRoleErrorMessage, http.StatusForbidden) case errors.Is(err, domain.ErrUserNotFound): http.Error(w, apperr.UserNotFoundErrorMessage, http.StatusNotFound) case errors.Is(err, domain.ErrRoleChanged): http.Error(w, apperr.UserRoleChangedErrorMessage, http.StatusConflict) default: http.Error(w, "Internal server error", http.StatusInternalServerError) } }