aboutsummaryrefslogtreecommitdiff
path: root/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'controllers')
-rw-r--r--controllers/404.go26
-rw-r--r--controllers/account.go30
-rw-r--r--controllers/errors.go61
-rw-r--r--controllers/login.go31
-rw-r--r--controllers/posts.go64
-rw-r--r--controllers/register.go27
6 files changed, 159 insertions, 80 deletions
diff --git a/controllers/404.go b/controllers/404.go
deleted file mode 100644
index 670f230..0000000
--- a/controllers/404.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package controllers
-
-import (
- "imageboard/utils/shortcuts"
- "strings"
-
- "github.com/gofiber/fiber/v2"
-)
-
-func NotFoundController(ctx *fiber.Ctx) error {
- ctx.Locals("Title", "Page Not Found")
-
- path := ctx.Path()
-
- if strings.HasSuffix(path, ".json") {
- return ctx.Status(fiber.StatusNotFound).JSON(fiber.Map{
- "error": "Not Found",
- })
- }
-
- if len(path) > 1 && strings.Contains(path[1:], ".") && !strings.HasSuffix(path, ".html") {
- return ctx.SendStatus(fiber.StatusNotFound)
- }
-
- return shortcuts.Render(ctx, "404", nil)
-}
diff --git a/controllers/account.go b/controllers/account.go
index 06e29d5..d59da8e 100644
--- a/controllers/account.go
+++ b/controllers/account.go
@@ -9,35 +9,45 @@ import (
"github.com/gofiber/fiber/v2"
)
-func renderVerifyEmailError(ctx *fiber.Ctx, errorMsg string, statusCode int) error {
- return shortcuts.RenderWithStatus(ctx, config.TEMPLATE_VERIFY_EMAIL, fiber.Map{
- "Error": errorMsg,
- }, statusCode)
-}
-
func VerifyEmailController(ctx *fiber.Ctx) error {
ctx.Locals("Title", config.PT_VERIFY_EMAIL)
if auth.IsAuthenticated(ctx) {
return ctx.Redirect(auth.GetRedirectURL(ctx), fiber.StatusSeeOther)
}
token := ctx.Query("token")
+ handleVerifyEmailError := func(errorMessage string, statusCode int) error {
+ return TemplateErrorController(ctx, TemplateError{
+ Template: config.TEMPLATE_VERIFY_EMAIL,
+ ErrorMessage: errorMessage,
+ StatusCode: statusCode,
+ }, nil)
+ }
+
if token == "" {
- return renderVerifyEmailError(ctx, config.ERR_VERIFY_EMAIL_MISSING_TOKEN, fiber.StatusBadRequest)
+ return handleVerifyEmailError(config.ERR_VERIFY_EMAIL_MISSING_TOKEN, fiber.StatusBadRequest)
}
emailToken, err := database.VerifyToken(token, config.EmailTokenTypeVerification)
if err != nil {
- return renderVerifyEmailError(ctx, config.ERR_VERIFY_EMAIL_INVALID_OR_EXPIRED_TOKEN, fiber.StatusBadRequest)
+ return handleVerifyEmailError(config.ERR_VERIFY_EMAIL_INVALID_OR_EXPIRED_TOKEN, fiber.StatusBadRequest)
}
user, err := database.GetUserByID(emailToken.UserID)
if err != nil {
- return renderVerifyEmailError(ctx, config.ERR_VERIFY_EMAIL_USER_NOT_FOUND, fiber.StatusInternalServerError)
+ if err.Error() == "record not found" {
+ return handleVerifyEmailError(config.ERR_VERIFY_EMAIL_USER_NOT_FOUND, fiber.StatusBadRequest)
+ }
+
+ return handleVerifyEmailError(config.ERR_VERIFY_EMAIL_ACTIVATION_FAILED, fiber.StatusInternalServerError)
}
user.Activate()
if err := database.DB.Save(user).Error; err != nil {
- return renderVerifyEmailError(ctx, config.ERR_VERIFY_EMAIL_ACTIVATION_FAILED, fiber.StatusInternalServerError)
+ if err.Error() == "record not found" {
+ return handleVerifyEmailError(config.ERR_VERIFY_EMAIL_USER_NOT_FOUND, fiber.StatusBadRequest)
+ }
+
+ return handleVerifyEmailError(config.ERR_VERIFY_EMAIL_ACTIVATION_FAILED, fiber.StatusInternalServerError)
}
return shortcuts.Render(ctx, config.TEMPLATE_VERIFY_EMAIL, fiber.Map{
diff --git a/controllers/errors.go b/controllers/errors.go
new file mode 100644
index 0000000..472a5a8
--- /dev/null
+++ b/controllers/errors.go
@@ -0,0 +1,61 @@
+package controllers
+
+import (
+ "errors"
+ "imageboard/config"
+ "imageboard/utils/shortcuts"
+ "strings"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+type TemplateError struct {
+ Template string
+ ErrorMessage string
+ StatusCode int
+}
+
+func TemplateErrorController(ctx *fiber.Ctx, err TemplateError, bind fiber.Map) error {
+ bind["Error"] = err.ErrorMessage
+ return shortcuts.RenderWithStatus(ctx, err.Template, bind, err.StatusCode)
+}
+
+func GenericErrorController(ctx *fiber.Ctx, title string, err error, statusCode int) error {
+ ctx.Locals("Title", title)
+
+ if strings.HasSuffix(ctx.Path(), ".json") {
+ return ctx.Status(statusCode).JSON(fiber.Map{
+ "error": err.Error(),
+ })
+ }
+
+ if len(ctx.Path()) > 1 && strings.Contains(ctx.Path()[1:], ".") && !strings.HasSuffix(ctx.Path(), ".html") {
+ return ctx.SendStatus(statusCode)
+ }
+
+ return shortcuts.RenderWithStatus(ctx, config.TEMPLATE_ERROR, fiber.Map{
+ "Title": title,
+ "Error": err.Error(),
+ }, statusCode)
+}
+
+func NotFoundController(ctx *fiber.Ctx) error {
+ error := errors.New("The page you are looking for does not exist.")
+ return GenericErrorController(ctx, "Page Not Found", error, fiber.StatusNotFound)
+}
+
+func InternalServerErrorController(ctx *fiber.Ctx, err error) error {
+ return GenericErrorController(ctx, "Internal Server Error", err, fiber.StatusInternalServerError)
+}
+
+func BadRequestController(ctx *fiber.Ctx, err error) error {
+ return GenericErrorController(ctx, "Bad Request", err, fiber.StatusBadRequest)
+}
+
+func UnauthorizedController(ctx *fiber.Ctx, err error) error {
+ return GenericErrorController(ctx, "Unauthorized", err, fiber.StatusUnauthorized)
+}
+
+func ForbiddenController(ctx *fiber.Ctx, err error) error {
+ return GenericErrorController(ctx, "Forbidden", err, fiber.StatusForbidden)
+}
diff --git a/controllers/login.go b/controllers/login.go
index aa02e0c..64ad047 100644
--- a/controllers/login.go
+++ b/controllers/login.go
@@ -15,13 +15,6 @@ type LoginForm struct {
Password string `json:"password" form:"password"`
}
-func renderLoginError(ctx *fiber.Ctx, errorMsg string, statusCode int) error {
- return shortcuts.RenderWithStatus(ctx, config.TEMPLATE_LOGIN, fiber.Map{
- "Error": errorMsg,
- "Username": ctx.FormValue("username"), // Preserve username in form
- }, statusCode)
-}
-
func LoginPageController(ctx *fiber.Ctx) error {
ctx.Locals("Title", config.PT_LOGIN)
@@ -40,35 +33,45 @@ func LoginPostController(ctx *fiber.Ctx) error {
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 renderLoginError(ctx, config.ERR_INVALID_FORM_DATA, fiber.StatusBadRequest)
+ return handleLoginError(config.ERR_INVALID_FORM_DATA, fiber.StatusBadRequest)
}
user, err := database.GetUserByUsername(form.Username)
if err != nil {
- return renderLoginError(ctx, config.ERR_USER_NOT_FOUND, fiber.StatusUnauthorized)
+ return handleLoginError(config.ERR_USER_NOT_FOUND, fiber.StatusUnauthorized)
}
if !user.CheckPassword(form.Password) {
- return renderLoginError(ctx, config.ERR_LOGIN_INVALID_CREDENTIALS, fiber.StatusUnauthorized)
+ return handleLoginError(config.ERR_LOGIN_INVALID_CREDENTIALS, fiber.StatusUnauthorized)
}
if !user.IsActive() {
- return renderLoginError(ctx, config.ERR_ACCOUNT_DISABLED, fiber.StatusForbidden)
+ return handleLoginError(config.ERR_ACCOUNT_DISABLED, fiber.StatusForbidden)
}
if !user.CanLogin() {
- return renderLoginError(ctx, config.ERR_ACCOUNT_UNABLE_TO_LOGIN, fiber.StatusForbidden)
+ return handleLoginError(config.ERR_ACCOUNT_UNABLE_TO_LOGIN, fiber.StatusForbidden)
}
sess, err := session.Store.Get(ctx)
if err != nil {
- return renderLoginError(ctx, config.ERR_SESSION_FAILED_TO_CREATE, fiber.StatusInternalServerError)
+ 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 renderLoginError(ctx, config.ERR_SESSION_FAILED_TO_SAVE, fiber.StatusInternalServerError)
+ return handleLoginError(config.ERR_SESSION_FAILED_TO_SAVE, fiber.StatusInternalServerError)
}
user.UpdateLastUserLogin(database.DB)
diff --git a/controllers/posts.go b/controllers/posts.go
index 41bbc86..038ca1f 100644
--- a/controllers/posts.go
+++ b/controllers/posts.go
@@ -1,6 +1,7 @@
package controllers
import (
+ "errors"
"imageboard/config"
"imageboard/database"
"imageboard/utils/auth"
@@ -10,7 +11,6 @@ import (
"imageboard/utils/shortcuts"
"imageboard/utils/transformers"
"io"
- "log"
"net/http"
"strings"
@@ -39,7 +39,7 @@ func PostsPageController(ctx *fiber.Ctx) error {
posts, err := database.GetPosts(preferences.PostsPerPage, queryRatings, queryTagsList)
if err != nil {
- log.Println(err)
+ return InternalServerErrorController(ctx, err)
}
return shortcuts.Render(ctx, config.TEMPLATE_POST_LIST, fiber.Map{
@@ -272,31 +272,25 @@ func PostsUploadImageLinkProxyController(ctx *fiber.Ctx) error {
return ctx.Send(buf)
}
-func renderSinglePostError(ctx *fiber.Ctx, errorMsg string, statusCode int) error {
- return shortcuts.RenderWithStatus(ctx, config.TEMPLATE_POST_SINGLE, fiber.Map{
- "Error": errorMsg,
- }, statusCode)
-}
-
func PostsSinglePostPageController(ctx *fiber.Ctx) error {
ctx.Locals("Title", config.PT_POST_SINGLE)
postID := ctx.Params("id")
if postID == "" {
- return renderSinglePostError(ctx, "Post ID is required", fiber.StatusBadRequest)
+ return NotFoundController(ctx)
}
uintPostID, err := format.StringToUint(postID)
if err != nil {
- return renderSinglePostError(ctx, "Invalid Post ID", fiber.StatusBadRequest)
+ return NotFoundController(ctx)
}
post, err := database.GetPostByID(uintPostID)
if err != nil {
if err.Error() == "record not found" {
- return renderSinglePostError(ctx, "Post not found", fiber.StatusNotFound)
+ return NotFoundController(ctx)
}
- return renderSinglePostError(ctx, "Failed to retrieve post. "+err.Error(), fiber.StatusInternalServerError)
+ return InternalServerErrorController(ctx, err)
}
currentUser := auth.GetCurrentUser(ctx)
@@ -320,30 +314,64 @@ func PostsSinglePostFavouriteController(ctx *fiber.Ctx) error {
postID := ctx.Params("id")
if postID == "" {
- return renderSinglePostError(ctx, "Post ID is required", fiber.StatusBadRequest)
+ return NotFoundController(ctx)
}
uintPostID, err := format.StringToUint(postID)
if err != nil {
- return renderSinglePostError(ctx, "Invalid Post ID", fiber.StatusBadRequest)
+ return NotFoundController(ctx)
}
post, err := database.GetPostByID(uintPostID)
if err != nil {
if err.Error() == "record not found" {
- return renderSinglePostError(ctx, "Post not found", fiber.StatusNotFound)
+ return NotFoundController(ctx)
}
- return renderSinglePostError(ctx, "Failed to retrieve post. "+err.Error(), fiber.StatusInternalServerError)
+ return InternalServerErrorController(ctx, err)
}
currentUser := auth.GetCurrentUser(ctx)
if currentUser == nil {
- return renderSinglePostError(ctx, "User not found", fiber.StatusUnauthorized)
+ return UnauthorizedController(ctx, errors.New("User not found"))
}
if err := post.ToggleFavourite(database.DB, currentUser); err != nil {
- return renderSinglePostError(ctx, "Failed to toggle favourite. "+err.Error(), fiber.StatusInternalServerError)
+ return InternalServerErrorController(ctx, err)
}
return ctx.Redirect("/posts/" + postID)
}
+
+func PostsSinglePostEditController(ctx *fiber.Ctx) error {
+ if !auth.IsAuthenticated(ctx) {
+ return ctx.Redirect(auth.GetLoginURLWithNextField(ctx), fiber.StatusFound)
+ }
+
+ postID := ctx.Params("id")
+ if postID == "" {
+ return NotFoundController(ctx)
+ }
+
+ uintPostID, err := format.StringToUint(postID)
+ if err != nil {
+ return NotFoundController(ctx)
+ }
+
+ post, err := database.GetPostByID(uintPostID)
+ if err != nil {
+ if err.Error() == "record not found" {
+ return NotFoundController(ctx)
+ }
+ return InternalServerErrorController(ctx, err)
+ }
+
+ if post.Uploader.Username != auth.GetCurrentUser(ctx).Username || !auth.GetCurrentUser(ctx).CanEditPosts() {
+ return ForbiddenController(ctx, errors.New("You do not have permission to edit this post"))
+ }
+
+ ctx.Locals("Title", config.PT_POST_EDIT+" #"+format.Int64ToString(int64(post.ID)))
+ return shortcuts.Render(ctx, config.TEMPLATE_POST_EDIT, fiber.Map{
+ "Post": post,
+ "CDNURL": format.GetCDNURL(),
+ })
+}
diff --git a/controllers/register.go b/controllers/register.go
index c52d6e5..8952c91 100644
--- a/controllers/register.go
+++ b/controllers/register.go
@@ -20,14 +20,6 @@ type RegisterForm struct {
ConfirmPassword string `json:"confirm_password" form:"confirm_password"`
}
-func renderRegisterError(ctx *fiber.Ctx, errorMsg string, statusCode int) error {
- return shortcuts.RenderWithStatus(ctx, config.TEMPLATE_REGISTER, fiber.Map{
- "Error": errorMsg,
- "Username": ctx.FormValue("username"),
- "Email": ctx.FormValue("email"),
- }, statusCode)
-}
-
func RegisterPageController(ctx *fiber.Ctx) error {
ctx.Locals("Title", config.PT_REGISTER)
@@ -46,12 +38,23 @@ func RegisterPostController(ctx *fiber.Ctx) error {
}
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 renderRegisterError(ctx, config.ERR_INVALID_FORM_DATA, fiber.StatusBadRequest)
+ return handleRegisterError(config.ERR_INVALID_FORM_DATA, fiber.StatusBadRequest)
}
if form.Password != form.ConfirmPassword {
- return renderRegisterError(ctx, config.ERR_PASSWORD_MISMATCH, fiber.StatusBadRequest)
+ return handleRegisterError(config.ERR_PASSWORD_MISMATCH, fiber.StatusBadRequest)
}
user := &models.User{
@@ -70,12 +73,12 @@ func RegisterPostController(ctx *fiber.Ctx) error {
statusCode = fiber.StatusInternalServerError
}
- return renderRegisterError(ctx, "Failed to create user: "+err.Error(), statusCode)
+ 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 renderRegisterError(ctx, "User created but failed to send verification email", fiber.StatusInternalServerError)
+ return handleRegisterError(config.ERR_REGISTER_USER_CREATED_EMAIL_FAILED, fiber.StatusInternalServerError)
}
return shortcuts.Render(ctx, config.TEMPLATE_REGISTER, fiber.Map{