package account import ( "encoding/json" "errors" "fmt" "net/http" "strconv" "api_yal/internal/logger" "api_yal/internal/middleware" "github.com/go-playground/validator/v10" "go.uber.org/zap" ) // AccountHandler обработчик для операций с аккаунтами type AccountHandler struct { service AccountService validator *validator.Validate } // NewHandler создает новый экземпляр Handler func NewHandler(service AccountService) *AccountHandler { return &AccountHandler{ service: service, validator: validator.New(), } } // GetAccountByID получение аккаунта по ID func (h *AccountHandler) GetAccountByID(w http.ResponseWriter, r *http.Request) { l := logger.Get() // Получаем ID из контекста (для своего профиля) userID, ok := r.Context().Value(middleware.UserIDKey).(uint) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } // Проверяем, что пользователь запрашивает свой профиль // В реальном приложении админы могут просматривать чужие профили account, err := h.service.GetAccountByID(userID) if err != nil { l.Error("Ошибка получения аккаунта", zap.Error(err)) if errors.Is(err, ErrAccountNotFound) { http.Error(w, "Account not found", http.StatusNotFound) return } http.Error(w, "Failed to get account", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(account) } // GetAccountProfile получение профиля пользователя func (h *AccountHandler) GetAccountProfile(w http.ResponseWriter, r *http.Request) { l := logger.Get() userID, ok := r.Context().Value(middleware.UserIDKey).(uint) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } profile, err := h.service.GetAccountProfile(userID) if err != nil { l.Error("Ошибка получения профиля", zap.Error(err)) if errors.Is(err, ErrAccountNotFound) { http.Error(w, "Account not found", http.StatusNotFound) return } http.Error(w, "Failed to get profile", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(profile) } // UpdateAccount обновление аккаунта func (h *AccountHandler) UpdateAccount(w http.ResponseWriter, r *http.Request) { l := logger.Get() userID, ok := r.Context().Value(middleware.UserIDKey).(uint) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } var req UpdateAccountRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid request body", http.StatusBadRequest) return } // Валидация не требуется для всех полей, так как они опциональны account, err := h.service.UpdateAccount(userID, req) if err != nil { l.Error("Ошибка обновления аккаунта", zap.Error(err)) if errors.Is(err, ErrAccountNotFound) { http.Error(w, "Account not found", http.StatusNotFound) return } http.Error(w, "Failed to update account", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(account) } // ChangePassword смена пароля func (h *AccountHandler) ChangePassword(w http.ResponseWriter, r *http.Request) { l := logger.Get() userID, ok := r.Context().Value(middleware.UserIDKey).(uint) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } var req ChangePasswordRequest 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 { h.handleValidationError(w, err) return } if err := h.service.ChangePassword(userID, req); err != nil { l.Error("Ошибка смены пароля", zap.Error(err)) if errors.Is(err, ErrInvalidCurrentPassword) { http.Error(w, "Current password is incorrect", http.StatusBadRequest) return } if errors.Is(err, ErrAccountNotFound) { http.Error(w, "Account not found", http.StatusNotFound) return } http.Error(w, "Failed to change password", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{ "message": "Password changed successfully", }) } // DeleteAccount удаление аккаунта func (h *AccountHandler) DeleteAccount(w http.ResponseWriter, r *http.Request) { l := logger.Get() userID, ok := r.Context().Value(middleware.UserIDKey).(uint) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } if err := h.service.DeleteAccount(userID); err != nil { l.Error("Ошибка удаления аккаунта", zap.Error(err)) if errors.Is(err, ErrAccountNotFound) { http.Error(w, "Account not found", http.StatusNotFound) return } http.Error(w, "Failed to delete account", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{ "message": "Account deleted successfully", }) } // ==================== Административные методы ==================== // ListAccounts список аккаунтов (админ) func (h *AccountHandler) ListAccounts(w http.ResponseWriter, r *http.Request) { l := logger.Get() var req ListAccountsRequest // Парсинг query параметров if pageStr := r.URL.Query().Get("page"); pageStr != "" { page, _ := strconv.Atoi(pageStr) req.Page = page } if pageSizeStr := r.URL.Query().Get("page_size"); pageSizeStr != "" { pageSize, _ := strconv.Atoi(pageSizeStr) req.PageSize = pageSize } req.Search = r.URL.Query().Get("search") req.Role = r.URL.Query().Get("role") if isActiveStr := r.URL.Query().Get("is_active"); isActiveStr != "" { isActive, _ := strconv.ParseBool(isActiveStr) req.IsActive = &isActive } if err := h.validator.Struct(req); err != nil { h.handleValidationError(w, err) return } response, err := h.service.ListAccounts(req) if err != nil { l.Error("Ошибка получения списка аккаунтов", zap.Error(err)) http.Error(w, "Failed to list accounts", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) } // GetAccountByIDAdmin получение аккаунта по ID (админ) func (h *AccountHandler) GetAccountByIDAdmin(w http.ResponseWriter, r *http.Request) { l := logger.Get() // Получаем ID из URL idStr := r.URL.Query().Get("id") if idStr == "" { http.Error(w, "Missing id parameter", http.StatusBadRequest) return } id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { http.Error(w, "Invalid id parameter", http.StatusBadRequest) return } account, err := h.service.GetAccountByID(uint(id)) if err != nil { l.Error("Ошибка получения аккаунта", zap.Error(err)) if errors.Is(err, ErrAccountNotFound) { http.Error(w, "Account not found", http.StatusNotFound) return } http.Error(w, "Failed to get account", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(account) } // VerifyAccount верификация аккаунта (админ) func (h *AccountHandler) VerifyAccount(w http.ResponseWriter, r *http.Request) { l := logger.Get() // Получаем ID из URL idStr := r.URL.Query().Get("id") if idStr == "" { http.Error(w, "Missing id parameter", http.StatusBadRequest) return } id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { http.Error(w, "Invalid id parameter", http.StatusBadRequest) return } var req VerifyAccountRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid request body", http.StatusBadRequest) return } if err := h.service.VerifyAccount(uint(id), req); err != nil { l.Error("Ошибка верификации аккаунта", zap.Error(err)) if errors.Is(err, ErrAccountNotFound) { http.Error(w, "Account not found", http.StatusNotFound) return } http.Error(w, "Failed to verify account", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{ "message": "Account verified successfully", }) } // UpdateAccountStatus обновление статуса аккаунта (админ) func (h *AccountHandler) UpdateAccountStatus(w http.ResponseWriter, r *http.Request) { l := logger.Get() // Получаем ID из URL idStr := r.URL.Query().Get("id") if idStr == "" { http.Error(w, "Missing id parameter", http.StatusBadRequest) return } id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { http.Error(w, "Invalid id parameter", http.StatusBadRequest) return } var req UpdateAccountStatusRequest 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 { h.handleValidationError(w, err) return } if err := h.service.UpdateAccountStatus(uint(id), req); err != nil { l.Error("Ошибка обновления статуса аккаунта", zap.Error(err)) if errors.Is(err, ErrAccountNotFound) { http.Error(w, "Account not found", http.StatusNotFound) return } http.Error(w, "Failed to update account status", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{ "message": "Account status updated successfully", }) } // handleValidationError обрабатывает ошибки валидации func (h *AccountHandler) handleValidationError(w http.ResponseWriter, err error) { 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, }) }