Refactor User Management API and Update Documentation

- Changed API tags from "Admin-Users" to "Admin-Authorization" for better clarity in user management endpoints.
- Removed unused endpoints for retrieving users by company ID and role, streamlining the user management functionality.
- Updated user entity and forms to reflect new example values for improved clarity in API documentation.
- Enhanced pagination handling in user listing responses, ensuring consistent metadata structure.
- Updated API documentation to reflect changes in endpoint structure and response formats, improving clarity for API consumers.
This commit is contained in:
n.nakhostin
2025-09-06 14:00:22 +03:30
parent eb69a842f0
commit 38844939b5
11 changed files with 567 additions and 1734 deletions
+18 -217
View File
@@ -1,7 +1,6 @@
package user
import (
"strconv"
"tm/pkg/authorization"
"tm/pkg/logger"
"tm/pkg/response"
@@ -117,7 +116,7 @@ func (h *Handler) ResetPassword(c echo.Context) error {
// GetProfile gets current user profile
// @Summary Get authenticated user profile
// @Description Retrieve complete profile information for the currently authenticated user including personal details, role information, permissions, and account status. This endpoint requires valid authentication token.
// @Tags Admin-Users
// @Tags Admin-Authorization
// @Accept json
// @Produce json
// @Security BearerAuth
@@ -133,7 +132,7 @@ func (h *Handler) GetProfile(c echo.Context) error {
return response.Unauthorized(c, "User not authenticated")
}
user, err := h.service.GetProfile(c.Request().Context(), userID)
user, err := h.service.GetUserByID(c.Request().Context(), userID)
if err != nil {
return response.NotFound(c, "User not found")
}
@@ -144,7 +143,7 @@ func (h *Handler) GetProfile(c echo.Context) error {
// UpdateProfile updates current user profile
// @Summary Update authenticated user profile
// @Description Update profile information for the currently authenticated user including personal details, contact information, and preferences. Only the authenticated user can update their own profile.
// @Tags Admin-Users
// @Tags Admin-Authorization
// @Accept json
// @Produce json
// @Security BearerAuth
@@ -168,7 +167,7 @@ func (h *Handler) UpdateProfile(c echo.Context) error {
return response.BadRequest(c, "Invalid request format", "")
}
user, err := h.service.UpdateUser(c.Request().Context(), userID, form, &userID)
user, err := h.service.Update(c.Request().Context(), userID, form)
if err != nil {
return response.BadRequest(c, err.Error(), "")
}
@@ -179,7 +178,7 @@ func (h *Handler) UpdateProfile(c echo.Context) error {
// ChangePassword changes current user password
// @Summary Change user password
// @Description Change password for the currently authenticated user. Requires current password verification and enforces password policy. This operation invalidates all existing sessions and requires re-authentication.
// @Tags Admin-Users
// @Tags Admin-Authorization
// @Accept json
// @Produce json
// @Security BearerAuth
@@ -261,14 +260,8 @@ func (h *Handler) Logout(c echo.Context) error {
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Router /admin/v1/users [post]
func (h *Handler) CreateUser(c echo.Context) error {
// Get current user ID from JWT token
currentUserID, err := GetUserIDFromContext(c)
form, err := response.Parse[CreateUserForm](c)
if err != nil {
return response.Unauthorized(c, "User not authenticated")
}
var form CreateUserForm
if err := c.Bind(&form); err != nil {
return response.BadRequest(c, "Invalid request format", "")
}
@@ -278,7 +271,7 @@ func (h *Handler) CreateUser(c echo.Context) error {
}
// Call service
user, err := h.service.CreateUser(c.Request().Context(), &form, &currentUserID)
user, err := h.service.Register(c.Request().Context(), form)
if err != nil {
return response.BadRequest(c, err.Error(), "")
}
@@ -296,7 +289,6 @@ func (h *Handler) CreateUser(c echo.Context) error {
// @Param search query string false "Search term"
// @Param status query string false "User status filter"
// @Param role query string false "User role filter"
// @Param company_id query string false "Company ID filter"
// @Param limit query int false "Limit results"
// @Param offset query int false "Offset results"
// @Param sort_by query string false "Sort field"
@@ -308,8 +300,8 @@ func (h *Handler) CreateUser(c echo.Context) error {
// @Failure 500 {object} response.APIResponse
// @Router /admin/v1/users [get]
func (h *Handler) ListUsers(c echo.Context) error {
var form ListUsersForm
if err := c.Bind(&form); err != nil {
form, err := response.Parse[SearchUsersForm](c)
if err != nil {
return response.BadRequest(c, "Invalid request format", "")
}
@@ -319,7 +311,7 @@ func (h *Handler) ListUsers(c echo.Context) error {
}
// Call service
users, err := h.service.ListUsers(c.Request().Context(), &form)
users, err := h.service.Search(c.Request().Context(), form, response.NewPagination(c))
if err != nil {
return response.InternalServerError(c, "Failed to list users")
}
@@ -370,16 +362,10 @@ func (h *Handler) GetUserByID(c echo.Context) error {
// @Failure 500 {object} response.APIResponse
// @Router /admin/v1/users/{id} [put]
func (h *Handler) UpdateUser(c echo.Context) error {
// Extract user ID from JWT token context
currentUserID, err := GetUserIDFromContext(c)
if err != nil {
return response.Unauthorized(c, "User not authenticated")
}
idStr := c.Param("id")
var form UpdateUserForm
if err := c.Bind(&form); err != nil {
form, err := response.Parse[UpdateUserForm](c)
if err != nil {
return response.BadRequest(c, "Invalid request format", "")
}
@@ -389,7 +375,7 @@ func (h *Handler) UpdateUser(c echo.Context) error {
}
// Call service
user, err := h.service.UpdateUser(c.Request().Context(), idStr, &form, &currentUserID)
user, err := h.service.Update(c.Request().Context(), idStr, form)
if err != nil {
return response.BadRequest(c, err.Error(), "")
}
@@ -413,15 +399,9 @@ func (h *Handler) UpdateUser(c echo.Context) error {
// @Failure 500 {object} response.APIResponse
// @Router /admin/v1/users/{id} [delete]
func (h *Handler) DeleteUser(c echo.Context) error {
// Extract user ID from JWT token context
currentUserID, err := GetUserIDFromContext(c)
if err != nil {
return response.Unauthorized(c, "User not authenticated")
}
id := c.Param("id")
idStr := c.Param("id")
err = h.service.DeleteUser(c.Request().Context(), idStr, &currentUserID)
err := h.service.Delete(c.Request().Context(), id)
if err != nil {
return response.BadRequest(c, err.Error(), "")
}
@@ -448,15 +428,10 @@ func (h *Handler) DeleteUser(c echo.Context) error {
// @Failure 500 {object} response.APIResponse
// @Router /admin/v1/users/{id}/status [put]
func (h *Handler) UpdateUserStatus(c echo.Context) error {
currentUserID, err := GetUserIDFromContext(c)
if err != nil {
return response.Unauthorized(c, "User not authenticated")
}
idStr := c.Param("id")
var form UpdateUserStatusForm
if err := c.Bind(&form); err != nil {
form, err := response.Parse[UpdateUserStatusForm](c)
if err != nil {
return response.BadRequest(c, "Invalid request format", "")
}
@@ -466,7 +441,7 @@ func (h *Handler) UpdateUserStatus(c echo.Context) error {
}
// Call service
err = h.service.UpdateUserStatus(c.Request().Context(), idStr, &form, &currentUserID)
err = h.service.UpdateStatus(c.Request().Context(), idStr, form)
if err != nil {
return response.BadRequest(c, err.Error(), "")
}
@@ -475,177 +450,3 @@ func (h *Handler) UpdateUserStatus(c echo.Context) error {
"message": "User status updated successfully",
}, "User status updated successfully")
}
// UpdateUserRole updates user role (admin only)
// @Summary Update user role
// @Description Update user role (admin only)
// @Tags Admin-Users
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path string true "User ID"
// @Param role body UpdateUserRoleForm true "Role update data"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 403 {object} response.APIResponse
// @Failure 404 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /admin/v1/users/{id}/role [put]
func (h *Handler) UpdateUserRole(c echo.Context) error {
// Extract user ID from JWT token context
currentUserID, err := GetUserIDFromContext(c)
if err != nil {
return response.Unauthorized(c, "User not authenticated")
}
idStr := c.Param("id")
var form UpdateUserRoleForm
if err := c.Bind(&form); err != nil {
return response.BadRequest(c, "Invalid request format", "")
}
// Validate form
if _, err := govalidator.ValidateStruct(form); err != nil {
return response.ValidationError(c, err.Error(), "")
}
// Call service
err = h.service.UpdateUserRole(c.Request().Context(), idStr, &form, &currentUserID)
if err != nil {
return response.BadRequest(c, err.Error(), "")
}
return response.Success(c, map[string]interface{}{
"message": "User role updated successfully",
}, "User role updated successfully")
}
// GetUsersByCompanyID gets users by company ID (admin only)
// @Summary Get users by company ID
// @Description Get users belonging to a specific company (admin only)
// @Tags Admin-Users
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param company_id path string true "Company ID"
// @Param limit query int false "Limit results"
// @Param offset query int false "Offset results"
// @Success 200 {object} response.APIResponse{data=map[string]interface{}} "Users with pagination metadata"
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 403 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /admin/v1/users/company/{company_id} [get]
func (h *Handler) GetUsersByCompanyID(c echo.Context) error {
companyIDStr := c.Param("company_id")
// Get query parameters
limitStr := c.QueryParam("limit")
if limitStr == "" {
limitStr = "20"
}
offsetStr := c.QueryParam("offset")
if offsetStr == "" {
offsetStr = "0"
}
limit, err := strconv.Atoi(limitStr)
if err != nil {
return response.BadRequest(c, "Invalid limit parameter", "")
}
offset, err := strconv.Atoi(offsetStr)
if err != nil {
return response.BadRequest(c, "Invalid offset parameter", "")
}
// Call service
users, total, err := h.service.GetUsersByCompanyID(c.Request().Context(), companyIDStr, limit, offset)
if err != nil {
return response.InternalServerError(c, "Failed to get users by company")
}
// Convert to responses
var userResponses []*UserResponse
for _, user := range users {
userResponses = append(userResponses, user.ToResponse())
}
return response.SuccessWithMeta(c, map[string]interface{}{
"users": userResponses,
}, &response.Meta{
Total: int(total),
Limit: limit,
Offset: offset,
}, "Users retrieved successfully")
}
// GetUsersByRole gets users by role (admin only)
// @Summary Get users by role
// @Description Get users with a specific role (admin only)
// @Tags Admin-Users
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param role path string true "User role"
// @Param limit query int false "Limit results"
// @Param offset query int false "Offset results"
// @Success 200 {object} response.APIResponse{data=map[string]interface{}} "Users with pagination metadata"
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 403 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /admin/v1/users/role/{role} [get]
func (h *Handler) GetUsersByRole(c echo.Context) error {
roleStr := c.Param("role")
role := UserRole(roleStr)
// Validate role
if !h.validator.IsValidRole(role) {
return response.BadRequest(c, "Invalid role", "")
}
// Get query parameters
limitStr := c.QueryParam("limit")
if limitStr == "" {
limitStr = "20"
}
offsetStr := c.QueryParam("offset")
if offsetStr == "" {
offsetStr = "0"
}
limit, err := strconv.Atoi(limitStr)
if err != nil {
return response.BadRequest(c, "Invalid limit parameter", "")
}
offset, err := strconv.Atoi(offsetStr)
if err != nil {
return response.BadRequest(c, "Invalid offset parameter", "")
}
// Call service
users, err := h.service.GetUsersByRole(c.Request().Context(), role, limit, offset)
if err != nil {
return response.InternalServerError(c, "Failed to get users by role")
}
// Convert to responses
var userResponses []*UserResponse
for _, user := range users {
userResponses = append(userResponses, user.ToResponse())
}
return response.SuccessWithMeta(c, map[string]interface{}{
"users": userResponses,
"role": role,
}, &response.Meta{
Limit: limit,
Offset: offset,
}, "Users retrieved successfully")
}
// AuthMiddleware and AdminMiddleware are now implemented in middleware.go