15357fd3c0
yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarba
224 lines
7.0 KiB
Go
224 lines
7.0 KiB
Go
// handlers/email_handler.go
|
|
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"api_bb/internal/models"
|
|
"api_bb/internal/service"
|
|
"api_bb/pkg/logger"
|
|
"api_bb/pkg/middleware"
|
|
"api_bb/pkg/utils"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type EmailHandler struct {
|
|
logger logger.LoggerInterface
|
|
emailService *service.EmailService
|
|
}
|
|
|
|
func NewEmailHandler(emailService *service.EmailService) *EmailHandler {
|
|
return &EmailHandler{
|
|
logger: logger.NewWrapper(logger.Get().With(zap.String("handler", "email"))),
|
|
emailService: emailService,
|
|
}
|
|
}
|
|
|
|
// VerifyEmail подтверждает email пользователя
|
|
func (h *EmailHandler) VerifyEmail(w http.ResponseWriter, r *http.Request) {
|
|
h.logger.Info("handling email verification request",
|
|
zap.String("method", r.Method),
|
|
zap.String("path", r.URL.Path),
|
|
zap.String("remote_addr", r.RemoteAddr),
|
|
)
|
|
|
|
token := r.URL.Query().Get("token")
|
|
if token == "" {
|
|
h.logger.Warn("email verification failed - token is required")
|
|
utils.RespondWithError(w, http.StatusBadRequest, "Токен обязателен")
|
|
return
|
|
}
|
|
|
|
if err := h.emailService.VerifyEmail(token); err != nil {
|
|
h.logger.Error("email verification failed, expired",
|
|
zap.Error(err),
|
|
zap.String("token", token),
|
|
)
|
|
utils.RespondWithError(w, http.StatusBadRequest, "Неверный или просроченный токен")
|
|
return
|
|
}
|
|
|
|
h.logger.Info("email successfully verified",
|
|
zap.String("token", token),
|
|
)
|
|
|
|
utils.RespondWithJSON(w, http.StatusOK, map[string]string{
|
|
"message": "Email успешно подтвержден",
|
|
})
|
|
}
|
|
|
|
// RequestPasswordReset запрашивает сброс пароля
|
|
func (h *EmailHandler) RequestPasswordReset(w http.ResponseWriter, r *http.Request) {
|
|
h.logger.Info("handling password reset request",
|
|
zap.String("method", r.Method),
|
|
zap.String("path", r.URL.Path),
|
|
zap.String("remote_addr", r.RemoteAddr),
|
|
)
|
|
|
|
var req models.PasswordResetRequest
|
|
if err := utils.DecodeJSONBody(w, r, &req); err != nil {
|
|
h.logger.Warn("password reset request failed - invalid request format",
|
|
zap.Error(err),
|
|
)
|
|
utils.RespondWithError(w, http.StatusBadRequest, "Неверный формат запроса")
|
|
return
|
|
}
|
|
|
|
if err := h.emailService.SendPasswordResetEmail(req.Email); err != nil {
|
|
h.logger.Error("password reset request failed",
|
|
zap.Error(err),
|
|
zap.String("email", req.Email),
|
|
)
|
|
// Для безопасности всегда возвращаем успех
|
|
}
|
|
|
|
h.logger.Info("password reset request processed",
|
|
zap.String("email", req.Email),
|
|
)
|
|
|
|
utils.RespondWithJSON(w, http.StatusOK, map[string]string{
|
|
"message": "Если email зарегистрирован, инструкции по восстановлению пароля будут отправлены",
|
|
})
|
|
}
|
|
|
|
// ConfirmPasswordReset подтверждает сброс пароля
|
|
func (h *EmailHandler) ConfirmPasswordReset(w http.ResponseWriter, r *http.Request) {
|
|
h.logger.Info("handling password reset confirmation request",
|
|
zap.String("method", r.Method),
|
|
zap.String("path", r.URL.Path),
|
|
zap.String("remote_addr", r.RemoteAddr),
|
|
)
|
|
|
|
var req models.PasswordResetConfirm
|
|
if err := utils.DecodeJSONBody(w, r, &req); err != nil {
|
|
h.logger.Warn("password reset confirmation failed - invalid request format",
|
|
zap.Error(err),
|
|
)
|
|
utils.RespondWithError(w, http.StatusBadRequest, "Неверный формат запроса")
|
|
return
|
|
}
|
|
|
|
if err := h.emailService.ResetPassword(req.Token, req.Password); err != nil {
|
|
h.logger.Error("password reset confirmation failed",
|
|
zap.Error(err),
|
|
zap.String("token", req.Token),
|
|
)
|
|
utils.RespondWithError(w, http.StatusBadRequest, "Неверный или просроченный токен")
|
|
return
|
|
}
|
|
|
|
h.logger.Info("password successfully reset",
|
|
zap.String("token", req.Token),
|
|
)
|
|
|
|
utils.RespondWithJSON(w, http.StatusOK, map[string]string{
|
|
"message": "Пароль успешно изменен",
|
|
})
|
|
}
|
|
|
|
type NewsletterRequest struct {
|
|
Subject string `json:"subject" validate:"required"`
|
|
Content string `json:"content" validate:"required"`
|
|
}
|
|
|
|
// SendNewsletter отправляет рассылку новостей
|
|
func (h *EmailHandler) SendNewsletter(w http.ResponseWriter, r *http.Request) {
|
|
h.logger.Info("handling newsletter sending request",
|
|
zap.String("method", r.Method),
|
|
zap.String("path", r.URL.Path),
|
|
zap.String("remote_addr", r.RemoteAddr),
|
|
)
|
|
|
|
var req NewsletterRequest
|
|
if err := utils.DecodeJSONBody(w, r, &req); err != nil {
|
|
h.logger.Warn("newsletter sending failed - invalid request format",
|
|
zap.Error(err),
|
|
)
|
|
utils.RespondWithError(w, http.StatusBadRequest, "Неверный формат запроса")
|
|
return
|
|
}
|
|
|
|
if err := h.emailService.SendNewsletterToSubscribers(req.Subject, req.Content); err != nil {
|
|
h.logger.Error("newsletter sending failed",
|
|
zap.Error(err),
|
|
zap.String("subject", req.Subject),
|
|
)
|
|
utils.RespondWithError(w, http.StatusInternalServerError, "Не удалось отправить рассылку")
|
|
return
|
|
}
|
|
|
|
h.logger.Info("newsletter sent successfully",
|
|
zap.String("subject", req.Subject),
|
|
)
|
|
|
|
utils.RespondWithJSON(w, http.StatusOK, map[string]string{
|
|
"message": "Рассылка отправлена подписчикам",
|
|
})
|
|
}
|
|
|
|
// ResendVerification повторно отправляет email верификации
|
|
func (h *EmailHandler) ResendVerification(w http.ResponseWriter, r *http.Request) {
|
|
h.logger.Info("handling resend verification request",
|
|
zap.String("method", r.Method),
|
|
zap.String("path", r.URL.Path),
|
|
zap.String("remote_addr", r.RemoteAddr),
|
|
)
|
|
|
|
user, ok := middleware.GetUserFromContext(r.Context())
|
|
if !ok {
|
|
h.logger.Warn("resend verification failed - authentication required")
|
|
utils.RespondWithError(w, http.StatusUnauthorized, "Пользователь не авторизован")
|
|
return
|
|
}
|
|
|
|
// Получаем пользователя
|
|
userData, err := h.emailService.GetUserByID(user.ID)
|
|
if err != nil {
|
|
h.logger.Warn("resend verification failed - user not found",
|
|
zap.Uint("user_id", user.ID),
|
|
zap.Error(err),
|
|
)
|
|
utils.RespondWithError(w, http.StatusNotFound, "Пользователь не найден")
|
|
return
|
|
}
|
|
|
|
if userData.EmailVerified {
|
|
h.logger.Warn("resend verification failed - email already verified",
|
|
zap.Uint("user_id", user.ID),
|
|
zap.String("email", userData.Email),
|
|
)
|
|
utils.RespondWithError(w, http.StatusBadRequest, "Email уже подтвержден")
|
|
return
|
|
}
|
|
|
|
if err := h.emailService.SendVerificationEmail(userData.ID, userData.Email, userData.FirstName); err != nil {
|
|
h.logger.Error("resend verification failed",
|
|
zap.Error(err),
|
|
zap.Uint("user_id", user.ID),
|
|
zap.String("email", userData.Email),
|
|
)
|
|
utils.RespondWithError(w, http.StatusInternalServerError, "Не удалось отправить email подтверждения")
|
|
return
|
|
}
|
|
|
|
h.logger.Info("verification email resent successfully",
|
|
zap.Uint("user_id", user.ID),
|
|
zap.String("email", userData.Email),
|
|
)
|
|
|
|
utils.RespondWithJSON(w, http.StatusOK, map[string]string{
|
|
"message": "Email подтверждения отправлен повторно",
|
|
})
|
|
}
|