From c3677e1a4dc0b662579c82755aef6e0e9573eee8 Mon Sep 17 00:00:00 2001 From: Bobby <30593201+luciferreeves@users.noreply.github.com> Date: Thu, 5 Mar 2026 13:14:50 +0530 Subject: feat: add resend activation functionality and update verification process --- shrine/controllers/auth.go | 46 +++++++++++++++++++++++++++++++++++++++++++-- shrine/repositories/user.go | 6 ++++++ shrine/router/auth.go | 1 + shrine/types/request.go | 5 +++++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/shrine/controllers/auth.go b/shrine/controllers/auth.go index 8eedb38..1e49b37 100644 --- a/shrine/controllers/auth.go +++ b/shrine/controllers/auth.go @@ -99,14 +99,21 @@ func VerifyController(context *fiber.Ctx) error { return BadRequest(context, errors.New("Verification token is required.")) } + verificationType := enums.VerificationType(body.Type) + tokenHash := auth.HashToken(body.Token) - user, err := repositories.FindUserByVerification(tokenHash, enums.Activation) + user, err := repositories.FindUserByVerification(tokenHash, verificationType) if err != nil { return BadRequest(context, errors.New("Your verification link is invalid or has expired.")) } - user.VerifyEmail() + switch verificationType { + case enums.Activation: + user.VerifyEmail() + default: + return BadRequest(context, errors.New("Invalid verification type.")) + } if err := repositories.UpdateUser(user); err != nil { return InternalServerError(context, errors.New("Failed to verify your account.")) @@ -117,6 +124,41 @@ func VerifyController(context *fiber.Ctx) error { }) } +func ResendActivationController(context *fiber.Ctx) error { + body, err := meta.Body[types.ResendActivationRequest](context) + if err != nil { + return BadRequest(context, errors.New("Invalid request body.")) + } + + user, err := repositories.FindUserByEmail(body.Email) + if err != nil { + return BadRequest(context, errors.New("No account exists with that email address.")) + } + + if user.IsVerified() { + return BadRequest(context, errors.New("This account has already been verified.")) + } + + token, err := auth.GenerateToken() + if err != nil { + return InternalServerError(context, errors.New("Failed to generate verification token.")) + } + + user.SetVerification(auth.HashToken(token), time.Now().Add(24*time.Hour), enums.Activation) + + if err := repositories.UpdateUser(user); err != nil { + return InternalServerError(context, errors.New("Failed to store verification token.")) + } + + if err := emails.SendActivation(user.Email, user.Username, token); err != nil { + logger.Errorf("Auth", "Failed to send verification email to %s: %v", user.Email, err) + } + + return Success(context, types.MessageResponse{ + Message: "A new verification email has been sent. Please check your inbox.", + }) +} + func LogoutController(context *fiber.Ctx) error { tokenHash := auth.GetTokenHash(context) if err := repositories.DeleteToken(tokenHash); err != nil { diff --git a/shrine/repositories/user.go b/shrine/repositories/user.go index 697c5df..1161257 100644 --- a/shrine/repositories/user.go +++ b/shrine/repositories/user.go @@ -30,6 +30,12 @@ func UpdateUser(user *models.User) error { return database.DB.Save(user).Error } +func FindUserByEmail(email string) (*models.User, error) { + var user models.User + err := database.DB.Where("email = ?", email).First(&user).Error + return &user, err +} + func FindUserByVerification(hash string, verificationType enums.VerificationType) (*models.User, error) { var user models.User err := database.DB.Where("verification_hash = ? AND verification_type = ? AND verification_expiry > ?", hash, verificationType, time.Now()).First(&user).Error diff --git a/shrine/router/auth.go b/shrine/router/auth.go index 7c566eb..5ad5fee 100644 --- a/shrine/router/auth.go +++ b/shrine/router/auth.go @@ -13,6 +13,7 @@ func init() { urls.Path(types.POST, "/register", controllers.RegisterController, "register") urls.Path(types.POST, "/login", controllers.LoginController, "login") urls.Path(types.POST, "/verify", controllers.VerifyController, "verify") + urls.Path(types.POST, "/reactivate", controllers.ResendActivationController, "reactivate") urls.Path(types.POST, "/logout", auth.RequireAuthentication(controllers.LogoutController), "logout") urls.Path(types.GET, "/me", auth.RequireAuthentication(controllers.MeController), "me") } \ No newline at end of file diff --git a/shrine/types/request.go b/shrine/types/request.go index 32e81a9..a782efd 100644 --- a/shrine/types/request.go +++ b/shrine/types/request.go @@ -14,4 +14,9 @@ type LoginRequest struct { type VerifyRequest struct { Token string `json:"token"` + Type string `json:"type"` +} + +type ResendActivationRequest struct { + Email string `json:"email"` } \ No newline at end of file -- cgit v1.2.3