/
Arsinenko
/
CompClubAPI_Go
Обзор
Документация
Войти
/
Arsinenko
/
CompClubAPI_Go
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
internal/handlers/user_handler.go
296 строк
11 KB
Arsinenko
Update
08 ноя 2025, 13:12
08 ноя 2025, 13:12
2f36b0f
Код
Авторство
О чём код?
package handlers import ( "CompClubAPI/internal/middleware" "CompClubAPI/internal/services" "net/http" "strconv" "strings" "github.com/gin-gonic/gin" ) // RegisterUserHandler godoc // @Summary Register a new user // @Description Creates a new user account. Only admins can register other admins. // @Tags users // @Accept json // @Produce json // @Param request body services.CreateUserRequest true "User registration data" // @Success 200 {object} map[string]interface{} "User registered successfully" // @Failure 400 {object} map[string]string "Invalid request body, invalid role, or invalid model" // @Failure 401 {object} map[string]string "Missing or invalid Authorization header (when creating admin)" // @Failure 403 {object} map[string]string "Only admins can create admin users" // @Failure 409 {object} map[string]string "User already exists" // @Failure 500 {object} map[string]string "Internal server error" // @Router /users/register [post] func RegisterUserHandler(s services.UserService, jwtMiddleware middleware.JwtMiddleware) gin.HandlerFunc { return func(c *gin.Context) { var req services.CreateUserRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // Только админ может создать пользователя с ролью admin if strings.EqualFold(req.Role, "admin") { authHeader := c.GetHeader("Authorization") parts := strings.Fields(authHeader) if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") { c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header format must be Bearer {token}"}) return } token, err := jwtMiddleware.VerifyToken(parts[1]) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token: " + err.Error()}) return } claims, err := jwtMiddleware.GetClaims(token) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token claims: " + err.Error()}) return } role, _ := claims["role"].(string) if role != "admin" { c.JSON(http.StatusForbidden, gin.H{"error": "Admin access required to create admin user"}) return } } user, err := s.CreateUser(req) if err != nil { switch err.Error() { case "user already exists": c.JSON(http.StatusConflict, gin.H{"error": err.Error()}) return case "invalid role", "invalid model": c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return default: c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } } c.JSON(http.StatusOK, gin.H{"user": user}) } } // LoginUserHandler godoc // @Summary Authenticate user // @Description Logs in a user and returns a JWT token // @Tags users // @Accept json // @Produce json // @Param request body services.LoginUserRequest true "Login credentials" // @Success 200 {object} map[string]string "JWT token" // @Failure 400 {object} map[string]string "Invalid credentials or user not found" // @Failure 500 {object} map[string]string "Internal server error" // @Router /users/auth [post] func LoginUserHandler(s services.UserService, jwtMiddleware middleware.JwtMiddleware) gin.HandlerFunc { return func(c *gin.Context) { var req services.LoginUserRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return // <-- добавлен return } user, err := s.LoginUser(req) if err != nil { if err.Error() == "incorrect password" || err.Error() == "user not found" { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } token, err := jwtMiddleware.GenerateToken(user.Login, user.Role) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"token": token}) } } // GetUsersHandler godoc // @Summary Get all users (admin only) // @Description Retrieves a list of all registered users. Requires admin role. // @Tags users // @Produce json // @Param page query int false "Page number for pagination" // @Param size query int false "Number of items per page" // @Success 200 {object} map[string]interface{} "List of users" // @Failure 500 {object} map[string]string "Internal server error (if any)" // @Security ApiKeyAuth // @Router /users/ [get] func GetUsersHandler(s services.UserService) gin.HandlerFunc { return func(c *gin.Context) { page, err := strconv.Atoi(c.DefaultQuery("page", "1")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } users, _ := s.GetAllUsers() sizeStr := c.DefaultQuery("size", "0") if sizeStr == "" || sizeStr == "0" { c.JSON(http.StatusOK, gin.H{"users": users}) return } size, err := strconv.Atoi(sizeStr) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } start := (size - 1) * page end := start + size result := users[start:end] c.JSON(http.StatusOK, gin.H{"users": result}) } } // GetUsersBySubstringHandler godoc // @Summary Get users by substring (admin only) // @Description Retrieves a list of users whose login contains the given substring. Requires admin role. // @Tags users // @Produce json // @Param substr path string true "Substring to search for in user logins" // @Success 200 {object} map[string]interface{} "List of users matching the substring" // @Failure 500 {object} map[string]string "Internal server error" // @Security ApiKeyAuth // @Router /users/search/{substr} [get] func GetUsersBySubstringHandler(s services.UserService) gin.HandlerFunc { return func(c *gin.Context) { substring := c.Param("substr") users, _ := s.GetAllUsers() var result []services.UserResponse for _, user := range users { if strings.Contains(user.Login, substring) { result = append(result, user) } } c.JSON(http.StatusOK, gin.H{"users": result}) } } // GetUserHandler godoc // @Summary Get user by login // @Description Retrieves user details by login. Accessible to the user themselves or admins. // @Tags users // @Produce json // @Param login path string true "User login" // @Success 200 {object} map[string]interface{} "User details" // @Failure 404 {object} map[string]string "User not found" // @Failure 500 {object} map[string]string "Internal server error" // @Security ApiKeyAuth // @Router /users/{login} [get] func GetUserHandler(s services.UserService) gin.HandlerFunc { return func(c *gin.Context) { login := c.Param("login") user, err := s.GetUser(login) if err != nil { if err.Error() == "user not found" { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"user": user}) } } // DeleteUserHandler godoc // @Summary Delete a user (admin only) // @Description Removes a user from the system by login. Requires admin role. // @Tags users // @Produce json // @Param login path string true "User login to delete" // @Success 200 {object} map[string]string "User deleted successfully" // @Failure 404 {object} map[string]string "User not found" // @Failure 500 {object} map[string]string "Internal server error" // @Security ApiKeyAuth // @Router /users/{login} [delete] func DeleteUserHandler(s services.UserService) gin.HandlerFunc { return func(c *gin.Context) { login := c.Param("login") err := s.DeleteUser(login) if err != nil { if err.Error() == "user not found" { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "user deleted"}) } } // UpdateUserHandler godoc // @Summary Update user details (admin only) // @Description Updates user information (e.g., role, password). Requires admin role. // @Tags users // @Accept json // @Produce json // @Param login path string true "User login to update" // @Param request body services.UpdateUserRequest true "Updated user data" // @Success 200 {object} map[string]interface{} "Updated user" // @Failure 400 {object} map[string]string "Invalid request body" // @Failure 404 {object} map[string]string "User not found" // @Failure 500 {object} map[string]string "Internal server error" // @Security ApiKeyAuth // @Router /users/{login} [put] func UpdateUserHandler(s services.UserService) gin.HandlerFunc { return func(c *gin.Context) { var req services.UpdateUserRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return // <-- добавлен return } login := c.Param("login") user, err := s.UpdateUser(login, req) if err != nil { if err.Error() == "user not found" { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return } if err.Error() == "invalid property" { c.JSON(http.StatusBadRequest, gin.H{"error": "Available properties: balance, password"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"user": user}) } } // InitUserRoutes initializes user-related routes // - /register and /auth are public // - /{login} (GET) requires authentication // - /, /{login} (PUT/DELETE) require admin role func InitUserRoutes(r *gin.RouterGroup, s services.UserService) { jwtMiddleware := middleware.NewJwtMiddleware() // Публичные маршруты (не требуют авторизации) r.POST("/register", RegisterUserHandler(s, jwtMiddleware)) r.POST("/auth", LoginUserHandler(s, jwtMiddleware)) // Защищенные маршруты (требуют авторизации) userRouters := r.Group("/") userRouters.Use(middleware.AuthMiddleware(jwtMiddleware)) { userRouters.GET("/:login", GetUserHandler(s)) } // Админские маршруты (требуют роль admin) adminRoutes := r.Group("/") adminRoutes.Use(middleware.AdminMiddleware(jwtMiddleware)) { adminRoutes.GET("/", GetUsersHandler(s)) adminRoutes.DELETE("/:login", DeleteUserHandler(s)) adminRoutes.PUT("/:login", UpdateUserHandler(s)) adminRoutes.GET("/search/:substr", GetUsersBySubstringHandler(s)) } }