aboutsummaryrefslogtreecommitdiff
path: root/controllers
diff options
context:
space:
mode:
authorBobby <[email protected]>2025-12-15 14:28:13 +0530
committerBobby <[email protected]>2025-12-15 14:28:13 +0530
commite143ba0b4a0fff8448124d86bb94e07742aa0a9b (patch)
tree0dce19e2122b60c6a9e1a338fa884ba206be561c /controllers
parent5f6e383d3799d39036842e00ae3149be7fafe188 (diff)
downloadimageboard-main.tar.xz
imageboard-main.zip
account routes clubbed together; send email for forgot usernameHEADmain
Diffstat (limited to 'controllers')
-rw-r--r--controllers/account.go279
-rw-r--r--controllers/login.go81
-rw-r--r--controllers/logout.go28
-rw-r--r--controllers/register.go89
4 files changed, 279 insertions, 198 deletions
diff --git a/controllers/account.go b/controllers/account.go
index d59da8e..df0ccdb 100644
--- a/controllers/account.go
+++ b/controllers/account.go
@@ -3,12 +3,291 @@ package controllers
import (
"imageboard/config"
"imageboard/database"
+ "imageboard/models"
+ "imageboard/session"
"imageboard/utils/auth"
+ "imageboard/utils/email"
"imageboard/utils/shortcuts"
+ "log"
+ "strings"
"github.com/gofiber/fiber/v2"
)
+type LoginForm struct {
+ Username string `json:"username" form:"username"`
+ Password string `json:"password" form:"password"`
+}
+
+func LoginPageController(ctx *fiber.Ctx) error {
+ ctx.Locals("Title", config.PT_LOGIN)
+
+ if auth.IsAuthenticated(ctx) {
+ return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther)
+ }
+
+ next := ctx.Query("next")
+ return shortcuts.Render(ctx, config.TEMPLATE_LOGIN, fiber.Map{
+ "Next": next,
+ })
+}
+
+func LoginPostController(ctx *fiber.Ctx) error {
+ ctx.Locals("Title", config.PT_LOGIN)
+
+ var form LoginForm
+ var err error
+ handleLoginError := func(errorMessage string, statusCode int) error {
+ return TemplateErrorController(ctx, TemplateError{
+ Template: config.TEMPLATE_LOGIN,
+ ErrorMessage: errorMessage,
+ StatusCode: statusCode,
+ }, fiber.Map{
+ "Username": form.Username,
+ })
+ }
+
+ if err = ctx.BodyParser(&form); err != nil {
+ return handleLoginError(config.ERR_INVALID_FORM_DATA, fiber.StatusBadRequest)
+ }
+
+ user, err := database.GetUserByUsername(form.Username)
+ if err != nil {
+ return handleLoginError(config.ERR_USER_NOT_FOUND, fiber.StatusUnauthorized)
+ }
+
+ if !user.CheckPassword(form.Password) {
+ return handleLoginError(config.ERR_LOGIN_INVALID_CREDENTIALS, fiber.StatusUnauthorized)
+ }
+
+ if !user.IsActive() {
+ return handleLoginError(config.ERR_ACCOUNT_DISABLED, fiber.StatusForbidden)
+ }
+
+ if !user.CanLogin() {
+ return handleLoginError(config.ERR_ACCOUNT_UNABLE_TO_LOGIN, fiber.StatusForbidden)
+ }
+
+ sess, err := session.Store.Get(ctx)
+ if err != nil {
+ return handleLoginError(config.ERR_SESSION_FAILED_TO_CREATE, fiber.StatusInternalServerError)
+ }
+ sess.Set("user_id", user.ID)
+ sess.Set("username", user.Username)
+ if err := sess.Save(); err != nil {
+ return handleLoginError(config.ERR_SESSION_FAILED_TO_SAVE, fiber.StatusInternalServerError)
+ }
+
+ user.UpdateLastUserLogin(database.DB)
+ user.UpdateLastUserActivity(database.DB)
+
+ return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther)
+}
+
+func LogoutController(ctx *fiber.Ctx) error {
+ sess, err := session.Store.Get(ctx)
+ if err != nil {
+ return ctx.Redirect(config.URL_HOME, fiber.StatusSeeOther)
+ }
+
+ if err := sess.Destroy(); err != nil {
+ sess.Delete("user_id")
+ sess.Delete("username")
+ sess.Save()
+ }
+
+ next := ctx.Query("next")
+ if next != "" {
+ return ctx.Redirect(next, fiber.StatusSeeOther)
+ }
+
+ return ctx.Redirect(config.URL_HOME, fiber.StatusSeeOther)
+}
+
+type RegisterForm struct {
+ Username string `json:"username" form:"username"`
+ Email string `json:"email" form:"email"`
+ Password string `json:"password" form:"password"`
+ ConfirmPassword string `json:"confirm_password" form:"confirm_password"`
+}
+
+func RegisterPageController(ctx *fiber.Ctx) error {
+ ctx.Locals("Title", config.PT_REGISTER)
+
+ if auth.IsAuthenticated(ctx) {
+ return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther)
+ }
+
+ return shortcuts.Render(ctx, config.TEMPLATE_REGISTER, nil)
+}
+
+func RegisterPostController(ctx *fiber.Ctx) error {
+ ctx.Locals("Title", config.PT_REGISTER)
+
+ if auth.IsAuthenticated(ctx) {
+ return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther)
+ }
+
+ var form RegisterForm
+ handleRegisterError := func(errorMessage string, statusCode int) error {
+ return TemplateErrorController(ctx, TemplateError{
+ Template: config.TEMPLATE_REGISTER,
+ ErrorMessage: errorMessage,
+ StatusCode: statusCode,
+ }, fiber.Map{
+ "Username": form.Username,
+ "Email": form.Email,
+ })
+ }
+
+ if err := ctx.BodyParser(&form); err != nil {
+ return handleRegisterError(config.ERR_INVALID_FORM_DATA, fiber.StatusBadRequest)
+ }
+
+ if form.Password != form.ConfirmPassword {
+ return handleRegisterError(config.ERR_PASSWORD_MISMATCH, fiber.StatusBadRequest)
+ }
+
+ user := &models.User{
+ Username: form.Username,
+ Email: form.Email,
+ Password: form.Password,
+ PostsRequireApproval: true,
+ Level: config.UserLevelMember,
+ }
+
+ if err := database.CreateUser(user); err != nil {
+ var statusCode int
+ if strings.Contains(err.Error(), "username") {
+ statusCode = fiber.StatusConflict
+ } else if strings.Contains(err.Error(), "email") {
+ statusCode = fiber.StatusBadRequest
+ } else {
+ statusCode = fiber.StatusInternalServerError
+ }
+
+ return handleRegisterError(config.ERR_REGISTER_FAILED_TO_CREATE_USER+err.Error(), statusCode)
+ }
+
+ if err := email.SendVerificationEmail(user); err != nil {
+ log.Printf("Failed to send verification email: %v", err)
+ return handleRegisterError(config.ERR_REGISTER_USER_CREATED_EMAIL_FAILED, fiber.StatusInternalServerError)
+ }
+
+ return shortcuts.Render(ctx, config.TEMPLATE_REGISTER, fiber.Map{
+ "Success": config.SUCCESS_USER_REGISTERED,
+ })
+}
+
+func ForgotPasswordPageController(ctx *fiber.Ctx) error {
+ mode := ctx.Query("mode", "username")
+ switch mode {
+ case "username":
+ ctx.Locals("Title", config.PT_FORGOT_USERNAME)
+ case "password":
+ ctx.Locals("Title", config.PT_FORGOT_PASSWORD)
+ default:
+ ctx.Locals("Title", config.PT_FORGOT_USERNAME)
+ mode = "username"
+ }
+
+ if auth.IsAuthenticated(ctx) {
+ return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther)
+ }
+
+ return shortcuts.Render(ctx, config.TEMPLATE_FORGOT, fiber.Map{
+ "Mode": mode,
+ })
+}
+
+type ForgotPasswordInput struct {
+ Email string `json:"email" form:"email"`
+ Mode string `json:"mode" form:"mode"`
+}
+
+func ForgotPasswordPostController(ctx *fiber.Ctx) error {
+ ctx.Locals("Title", config.PT_FORGOT_PASSWORD)
+
+ if auth.IsAuthenticated(ctx) {
+ return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther)
+ }
+
+ var input ForgotPasswordInput
+ if err := ctx.BodyParser(&input); err != nil {
+ return TemplateErrorController(ctx, TemplateError{
+ Template: config.TEMPLATE_FORGOT,
+ ErrorMessage: config.ERR_INVALID_FORM_DATA,
+ StatusCode: fiber.StatusBadRequest,
+ }, fiber.Map{
+ "Mode": input.Mode,
+ })
+ }
+
+ switch input.Mode {
+ case "password":
+ ctx.Locals("Title", config.PT_FORGOT_PASSWORD)
+ case "username":
+ ctx.Locals("Title", config.PT_FORGOT_USERNAME)
+ default:
+ ctx.Locals("Title", config.PT_FORGOT_USERNAME)
+ input.Mode = "username"
+ }
+
+ users, err := database.GetUsersByEmail(input.Email)
+ if err != nil || len(users) == 0 {
+ return TemplateErrorController(ctx, TemplateError{
+ Template: config.TEMPLATE_FORGOT,
+ ErrorMessage: config.ERR_NO_ACCOUNT_ASSOCIATED_WITH_EMAIL,
+ StatusCode: fiber.StatusNotFound,
+ }, fiber.Map{
+ "Mode": input.Mode,
+ })
+ }
+
+ switch mode := input.Mode; mode {
+ case "username":
+ if err := email.SendForgotUsernameEmail(&users); err != nil {
+ log.Printf("Failed to send forgot username email: %v", err)
+ return TemplateErrorController(ctx, TemplateError{
+ Template: config.TEMPLATE_FORGOT,
+ ErrorMessage: "Failed to send username email. Please try again later.",
+ StatusCode: fiber.StatusInternalServerError,
+ }, fiber.Map{
+ "Mode": input.Mode,
+ })
+ }
+ case "password":
+ // TODO
+ default:
+ return TemplateErrorController(ctx, TemplateError{
+ Template: config.TEMPLATE_FORGOT,
+ ErrorMessage: config.ERR_INVALID_FORM_DATA,
+ StatusCode: fiber.StatusBadRequest,
+ }, fiber.Map{
+ "Mode": input.Mode,
+ })
+ }
+
+ switch input.Mode {
+ case "username":
+ return shortcuts.Render(ctx, config.TEMPLATE_FORGOT, fiber.Map{
+ "Success": config.SUCCESS_FORGOT_USERNAME_EMAIL_SENT,
+ "Mode": input.Mode,
+ })
+ case "password":
+ // TODO
+ return shortcuts.Render(ctx, config.TEMPLATE_FORGOT, fiber.Map{
+ "Success": "If an account with that email exists, a password reset email has been sent.",
+ "Mode": input.Mode,
+ })
+ default:
+ return shortcuts.Render(ctx, config.TEMPLATE_FORGOT, fiber.Map{
+ "Success": config.SUCCESS_FORGOT_USERNAME_EMAIL_SENT,
+ "Mode": input.Mode,
+ })
+ }
+}
+
func VerifyEmailController(ctx *fiber.Ctx) error {
ctx.Locals("Title", config.PT_VERIFY_EMAIL)
if auth.IsAuthenticated(ctx) {
diff --git a/controllers/login.go b/controllers/login.go
deleted file mode 100644
index 64ad047..0000000
--- a/controllers/login.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package controllers
-
-import (
- "imageboard/config"
- "imageboard/database"
- "imageboard/session"
- "imageboard/utils/auth"
- "imageboard/utils/shortcuts"
-
- "github.com/gofiber/fiber/v2"
-)
-
-type LoginForm struct {
- Username string `json:"username" form:"username"`
- Password string `json:"password" form:"password"`
-}
-
-func LoginPageController(ctx *fiber.Ctx) error {
- ctx.Locals("Title", config.PT_LOGIN)
-
- if auth.IsAuthenticated(ctx) {
- return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther)
- }
-
- next := ctx.Query("next")
- return shortcuts.Render(ctx, config.TEMPLATE_LOGIN, fiber.Map{
- "Next": next,
- })
-}
-
-func LoginPostController(ctx *fiber.Ctx) error {
- ctx.Locals("Title", config.PT_LOGIN)
-
- var form LoginForm
- var err error
- handleLoginError := func(errorMessage string, statusCode int) error {
- return TemplateErrorController(ctx, TemplateError{
- Template: config.TEMPLATE_LOGIN,
- ErrorMessage: errorMessage,
- StatusCode: statusCode,
- }, fiber.Map{
- "Username": form.Username,
- })
- }
-
- if err = ctx.BodyParser(&form); err != nil {
- return handleLoginError(config.ERR_INVALID_FORM_DATA, fiber.StatusBadRequest)
- }
-
- user, err := database.GetUserByUsername(form.Username)
- if err != nil {
- return handleLoginError(config.ERR_USER_NOT_FOUND, fiber.StatusUnauthorized)
- }
-
- if !user.CheckPassword(form.Password) {
- return handleLoginError(config.ERR_LOGIN_INVALID_CREDENTIALS, fiber.StatusUnauthorized)
- }
-
- if !user.IsActive() {
- return handleLoginError(config.ERR_ACCOUNT_DISABLED, fiber.StatusForbidden)
- }
-
- if !user.CanLogin() {
- return handleLoginError(config.ERR_ACCOUNT_UNABLE_TO_LOGIN, fiber.StatusForbidden)
- }
-
- sess, err := session.Store.Get(ctx)
- if err != nil {
- return handleLoginError(config.ERR_SESSION_FAILED_TO_CREATE, fiber.StatusInternalServerError)
- }
- sess.Set("user_id", user.ID)
- sess.Set("username", user.Username)
- if err := sess.Save(); err != nil {
- return handleLoginError(config.ERR_SESSION_FAILED_TO_SAVE, fiber.StatusInternalServerError)
- }
-
- user.UpdateLastUserLogin(database.DB)
- user.UpdateLastUserActivity(database.DB)
-
- return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther)
-}
diff --git a/controllers/logout.go b/controllers/logout.go
deleted file mode 100644
index 58ff545..0000000
--- a/controllers/logout.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package controllers
-
-import (
- "imageboard/config"
- "imageboard/session"
-
- "github.com/gofiber/fiber/v2"
-)
-
-func LogoutController(ctx *fiber.Ctx) error {
- sess, err := session.Store.Get(ctx)
- if err != nil {
- return ctx.Redirect(config.URL_HOME, fiber.StatusSeeOther)
- }
-
- if err := sess.Destroy(); err != nil {
- sess.Delete("user_id")
- sess.Delete("username")
- sess.Save()
- }
-
- next := ctx.Query("next")
- if next != "" {
- return ctx.Redirect(next, fiber.StatusSeeOther)
- }
-
- return ctx.Redirect(config.URL_HOME, fiber.StatusSeeOther)
-}
diff --git a/controllers/register.go b/controllers/register.go
deleted file mode 100644
index 6d1383f..0000000
--- a/controllers/register.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package controllers
-
-import (
- "imageboard/config"
- "imageboard/database"
- "imageboard/models"
- "imageboard/utils/auth"
- "imageboard/utils/email"
- "imageboard/utils/shortcuts"
- "log"
- "strings"
-
- "github.com/gofiber/fiber/v2"
-)
-
-type RegisterForm struct {
- Username string `json:"username" form:"username"`
- Email string `json:"email" form:"email"`
- Password string `json:"password" form:"password"`
- ConfirmPassword string `json:"confirm_password" form:"confirm_password"`
-}
-
-func RegisterPageController(ctx *fiber.Ctx) error {
- ctx.Locals("Title", config.PT_REGISTER)
-
- if auth.IsAuthenticated(ctx) {
- return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther)
- }
-
- return shortcuts.Render(ctx, config.TEMPLATE_REGISTER, nil)
-}
-
-func RegisterPostController(ctx *fiber.Ctx) error {
- ctx.Locals("Title", config.PT_REGISTER)
-
- if auth.IsAuthenticated(ctx) {
- return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther)
- }
-
- var form RegisterForm
- handleRegisterError := func(errorMessage string, statusCode int) error {
- return TemplateErrorController(ctx, TemplateError{
- Template: config.TEMPLATE_REGISTER,
- ErrorMessage: errorMessage,
- StatusCode: statusCode,
- }, fiber.Map{
- "Username": form.Username,
- "Email": form.Email,
- })
- }
-
- if err := ctx.BodyParser(&form); err != nil {
- return handleRegisterError(config.ERR_INVALID_FORM_DATA, fiber.StatusBadRequest)
- }
-
- if form.Password != form.ConfirmPassword {
- return handleRegisterError(config.ERR_PASSWORD_MISMATCH, fiber.StatusBadRequest)
- }
-
- user := &models.User{
- Username: form.Username,
- Email: form.Email,
- Password: form.Password,
- PostsRequireApproval: true,
- Level: config.UserLevelMember,
- }
-
- if err := database.CreateUser(user); err != nil {
- var statusCode int
- if strings.Contains(err.Error(), "username") {
- statusCode = fiber.StatusConflict
- } else if strings.Contains(err.Error(), "email") {
- statusCode = fiber.StatusBadRequest
- } else {
- statusCode = fiber.StatusInternalServerError
- }
-
- return handleRegisterError(config.ERR_REGISTER_FAILED_TO_CREATE_USER+err.Error(), statusCode)
- }
-
- if err := email.SendVerificationEmail(user); err != nil {
- log.Printf("Failed to send verification email: %v", err)
- return handleRegisterError(config.ERR_REGISTER_USER_CREATED_EMAIL_FAILED, fiber.StatusInternalServerError)
- }
-
- return shortcuts.Render(ctx, config.TEMPLATE_REGISTER, fiber.Map{
- "Success": config.SUCCESS_USER_REGISTERED,
- })
-}