From cfdcbc452064854140bb572dea154d3f5c2f857b Mon Sep 17 00:00:00 2001 From: Bobby Date: Sun, 13 Jul 2025 14:55:23 +0530 Subject: account verification and login flow --- controllers/account.go | 48 +++++++++++++++++++++++++++++++++ controllers/constants.go | 51 ++++++++++++++++++++--------------- database/tokens.go | 4 +-- models/user.go | 7 +++++ router/routes.go | 3 +++ templates/account/verify_email.django | 21 +++++++++++++++ templates/login.django | 2 +- templates/partials/navbar.django | 1 + 8 files changed, 112 insertions(+), 25 deletions(-) create mode 100644 controllers/account.go create mode 100644 templates/account/verify_email.django diff --git a/controllers/account.go b/controllers/account.go new file mode 100644 index 0000000..86b3ea4 --- /dev/null +++ b/controllers/account.go @@ -0,0 +1,48 @@ +package controllers + +import ( + "imageboard/database" + "imageboard/models" + "imageboard/utils/auth" + "imageboard/utils/shortcuts" + + "github.com/gofiber/fiber/v2" +) + +func renderVerifyEmailError(ctx *fiber.Ctx, errorMsg string, statusCode int) error { + return shortcuts.RenderWithStatus(ctx, TEMPLATE_VERIFY_EMAIL, fiber.Map{ + "Error": errorMsg, + }, statusCode) +} + +func VerifyEmailController(ctx *fiber.Ctx) error { + ctx.Locals("Title", PT_VERIFY_EMAIL) + if auth.IsAuthenticated(ctx) { + return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther) + } + token := ctx.Query("token") + if token == "" { + return renderVerifyEmailError(ctx, ERR_VERIFY_EMAIL_MISSING_TOKEN, fiber.StatusBadRequest) + } + + emailToken, err := database.VerifyToken(token, models.EmailTokenTypeVerification) + if err != nil { + return renderVerifyEmailError(ctx, ERR_VERIFY_EMAIL_INVALID_OR_EXPIRED_TOKEN, fiber.StatusBadRequest) + } + + user, err := database.GetUserByID(emailToken.UserID) + if err != nil { + return renderVerifyEmailError(ctx, ERR_VERIFY_EMAIL_USER_NOT_FOUND, fiber.StatusInternalServerError) + } + + user.Activate() + if err := database.DB.Save(user).Error; err != nil { + return renderVerifyEmailError(ctx, ERR_VERIFY_EMAIL_ACTIVATION_FAILED, fiber.StatusInternalServerError) + } + + return shortcuts.Render(ctx, TEMPLATE_VERIFY_EMAIL, fiber.Map{ + "Success": SUCCESS_VERIFY_EMAIL, + "Username": user.Username, + }) + +} diff --git a/controllers/constants.go b/controllers/constants.go index 021eeb9..7417314 100644 --- a/controllers/constants.go +++ b/controllers/constants.go @@ -2,20 +2,22 @@ package controllers const ( // Page titles - PT_HOME = "Home Page" - PT_LOGIN = "Login" - PT_POSTS = "Posts" - PT_PREFERENCES = "Preferences" - PT_REGISTER = "Register" - PT_404 = "Page Not Found" + PT_HOME = "Home Page" + PT_LOGIN = "Login" + PT_POSTS = "Posts" + PT_PREFERENCES = "Preferences" + PT_REGISTER = "Register" + PT_404 = "Page Not Found" + PT_VERIFY_EMAIL = "Verify Email" // Template names - TEMPLATE_HOME = "home" - TEMPLATE_LOGIN = "login" - TEMPLATE_POSTS = "posts" - TEMPLATE_PREFERENCES = "preferences" - TEMPLATE_REGISTER = "register" - TEMPLATE_404 = "404" + TEMPLATE_HOME = "home" + TEMPLATE_LOGIN = "login" + TEMPLATE_POSTS = "posts" + TEMPLATE_PREFERENCES = "preferences" + TEMPLATE_REGISTER = "register" + TEMPLATE_404 = "404" + TEMPLATE_VERIFY_EMAIL = "account/verify_email" // URL constants for various routes URL_HOME = "/" @@ -23,19 +25,24 @@ const ( URL_POSTS = "/posts" URL_PREFERENCES = "/preferences" URL_REGISTER = "/register" - URL_FORGOT_PASSWORD = "/accounts/forgot-password" - URL_RESEND_VERIFICATION = "/accounts/resend-verification" + URL_FORGOT_PASSWORD = "/account/forgot-password" + URL_RESEND_VERIFICATION = "/account/resend-verification" // Error messages - ERR_INVALID_FORM_DATA = "The submitted form data is invalid. Check your input and try again." - ERR_USER_NOT_FOUND = `User with that username not found. Maybe you want to register?` - ERR_LOGIN_INVALID_CREDENTIALS = `The credentials you provided are incorrect. Did you forget your password?` - ERR_ACCOUNT_DISABLED = `Your account is disabled or banned. You can reach out to support for assistance.` - ERR_ACCOUNT_UNABLE_TO_LOGIN = `You cannot log in at this time. Verify your email or contact support. If you misplaced your verification email, you can request a new one.` - ERR_PASSWORD_MISMATCH = "Entered passwords do not match. Ensure both fields are identical." - ERR_SESSION_FAILED_TO_CREATE = "Server failed to create a session. If this issue persists, contact support." - ERR_SESSION_FAILED_TO_SAVE = "Server failed to save session data. If this issue persists, contact support." + ERR_INVALID_FORM_DATA = "The submitted form data is invalid. Check your input and try again." + ERR_USER_NOT_FOUND = `User with that username not found. Maybe you want to register?` + ERR_LOGIN_INVALID_CREDENTIALS = `The credentials you provided are incorrect. Did you forget your password?` + ERR_ACCOUNT_DISABLED = `Your account is disabled or banned. You can reach out to support for assistance.` + ERR_ACCOUNT_UNABLE_TO_LOGIN = `You cannot log in at this time. Verify your email or contact support. If you misplaced your verification email, you can request a new one.` + ERR_PASSWORD_MISMATCH = "Entered passwords do not match. Ensure both fields are identical." + ERR_SESSION_FAILED_TO_CREATE = "Server failed to create a session. If this issue persists, contact support." + ERR_SESSION_FAILED_TO_SAVE = "Server failed to save session data. If this issue persists, contact support." + ERR_VERIFY_EMAIL_MISSING_TOKEN = `Verification token is missing. Check the link you clicked or request a new verification email.` + ERR_VERIFY_EMAIL_INVALID_OR_EXPIRED_TOKEN = `The verification token is either invalid or has expired. Try requesting a new verification email.` + ERR_VERIFY_EMAIL_USER_NOT_FOUND = `User not found for the provided verification token. If you think this is an error, contact support.` + ERR_VERIFY_EMAIL_ACTIVATION_FAILED = `Failed to activate your account. If this issue persists, contact support.` // Success messages SUCCESS_USER_REGISTERED = "Your account has been created successfully. A verification email has been sent to your email address. You will only be able to log in after verifying your email. If you did not receive the email, you can request a new one." + SUCCESS_VERIFY_EMAIL = `Your email has been successfully verified. You can now log in to your account.` ) diff --git a/database/tokens.go b/database/tokens.go index ddbc1f6..8ff69d4 100644 --- a/database/tokens.go +++ b/database/tokens.go @@ -46,9 +46,9 @@ func GenerateEmailToken(userID int, tokenType models.EmailTokenType) (*models.Em return token, nil } -func VerifyToken(userID int, token string, tokenType models.EmailTokenType) (*models.EmailToken, error) { +func VerifyToken(token string, tokenType models.EmailTokenType) (*models.EmailToken, error) { var emailToken models.EmailToken - if err := DB.Where("user_id = ? AND token = ? AND type = ?", userID, token, tokenType).First(&emailToken).Error; err != nil { + if err := DB.Where("token = ? AND type = ?", token, tokenType).First(&emailToken).Error; err != nil { return nil, err } diff --git a/models/user.go b/models/user.go index 3b92077..546f600 100644 --- a/models/user.go +++ b/models/user.go @@ -127,6 +127,13 @@ func (u *User) CheckPassword(password string) bool { return err == nil } +func (u *User) Activate() { + u.IsDeleted = false + u.AccountDisabled = false + u.AccountBanned = false + u.EmailVerified = true +} + func (u *User) IsActive() bool { return !u.IsDeleted && !u.AccountDisabled && !u.AccountBanned } diff --git a/router/routes.go b/router/routes.go index c522599..91665df 100644 --- a/router/routes.go +++ b/router/routes.go @@ -24,6 +24,9 @@ func Initialize(router *fiber.App) { register.Get("/", controllers.RegisterPageController) register.Post("/", controllers.RegisterPostController) + account := router.Group("/account") + account.Get("/verify", controllers.VerifyEmailController) + preferences := router.Group("/preferences") preferences.Get("/", controllers.PreferencesPageController) diff --git a/templates/account/verify_email.django b/templates/account/verify_email.django new file mode 100644 index 0000000..42298ef --- /dev/null +++ b/templates/account/verify_email.django @@ -0,0 +1,21 @@ +{% extends 'layouts/main.django' %} + +{% block content %} +
+ {% if Error %} +
+

Email Verification Error

+
+

{{ Error|safe }}

+
+ {% endif %} + + {% if Success %} +
+

Email Verified Successfully

+
+

{{ Success|safe }}

+
+ {% endif %} +
+{% endblock %} diff --git a/templates/login.django b/templates/login.django index 3c2e39b..01c6d28 100644 --- a/templates/login.django +++ b/templates/login.django @@ -30,7 +30,7 @@
- +

diff --git a/templates/partials/navbar.django b/templates/partials/navbar.django index 70e7950..7180e9c 100644 --- a/templates/partials/navbar.django +++ b/templates/partials/navbar.django @@ -12,6 +12,7 @@