mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
336 lines
8.7 KiB
Go
336 lines
8.7 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"bugulma/backend/internal/domain"
|
|
"bugulma/backend/internal/service"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type UserHandler struct {
|
|
userService *service.UserService
|
|
}
|
|
|
|
func NewUserHandler(userService *service.UserService) *UserHandler {
|
|
return &UserHandler{
|
|
userService: userService,
|
|
}
|
|
}
|
|
|
|
// ListUsers lists users with filters and pagination (admin only)
|
|
// @Summary List users
|
|
// @Tags admin
|
|
// @Produce json
|
|
// @Param role query string false "Filter by role"
|
|
// @Param isActive query bool false "Filter by active status"
|
|
// @Param search query string false "Search in email and name"
|
|
// @Param limit query int false "Limit" default(25)
|
|
// @Param offset query int false "Offset" default(0)
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/admin/users [get]
|
|
func (h *UserHandler) ListUsers(c *gin.Context) {
|
|
filters := domain.UserListFilters{}
|
|
|
|
// Parse role filter
|
|
if roleStr := c.Query("role"); roleStr != "" {
|
|
role := domain.UserRole(roleStr)
|
|
filters.Role = &role
|
|
}
|
|
|
|
// Parse isActive filter
|
|
if isActiveStr := c.Query("isActive"); isActiveStr != "" {
|
|
isActive := isActiveStr == "true"
|
|
filters.IsActive = &isActive
|
|
}
|
|
|
|
// Parse search
|
|
filters.Search = c.Query("search")
|
|
|
|
// Parse pagination
|
|
limit := 25
|
|
offset := 0
|
|
if limitStr := c.Query("limit"); limitStr != "" {
|
|
if parsed, err := strconv.Atoi(limitStr); err == nil {
|
|
limit = parsed
|
|
}
|
|
}
|
|
if offsetStr := c.Query("offset"); offsetStr != "" {
|
|
if parsed, err := strconv.Atoi(offsetStr); err == nil {
|
|
offset = parsed
|
|
}
|
|
}
|
|
|
|
pagination := domain.PaginationParams{
|
|
Limit: limit,
|
|
Offset: offset,
|
|
}
|
|
|
|
result, err := h.userService.ListUsers(c.Request.Context(), filters, pagination)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"users": result.Items,
|
|
"total": result.Total,
|
|
"limit": limit,
|
|
"offset": offset,
|
|
})
|
|
}
|
|
|
|
// GetUser gets a user by ID (admin only)
|
|
// @Summary Get user
|
|
// @Tags admin
|
|
// @Produce json
|
|
// @Param id path string true "User ID"
|
|
// @Success 200 {object} domain.User
|
|
// @Router /api/v1/admin/users/:id [get]
|
|
func (h *UserHandler) GetUser(c *gin.Context) {
|
|
userID := c.Param("id")
|
|
|
|
user, err := h.userService.GetUser(c.Request.Context(), userID)
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
|
|
return
|
|
}
|
|
|
|
// Don't return password
|
|
user.Password = ""
|
|
|
|
c.JSON(http.StatusOK, user)
|
|
}
|
|
|
|
// CreateUser creates a new user (admin only)
|
|
// @Summary Create user
|
|
// @Tags admin
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body CreateUserRequest true "User request"
|
|
// @Success 201 {object} domain.User
|
|
// @Router /api/v1/admin/users [post]
|
|
func (h *UserHandler) CreateUser(c *gin.Context) {
|
|
var req CreateUserRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
createReq := service.CreateUserRequest{
|
|
Email: req.Email,
|
|
Name: req.Name,
|
|
Password: req.Password,
|
|
Role: domain.UserRole(req.Role),
|
|
Permissions: req.Permissions,
|
|
}
|
|
|
|
user, err := h.userService.CreateUser(c.Request.Context(), createReq)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
// Don't return password
|
|
user.Password = ""
|
|
|
|
c.JSON(http.StatusCreated, user)
|
|
}
|
|
|
|
type CreateUserRequest struct {
|
|
Email string `json:"email" binding:"required,email"`
|
|
Name string `json:"name" binding:"required"`
|
|
Password string `json:"password" binding:"required,min=8"`
|
|
Role string `json:"role" binding:"required"`
|
|
Permissions []string `json:"permissions"`
|
|
}
|
|
|
|
// UpdateUser updates a user (admin only)
|
|
// @Summary Update user
|
|
// @Tags admin
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "User ID"
|
|
// @Param request body UpdateUserRequest true "Update request"
|
|
// @Success 200 {object} domain.User
|
|
// @Router /api/v1/admin/users/:id [put]
|
|
func (h *UserHandler) UpdateUser(c *gin.Context) {
|
|
userID := c.Param("id")
|
|
|
|
var req UpdateUserRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
updateReq := service.UpdateUserRequest{}
|
|
if req.Name != nil {
|
|
updateReq.Name = req.Name
|
|
}
|
|
if req.Email != nil {
|
|
updateReq.Email = req.Email
|
|
}
|
|
if req.Role != nil {
|
|
role := domain.UserRole(*req.Role)
|
|
updateReq.Role = &role
|
|
}
|
|
if req.Permissions != nil {
|
|
updateReq.Permissions = req.Permissions
|
|
}
|
|
if req.IsActive != nil {
|
|
updateReq.IsActive = req.IsActive
|
|
}
|
|
|
|
user, err := h.userService.UpdateUser(c.Request.Context(), userID, updateReq)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
// Don't return password
|
|
user.Password = ""
|
|
|
|
c.JSON(http.StatusOK, user)
|
|
}
|
|
|
|
type UpdateUserRequest struct {
|
|
Name *string `json:"name"`
|
|
Email *string `json:"email"`
|
|
Role *string `json:"role"`
|
|
Permissions *[]string `json:"permissions"`
|
|
IsActive *bool `json:"isActive"`
|
|
}
|
|
|
|
// UpdateRole updates a user's role (admin only)
|
|
// @Summary Update user role
|
|
// @Tags admin
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "User ID"
|
|
// @Param request body UpdateRoleRequest true "Role request"
|
|
// @Success 200 {object} map[string]string
|
|
// @Router /api/v1/admin/users/:id/role [patch]
|
|
func (h *UserHandler) UpdateRole(c *gin.Context) {
|
|
userID := c.Param("id")
|
|
|
|
var req UpdateRoleRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
if err := h.userService.UpdateRole(c.Request.Context(), userID, domain.UserRole(req.Role)); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Role updated"})
|
|
}
|
|
|
|
type UpdateRoleRequest struct {
|
|
Role string `json:"role" binding:"required"`
|
|
}
|
|
|
|
// UpdatePermissions updates a user's permissions (admin only)
|
|
// @Summary Update user permissions
|
|
// @Tags admin
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "User ID"
|
|
// @Param request body UpdatePermissionsRequest true "Permissions request"
|
|
// @Success 200 {object} map[string]string
|
|
// @Router /api/v1/admin/users/:id/permissions [patch]
|
|
func (h *UserHandler) UpdatePermissions(c *gin.Context) {
|
|
userID := c.Param("id")
|
|
|
|
var req UpdatePermissionsRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
if err := h.userService.UpdatePermissions(c.Request.Context(), userID, req.Permissions); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Permissions updated"})
|
|
}
|
|
|
|
type UpdatePermissionsRequest struct {
|
|
Permissions []string `json:"permissions" binding:"required"`
|
|
}
|
|
|
|
// DeactivateUser deactivates a user (admin only)
|
|
// @Summary Deactivate user
|
|
// @Tags admin
|
|
// @Success 200 {object} map[string]string
|
|
// @Router /api/v1/admin/users/:id [delete]
|
|
func (h *UserHandler) DeactivateUser(c *gin.Context) {
|
|
userID := c.Param("id")
|
|
|
|
if err := h.userService.DeactivateUser(c.Request.Context(), userID); err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "User deactivated"})
|
|
}
|
|
|
|
// GetUserActivity gets activity log for a user (admin only)
|
|
// @Summary Get user activity
|
|
// @Tags admin
|
|
// @Produce json
|
|
// @Param id path string true "User ID"
|
|
// @Param limit query int false "Limit" default(50)
|
|
// @Param offset query int false "Offset" default(0)
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/admin/users/:id/activity [get]
|
|
func (h *UserHandler) GetUserActivity(c *gin.Context) {
|
|
userID := c.Param("id")
|
|
|
|
limit := 50
|
|
offset := 0
|
|
if limitStr := c.Query("limit"); limitStr != "" {
|
|
if parsed, err := strconv.Atoi(limitStr); err == nil {
|
|
limit = parsed
|
|
}
|
|
}
|
|
if offsetStr := c.Query("offset"); offsetStr != "" {
|
|
if parsed, err := strconv.Atoi(offsetStr); err == nil {
|
|
offset = parsed
|
|
}
|
|
}
|
|
|
|
activities, total, err := h.userService.GetUserActivity(c.Request.Context(), userID, limit, offset)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"activities": activities,
|
|
"total": total,
|
|
"limit": limit,
|
|
"offset": offset,
|
|
})
|
|
}
|
|
|
|
// GetUserStats gets user statistics (admin only)
|
|
// @Summary Get user statistics
|
|
// @Tags admin
|
|
// @Produce json
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/admin/users/stats [get]
|
|
func (h *UserHandler) GetUserStats(c *gin.Context) {
|
|
stats, err := h.userService.GetUserStats(c.Request.Context())
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, stats)
|
|
}
|