package controllers import ( "errors" "strings" httpmw "trustcontact/internal/http/middleware" "trustcontact/internal/services" "github.com/gofiber/fiber/v2" ) type AuthController struct { authService *services.AuthService } func NewAuthController(authService *services.AuthService) *AuthController { return &AuthController{authService: authService} } func (ac *AuthController) ShowHome(c *fiber.Ctx) error { return renderPublic(c, "home.html", map[string]any{ "Title": "Home", "NavSection": "home", }) } func (ac *AuthController) ShowSignup(c *fiber.Ctx) error { return renderPublic(c, "signup.html", map[string]any{ "Title": "Sign up", "NavSection": "public", }) } func (ac *AuthController) Signup(c *fiber.Ctx) error { email := strings.TrimSpace(c.FormValue("email")) password := c.FormValue("password") if err := ac.authService.Signup(c.UserContext(), email, password); err != nil { if errors.Is(err, services.ErrEmailAlreadyExists) { httpmw.SetTemplateData(c, "FlashError", "Email gia registrata") } else { httpmw.SetTemplateData(c, "FlashError", "Impossibile completare la registrazione") } return renderPublic(c, "signup.html", map[string]any{ "Title": "Sign up", "NavSection": "public", "Email": email, }) } if err := httpmw.SetFlashSuccess(c, "Registrazione completata. Controlla la tua email per verificare l'account."); err != nil { return err } return c.Redirect("/verify-notice") } func (ac *AuthController) ShowLogin(c *fiber.Ctx) error { return renderPublic(c, "login.html", map[string]any{ "Title": "Login", "NavSection": "public", }) } func (ac *AuthController) Login(c *fiber.Ctx) error { email := strings.TrimSpace(c.FormValue("email")) password := c.FormValue("password") user, err := ac.authService.Login(email, password) if err != nil { switch { case errors.Is(err, services.ErrEmailNotVerified): httpmw.SetTemplateData(c, "FlashError", "Email non verificata. Controlla la posta.") case errors.Is(err, services.ErrInvalidCredentials): httpmw.SetTemplateData(c, "FlashError", "Credenziali non valide") default: httpmw.SetTemplateData(c, "FlashError", "Errore durante il login") } return renderPublic(c, "login.html", map[string]any{ "Title": "Login", "NavSection": "public", "Email": email, }) } if err := httpmw.SetSessionUserID(c, user.ID); err != nil { return err } if err := httpmw.SetFlashSuccess(c, "Login effettuato"); err != nil { return err } return c.Redirect("/private") } func (ac *AuthController) Logout(c *fiber.Ctx) error { if err := httpmw.ClearSessionUser(c); err != nil { return err } if err := httpmw.SetFlashSuccess(c, "Logout effettuato"); err != nil { return err } return c.Redirect("/login") } func (ac *AuthController) VerifyEmail(c *fiber.Ctx) error { token := strings.TrimSpace(c.Query("token")) if token == "" { httpmw.SetTemplateData(c, "FlashError", "Token non valido") return renderPublic(c, "verify_notice.html", map[string]any{ "Title": "Verifica email", "NavSection": "public", }) } if err := ac.authService.VerifyEmail(token); err != nil { httpmw.SetTemplateData(c, "FlashError", "Token non valido o scaduto") return renderPublic(c, "verify_notice.html", map[string]any{ "Title": "Verifica email", "NavSection": "public", }) } if err := httpmw.SetFlashSuccess(c, "Email verificata. Ora puoi accedere."); err != nil { return err } return c.Redirect("/login") } func (ac *AuthController) ShowVerifyNotice(c *fiber.Ctx) error { return renderPublic(c, "verify_notice.html", map[string]any{ "Title": "Verifica email", "NavSection": "public", }) } func (ac *AuthController) ShowForbidden(c *fiber.Ctx) error { return renderPublic(c, "forbidden.html", map[string]any{ "Title": "Forbidden", "NavSection": "public", }) } func (ac *AuthController) ShowForgotPassword(c *fiber.Ctx) error { return renderPublic(c, "forgot_password.html", map[string]any{ "Title": "Forgot password", "NavSection": "public", }) } func (ac *AuthController) ForgotPassword(c *fiber.Ctx) error { email := strings.TrimSpace(c.FormValue("email")) if err := ac.authService.ForgotPassword(c.UserContext(), email); err != nil { httpmw.SetTemplateData(c, "FlashError", "Impossibile elaborare la richiesta") return renderPublic(c, "forgot_password.html", map[string]any{ "Title": "Forgot password", "NavSection": "public", "Email": email, }) } httpmw.SetTemplateData(c, "FlashSuccess", "Se l'account esiste, riceverai una email con le istruzioni.") return renderPublic(c, "forgot_password.html", map[string]any{ "Title": "Forgot password", "NavSection": "public", }) } func (ac *AuthController) ShowResetPassword(c *fiber.Ctx) error { token := strings.TrimSpace(c.Query("token")) return renderPublic(c, "reset_password.html", map[string]any{ "Title": "Reset password", "NavSection": "public", "Token": token, }) } func (ac *AuthController) ResetPassword(c *fiber.Ctx) error { token := strings.TrimSpace(c.Query("token")) password := c.FormValue("password") if token == "" { httpmw.SetTemplateData(c, "FlashError", "Token non valido") return renderPublic(c, "reset_password.html", map[string]any{ "Title": "Reset password", "NavSection": "public", }) } if err := ac.authService.ResetPassword(token, password); err != nil { httpmw.SetTemplateData(c, "FlashError", "Token non valido o scaduto") return renderPublic(c, "reset_password.html", map[string]any{ "Title": "Reset password", "NavSection": "public", "Token": token, }) } if err := httpmw.SetFlashSuccess(c, "Password aggiornata. Effettua il login."); err != nil { return err } return c.Redirect("/login") } func (ac *AuthController) UpdateLanguage(c *fiber.Ctx) error { currentUser, ok := httpmw.CurrentUserFromContext(c) if !ok { return c.SendStatus(fiber.StatusUnauthorized) } type langRequest struct { Lang string `json:"lang" form:"lang"` } var req langRequest if err := c.BodyParser(&req); err != nil { req.Lang = c.FormValue("lang") } lang := services.NormalizeLanguage(req.Lang) if !services.IsSupportedLanguage(lang) { return c.Status(fiber.StatusBadRequest).SendString("invalid language") } if err := ac.authService.UpdateUserLanguage(currentUser.ID, lang); err != nil { if errors.Is(err, services.ErrInvalidLanguage) { return c.Status(fiber.StatusBadRequest).SendString("invalid language") } return c.Status(fiber.StatusInternalServerError).SendString("cannot update language") } return c.SendStatus(fiber.StatusNoContent) } func (ac *AuthController) UpdateTheme(c *fiber.Ctx) error { currentUser, ok := httpmw.CurrentUserFromContext(c) if !ok { return c.SendStatus(fiber.StatusUnauthorized) } type themeRequest struct { Theme string `json:"theme" form:"theme"` } var req themeRequest if err := c.BodyParser(&req); err != nil { req.Theme = c.FormValue("theme") } theme := services.NormalizeTheme(req.Theme) if theme != "dark" && theme != "light" { return c.Status(fiber.StatusBadRequest).SendString("invalid theme") } if err := ac.authService.UpdateUserTheme(currentUser.ID, theme); err != nil { if errors.Is(err, services.ErrInvalidTheme) { return c.Status(fiber.StatusBadRequest).SendString("invalid theme") } return c.Status(fiber.StatusInternalServerError).SendString("cannot update theme") } return c.SendStatus(fiber.StatusNoContent) }