package controller import ( "codeword/internal/services" "github.com/gofiber/fiber/v2" "go.uber.org/zap" "time" ) type RecoveryController struct { logger *zap.Logger service *services.RecoveryService defaultURL string } func NewRecoveryController(logger *zap.Logger, service *services.RecoveryService, defaultRedirectionURL string) *RecoveryController { return &RecoveryController{ logger: logger, service: service, defaultURL: defaultRedirectionURL, } } func (r *RecoveryController) HandlePingDB(c *fiber.Ctx) error { return r.service.Ping(c.Context()) } // TODO add deps struct, counnt params >3 // HandleRecoveryRequest обрабатывает запрос на восстановление пароля func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error { email := c.FormValue("email") referralURL := c.Get("Referrer") redirectionURL := c.FormValue("RedirectionURL") if redirectionURL == "" && referralURL != "" { redirectionURL = referralURL } else if redirectionURL == "" { redirectionURL = r.defaultURL } key, err := r.service.GenerateKey() if err != nil { r.logger.Error("Failed to generate key", zap.Error(err)) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } user, err := r.service.FindUserByEmail(c.Context(), email) if err != nil || user == nil { r.logger.Error("Failed to find user by email", zap.Error(err)) return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"}) } //sign := referralURL + string(key) id, err := r.service.StoreRecoveryRecord(c.Context(), user.ID.Hex(), user.Email, key) if err != nil { r.logger.Error("Failed to store recovery record", zap.Error(err)) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } err = r.service.RecoveryEmailTask(c.Context(), user.ID.Hex(), email, key, id) if err != nil { r.logger.Error("Failed to send recovery email", zap.Error(err)) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } return c.Status(fiber.StatusOK).JSON(fiber.Map{ "id": id, }) } // HandleRecoveryLink обрабатывает ссылку восстановления и обменивает ее на токены func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error { key := c.Params("sign") // тут получается record, err := r.service.GetRecoveryRecord(c.Context(), []byte(key)) if err != nil { r.logger.Error("Failed to get recovery record", zap.Error(err)) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } // проверка на более чем 15 минут if time.Since(record.CreatedAt) > 15*time.Minute { r.logger.Error("Recovery link expired", zap.String("signature", key)) return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Recovery link expired"}) } tokens, err := r.service.ExchangeForTokens(record.UserID) if err != nil { r.logger.Error("Failed to exchange recovery link for tokens", zap.Error(err)) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } return c.Status(fiber.StatusOK).JSON(tokens) }