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:
+18
-217
@@ -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, ¤tUserID)
|
||||
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, ¤tUserID)
|
||||
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, ¤tUserID)
|
||||
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, ¤tUserID)
|
||||
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, ¤tUserID)
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user