Spaces:
Sleeping
Sleeping
| package controllers | |
| import ( | |
| "strconv" | |
| "abdanhafidz.com/go-boilerplate/models/dto" | |
| entity "abdanhafidz.com/go-boilerplate/models/entity" | |
| http_error "abdanhafidz.com/go-boilerplate/models/error" | |
| "abdanhafidz.com/go-boilerplate/services" | |
| "github.com/gin-gonic/gin" | |
| "github.com/google/uuid" | |
| ) | |
| type UserController interface { | |
| ListUsers(ctx *gin.Context) | |
| CreateUser(ctx *gin.Context) | |
| BulkCreateUsers(ctx *gin.Context) | |
| UpdateUser(ctx *gin.Context) | |
| DeleteUser(ctx *gin.Context) | |
| } | |
| type userController struct { | |
| accountService services.AccountService | |
| } | |
| func NewUserController(accountService services.AccountService) UserController { | |
| return &userController{accountService} | |
| } | |
| // ListUsers godoc | |
| // @Summary List All Users with Pagination | |
| // @Description Retrieve a paginated list of all users with optional role filter. Supports pagination parameters (page, limit) and can filter by user role. | |
| // @Tags Super Admin Users Management | |
| // @Accept json | |
| // @Produce json | |
| // @Security BearerAuth | |
| // @Param page query int false "Page number for pagination. Minimum value is 1. Default is 1." | |
| // @Param limit query int false "Number of items per page. Minimum 1, Maximum 50. Default is 10." | |
| // @Param role query string false "Filter users by role. Allowed values: user, admin, super_admin. Leave empty for no filter." | |
| // @Success 200 {object} dto.SuccessResponse[[]dto.UserResponse] | |
| // @Failure 400 {object} dto.ErrorResponse | |
| // @Failure 401 {object} dto.ErrorResponse | |
| // @Failure 403 {object} dto.ErrorResponse | |
| // @Router /api/v1/super-admin/users [get] | |
| func (c *userController) ListUsers(ctx *gin.Context) { | |
| limit, _ := strconv.Atoi(ctx.DefaultQuery("limit", "10")) | |
| page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1")) | |
| role := ctx.DefaultQuery("role", "") | |
| search := ctx.DefaultQuery("search", "") | |
| if limit < 1 { | |
| limit = 10 | |
| } else if limit > 50 { | |
| limit = 50 | |
| } | |
| if page < 1 { | |
| page = 1 | |
| } | |
| validRoles := map[string]bool{ | |
| "user": true, | |
| "admin": true, | |
| "super_admin": true, | |
| } | |
| if role != "" && !validRoles[role] { | |
| ResponseJSON(ctx, gin.H{}, []dto.UserResponse{}, http_error.BAD_REQUEST_ERROR) | |
| return | |
| } | |
| offset := (page - 1) * limit | |
| p := entity.Pagination{ | |
| Limit: limit, | |
| Offset: offset, | |
| Role: role, | |
| Search: search, | |
| } | |
| accounts, total, err := c.accountService.GetAllAccountsWithPagination(ctx.Request.Context(), p) | |
| if err != nil { | |
| ResponseJSON(ctx, gin.H{}, []dto.UserResponse{}, err) | |
| return | |
| } | |
| var users []dto.UserResponse | |
| for _, acc := range accounts { | |
| fullName := "" | |
| if acc.AccountDetail != nil && acc.AccountDetail.FullName != nil { | |
| fullName = *acc.AccountDetail.FullName | |
| } | |
| users = append(users, dto.UserResponse{ | |
| Id: acc.Id, | |
| Username: acc.Username, | |
| Email: acc.Email, | |
| FullName: fullName, | |
| Role: acc.Role, | |
| IsEmailVerified: acc.IsEmailVerified, | |
| IsDetailCompleted: acc.IsDetailCompleted, | |
| CreatedAt: acc.CreatedAt, | |
| }) | |
| } | |
| var totalPages int | |
| if total == 0 { | |
| totalPages = 1 | |
| } else { | |
| totalPages = int((total + int64(limit) - 1) / int64(limit)) | |
| } | |
| if page > totalPages { | |
| page = totalPages | |
| } | |
| meta := gin.H{ | |
| "totalItems": total, | |
| "totalPages": totalPages, | |
| "currentPage": page, | |
| "limit": limit, | |
| } | |
| ResponseJSON(ctx, meta, users, nil) | |
| } | |
| // CreateUser godoc | |
| // @Summary Create Single User | |
| // @Description Create a new user account by providing user details | |
| // @Tags Super Admin Users Management | |
| // @Accept json | |
| // @Produce json | |
| // @Security BearerAuth | |
| // @Param request body dto.CreateUserRequest true "Create User Request" | |
| // @Success 200 {object} dto.SuccessResponse[dto.UserResponse] | |
| // @Failure 400 {object} dto.ErrorResponse | |
| // @Failure 401 {object} dto.ErrorResponse | |
| // @Failure 403 {object} dto.ErrorResponse | |
| // @Router /api/v1/super-admin/users [post] | |
| func (c *userController) CreateUser(ctx *gin.Context) { | |
| req := RequestJSON[dto.CreateUserRequest](ctx) | |
| account, err := c.accountService.Create(ctx.Request.Context(), req.Name, req.Email, req.Username, req.Password, req.Role) | |
| if err != nil { | |
| ResponseJSON(ctx, req, dto.UserResponse{}, err) | |
| return | |
| } | |
| if req.Role != "" && req.Role != "user" { | |
| account.Role = req.Role | |
| account.IsEmailVerified = true | |
| account, _ = c.accountService.UpdateUserRole(ctx.Request.Context(), account) | |
| err = c.accountService.SetEmailVerified(ctx.Request.Context(), account.Id, true) | |
| if err != nil { | |
| ResponseJSON(ctx, req, dto.UserResponse{}, err) | |
| return | |
| } | |
| } | |
| res := dto.UserResponse{ | |
| Id: account.Id, | |
| Username: account.Username, | |
| Email: account.Email, | |
| Role: account.Role, | |
| IsEmailVerified: account.IsEmailVerified, | |
| IsDetailCompleted: account.IsDetailCompleted, | |
| CreatedAt: account.CreatedAt, | |
| } | |
| ResponseJSON(ctx, req, res, nil) | |
| } | |
| // BulkCreateUsers godoc | |
| // @Summary Bulk Create Users | |
| // @Description Create multiple user accounts at once | |
| // @Tags Super Admin Users Management | |
| // @Accept json | |
| // @Produce json | |
| // @Security BearerAuth | |
| // @Param requests body []dto.CreateUserRequest true "Bulk Create User Requests" | |
| // @Success 200 {object} dto.SuccessResponse[dto.CreateUserRequest] | |
| // @Failure 400 {object} dto.ErrorResponse | |
| // @Failure 401 {object} dto.ErrorResponse | |
| // @Failure 403 {object} dto.ErrorResponse | |
| // @Router /api/v1/super-admin/users/bulk [post] | |
| func (c *userController) BulkCreateUsers(ctx *gin.Context) { | |
| var requests []dto.CreateUserRequest | |
| if err := ctx.ShouldBindJSON(&requests); err != nil { | |
| ResponseJSON(ctx, requests, dto.CreateUserRequest{}, http_error.BAD_REQUEST_ERROR) | |
| ctx.Abort() | |
| return | |
| } | |
| response, err := c.accountService.BulkCreateAccounts(ctx.Request.Context(), requests) | |
| ResponseJSON(ctx, gin.H{"count": len(requests)}, response, err) | |
| } | |
| // GetUserById godoc | |
| // @Summary Edit User | |
| // @Description Update user information by ID | |
| // @Tags Super Admin Users Management | |
| // @Accept json | |
| // @Produce json | |
| // @Security BearerAuth | |
| // @Param id path string true "User ID" | |
| // @Param request body dto.UpdateUserRequest true "Update User Request" | |
| // @Success 200 {object} dto.SuccessResponse[dto.UserResponse] | |
| // @Failure 400 {object} dto.ErrorResponse | |
| // @Failure 401 {object} dto.ErrorResponse | |
| // @Failure 403 {object} dto.ErrorResponse | |
| // @Failure 404 {object} dto.ErrorResponse | |
| // @Router /api/v1/super-admin/users/{id} [put] | |
| func (c *userController) UpdateUser(ctx *gin.Context) { | |
| idParam := ctx.Param("id") | |
| userId, err := uuid.Parse(idParam) | |
| if err != nil { | |
| ResponseJSON(ctx, gin.H{"id": idParam}, dto.UserResponse{}, http_error.INVALID_TOKEN) | |
| return | |
| } | |
| req := RequestJSON[dto.UpdateUserRequest](ctx) | |
| account, err := c.accountService.GetById(ctx.Request.Context(), userId) | |
| if err != nil { | |
| ResponseJSON(ctx, gin.H{"id": userId}, dto.UserResponse{}, err) | |
| return | |
| } | |
| if account.Role == "super_admin" || account.Role == "admin" { | |
| account.IsEmailVerified = true | |
| err = c.accountService.SetEmailVerified(ctx.Request.Context(), account.Id, true) | |
| if err != nil { | |
| ResponseJSON(ctx, req, dto.UserResponse{}, err) | |
| return | |
| } | |
| } | |
| // Update fields if provided | |
| if req.Email != "" { | |
| account.Email = req.Email | |
| } | |
| if req.Username != "" { | |
| account.Username = req.Username | |
| } | |
| if req.Role != "" { | |
| account.Role = req.Role | |
| } | |
| if req.Password != "" { | |
| account.Password = req.Password | |
| } | |
| if req.Password != "" { | |
| account, err = c.accountService.Update(ctx.Request.Context(), account) | |
| } else { | |
| account, err = c.accountService.UpdateUserRole(ctx.Request.Context(), account) | |
| } | |
| if err != nil { | |
| ResponseJSON(ctx, req, dto.UserResponse{}, err) | |
| return | |
| } | |
| res := dto.UserResponse{ | |
| Id: account.Id, | |
| Username: account.Username, | |
| Email: account.Email, | |
| Role: account.Role, | |
| IsEmailVerified: account.IsEmailVerified, | |
| IsDetailCompleted: account.IsDetailCompleted, | |
| CreatedAt: account.CreatedAt, | |
| } | |
| ResponseJSON(ctx, req, res, nil) | |
| } | |
| // DeleteUser godoc | |
| // @Summary Delete User | |
| // @Description Delete a user account by ID | |
| // @Tags Super Admin Users Management | |
| // @Accept json | |
| // @Produce json | |
| // @Security BearerAuth | |
| // @Param id path string true "User ID" | |
| // @Success 200 {object} dto.SuccessResponse[any] | |
| // @Failure 400 {object} dto.ErrorResponse | |
| // @Failure 401 {object} dto.ErrorResponse | |
| // @Failure 403 {object} dto.ErrorResponse | |
| // @Failure 404 {object} dto.ErrorResponse | |
| // @Router /api/v1/super-admin/users/{id} [delete] | |
| func (c *userController) DeleteUser(ctx *gin.Context) { | |
| idParam := ctx.Param("id") | |
| userId, err := uuid.Parse(idParam) | |
| if err != nil { | |
| ResponseJSON[any](ctx, gin.H{"id": idParam}, nil, http_error.INVALID_TOKEN) | |
| return | |
| } | |
| _, err = c.accountService.GetById(ctx.Request.Context(), userId) | |
| if err != nil { | |
| ResponseJSON[any](ctx, gin.H{"id": userId}, nil, err) | |
| return | |
| } | |
| err = c.accountService.DeleteAccount(ctx.Request.Context(), userId) | |
| if err != nil { | |
| ResponseJSON[any](ctx, gin.H{"id": userId}, nil, err) | |
| return | |
| } | |
| ResponseJSON(ctx, gin.H{"id": userId}, gin.H{"message": "User deleted successfully"}, nil) | |
| } | |