package auth import ( "encoding/json" "errors" "fmt" "net/http" "strings" "api_yal/internal/logger" "api_yal/internal/middleware" "github.com/go-playground/validator/v10" "go.uber.org/zap" ) // AuthHandler обработчик для аутентификации type AuthHandler struct { authService AuthService validator *validator.Validate } // NewAuthHandler создает новый экземпляр AuthHandler func NewAuthHandler(authService *AuthService) *AuthHandler { return &AuthHandler{ authService: *authService, validator: validator.New(), } } // Register регистрация аккаунта пользователя func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) { l := logger.Get() l.Info("Начало обработки запроса регистрации") var req RegisterRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid request body", http.StatusBadRequest) return } if err := h.validator.Struct(req); err != nil { var invalidValidationError *validator.InvalidValidationError if errors.As(err, &invalidValidationError) { http.Error(w, "Invalid request", http.StatusBadRequest) return } var errs []string for _, err := range err.(validator.ValidationErrors) { errs = append(errs, fmt.Sprintf("field %s is invalid: %s", err.Field(), err.Tag())) } w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]interface{}{ "error": "Validation failed", "fields": errs, }) return } response, err := h.authService.Register(req) if err != nil { l.Error("Ошибка регистрации: %v", zap.Error(err)) status := http.StatusInternalServerError message := "Registration failed" if errors.Is(err, ErrUserAlreadyExists) { status = http.StatusConflict message = "User with this email already exists" } http.Error(w, message, status) return } l.Info("Завершение обработки запроса регистрации") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(response) } // Login вход пользователя func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) { l := logger.Get() l.Info("Начало обработки запроса входа") var req LoginRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid request body", http.StatusBadRequest) return } if err := h.validator.Struct(req); err != nil { var invalidValidationError *validator.InvalidValidationError if errors.As(err, &invalidValidationError) { http.Error(w, "Invalid request", http.StatusBadRequest) return } var errs []string for _, err := range err.(validator.ValidationErrors) { errs = append(errs, fmt.Sprintf("field %s is invalid: %s", err.Field(), err.Tag())) } w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]interface{}{ "error": "Validation failed", "fields": errs, }) return } response, err := h.authService.Login(req) if err != nil { l.Error("Ошибка входа: %v", zap.Error(err)) status := http.StatusUnauthorized message := "Login failed" if errors.Is(err, ErrUserNotFound) { message = "User not found" } else if errors.Is(err, ErrInvalidPassword) { message = "Invalid password" } http.Error(w, message, status) return } l.Info("Завершение обработки запроса входа") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) } // RefreshToken обновление токена func (h *AuthHandler) RefreshToken(w http.ResponseWriter, r *http.Request) { l := logger.Get() l.Info("Начало обработки запроса обновления токена") // Получаем токен из заголовка Authorization authHeader := r.Header.Get("Authorization") if authHeader == "" { http.Error(w, "Authorization header required", http.StatusUnauthorized) return } // Ожидаем формат "Bearer " parts := strings.Split(authHeader, " ") if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" { http.Error(w, "Invalid authorization header format", http.StatusUnauthorized) return } response, err := h.authService.RefreshToken(parts[1]) if err != nil { l.Error("Ошибка обновления токена: %v", zap.Error(err)) http.Error(w, "Token refresh failed", http.StatusUnauthorized) return } l.Info("Завершение обработки запроса обновления токена") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) } // Logout выход пользователя func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) { l := logger.Get() l.Info("Начало обработки запроса выхода") // Получаем ID пользователя из контекста (устанавливается middleware) userID, ok := r.Context().Value(middleware.UserIDKey).(uint) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } if err := h.authService.Logout(userID); err != nil { l.Error("Ошибка выхода: %v", zap.Error(err)) http.Error(w, "Logout failed", http.StatusInternalServerError) return } l.Info("Завершение обработки запроса выхода") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{ "message": "Successfully logged out", }) } // GetProfile получение профиля пользователя func (h *AuthHandler) GetProfile(w http.ResponseWriter, r *http.Request) { l := logger.Get() l.Debug("Получение профиля пользователя") // Получаем ID пользователя из контекста userID, ok := r.Context().Value(middleware.UserIDKey).(uint) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } // TODO: Реализовать получение профиля через сервис // response, err := h.authService.GetProfile(userID) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]interface{}{ "user_id": userID, "message": "Profile endpoint - to be implemented", }) } // UpdateProfile обновление профиля пользователя func (h *AuthHandler) UpdateProfile(w http.ResponseWriter, r *http.Request) { l := logger.Get() l.Debug("Обновление профиля пользователя") // Получаем ID пользователя из контекста userID, ok := r.Context().Value(middleware.UserIDKey).(uint) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } // TODO: Реализовать обновление профиля w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]interface{}{ "user_id": userID, "message": "Update profile endpoint - to be implemented", }) } // ChangePassword смена пароля func (h *AuthHandler) ChangePassword(w http.ResponseWriter, r *http.Request) { l := logger.Get() l.Debug("Смена пароля пользователя") // Получаем ID пользователя из контекста userID, ok := r.Context().Value(middleware.UserIDKey).(uint) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } // TODO: Реализовать смену пароля w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]interface{}{ "user_id": userID, "message": "Change password endpoint - to be implemented", }) }