979c265e36
modified: main_dc/yalarba/api_yal/internal/domain/account/handler.go modified: main_dc/yalarba/api_yal/internal/domain/account/router.go modified: main_dc/yalarba/api_yal/internal/domain/account/service.go modified: main_dc/yalarba/api_yal/internal/domain/auth/router.go new file: main_dc/yalarba/api_yal/internal/domain/comment/dto.go new file: main_dc/yalarba/api_yal/internal/domain/feetback/dto.go new file: main_dc/yalarba/api_yal/internal/domain/object/dto.go new file: main_dc/yalarba/api_yal/internal/domain/object/errors.go new file: main_dc/yalarba/api_yal/internal/domain/object/handler.go new file: main_dc/yalarba/api_yal/internal/domain/object/router.go new file: main_dc/yalarba/api_yal/internal/domain/object/service.go new file: main_dc/yalarba/api_yal/internal/domain/object/types.go new file: main_dc/yalarba/api_yal/internal/domain/rating/dto.go modified: main_dc/yalarba/api_yal/internal/models/rating.go add and not tested Object's domain
373 lines
10 KiB
Go
373 lines
10 KiB
Go
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,
|
|
})
|
|
} |