refac: separated api content into sub-packages & renamed usecases

This commit is contained in:
Florian Sylvain
2025-03-13 19:43:12 +01:00
parent 7e29c08ea9
commit 4d6054e22b
38 changed files with 181 additions and 152 deletions
+1
View File
@@ -12,3 +12,4 @@ bin
.env
tmp/
uploadedImages/
+26 -24
View File
@@ -1,16 +1,18 @@
package api
package auth
import (
"GoCMS/api"
"GoCMS/domain/user"
"GoCMS/useCases"
"encoding/json"
"net/http"
"os"
"time"
"github.com/go-chi/chi/v5"
"github.com/go-chi/jwtauth/v5"
"github.com/google/uuid"
"golang.org/x/crypto/bcrypt"
"net/http"
"os"
"time"
)
type RegisterCredentials struct {
@@ -25,14 +27,14 @@ type LoginCredentials struct {
}
var shouldCookieBeSecure = os.Getenv("ENVIRONMENT") == "production"
var TokenAuth *jwtauth.JWTAuth
var Token *jwtauth.JWTAuth
// TODO Move into its own file or package that handles api errors
const logsErrorMessage = "Access to the requested resource is forbidden due to incorrect password and/or username."
const bodyErrorMessage = "The request cannot be processed due to a mismatch in the format of the body."
const LogsErrorMessage = "Access to the requested resource is forbidden due to incorrect password and/or username."
const BodyErrorMessage = "The request cannot be processed due to a mismatch in the format of the body."
func SetJwtCookie(w *http.ResponseWriter, userId uint32) error {
_, tokenString, err := TokenAuth.Encode(map[string]interface{}{"user_id": userId})
_, tokenString, err := Token.Encode(map[string]interface{}{"user_id": userId})
if err != nil {
return err
}
@@ -48,7 +50,7 @@ func SetJwtCookie(w *http.ResponseWriter, userId uint32) error {
}
func SomeUsersVerified() bool {
users := Container.ListUsersUseCase.ListUsers()
users := api.Container.ListUsersUseCase.ListUsers()
for _, localUser := range users {
if localUser.IsVerified {
return true
@@ -58,13 +60,13 @@ func SomeUsersVerified() bool {
}
func IsUserTableEmpty() bool {
users := Container.ListUsersUseCase.ListUsers()
users := api.Container.ListUsersUseCase.ListUsers()
return len(users) == 0
}
func IsLoggedIn(r *http.Request) bool {
token, err := jwtauth.VerifyRequest(
TokenAuth,
Token,
r,
jwtauth.TokenFromCookie,
jwtauth.TokenFromHeader,
@@ -74,7 +76,7 @@ func IsLoggedIn(r *http.Request) bool {
func IsVerified(r *http.Request) bool {
token, err := jwtauth.VerifyRequest(
TokenAuth,
Token,
r,
jwtauth.TokenFromCookie,
jwtauth.TokenFromHeader,
@@ -83,12 +85,12 @@ func IsVerified(r *http.Request) bool {
return false
}
userId := token.PrivateClaims()["user_id"].(float64)
currentUser, _ := Container.GetUserUseCase.GetUser(uint32(userId))
currentUser, _ := api.Container.GetUserUseCase.GetUser(uint32(userId))
return currentUser.IsVerified
}
func getUserFromCredentials(credentials LoginCredentials) (user.User, error) {
dbUser, err := Container.GetUserUseCase.GetUserByUsername(credentials.Username)
func GetUserFromCredentials(credentials LoginCredentials) (user.User, error) {
dbUser, err := api.Container.GetUserUseCase.GetUserByUsername(credentials.Username)
if err != nil {
return user.User{}, err
}
@@ -101,8 +103,8 @@ func getUserFromCredentials(credentials LoginCredentials) (user.User, error) {
return dbUser, nil
}
func getNewUser(newUserCredentials RegisterCredentials, verificationCode string) (user.User, error) {
createdUser, err := Container.CreateUserUseCase.CreateUser(useCases.CreateUserCommand{
func GetNewUser(newUserCredentials RegisterCredentials, verificationCode string) (user.User, error) {
createdUser, err := api.Container.CreateUserUseCase.CreateUser(useCases.CreateUserCommand{
Username: newUserCredentials.Username,
Password: newUserCredentials.Password,
Email: newUserCredentials.Email,
@@ -119,19 +121,19 @@ func login(w http.ResponseWriter, r *http.Request) {
err := json.NewDecoder(r.Body).Decode(&credentials)
if err != nil {
http.Error(w, bodyErrorMessage, http.StatusBadRequest)
http.Error(w, BodyErrorMessage, http.StatusBadRequest)
return
}
err = validate.Struct(credentials)
err = api.Validate.Struct(credentials)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
dbUser, err := getUserFromCredentials(credentials)
dbUser, err := GetUserFromCredentials(credentials)
if err != nil {
http.Error(w, logsErrorMessage, http.StatusForbidden)
http.Error(w, LogsErrorMessage, http.StatusForbidden)
}
_ = SetJwtCookie(&w, dbUser.ID)
@@ -149,18 +151,18 @@ func register(w http.ResponseWriter, r *http.Request) {
var credentials RegisterCredentials
err := json.NewDecoder(r.Body).Decode(&credentials)
if err != nil {
http.Error(w, bodyErrorMessage, http.StatusBadRequest)
http.Error(w, BodyErrorMessage, http.StatusBadRequest)
return
}
err = validate.Struct(credentials)
err = api.Validate.Struct(credentials)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
verificationCode := uuid.NewString()
createdUser, err := getNewUser(credentials, verificationCode)
createdUser, err := GetNewUser(credentials, verificationCode)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@@ -1,13 +1,15 @@
package api
package image
import (
"GoCMS/api"
"encoding/json"
"github.com/go-chi/chi/v5"
"net/http"
"strconv"
"github.com/go-chi/chi/v5"
)
func postImage(w http.ResponseWriter, r *http.Request) {
func PostImage(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
id := chi.URLParam(r, "id")
@@ -19,13 +21,13 @@ func postImage(w http.ResponseWriter, r *http.Request) {
return
}
newImage, err := Container.CreateImageUseCase.CreateImage(file, *fileHeader)
newImage, err := api.Container.CreateImageUseCase.CreateImage(file, *fileHeader)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
err = Container.UpdatePostUseCase.AddImage(uint32(idInt), newImage.ID)
err = api.Container.UpdatePostUseCase.AddImage(uint32(idInt), newImage.ID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@@ -1,13 +1,14 @@
package api
package pages
import (
"GoCMS/api"
"html/template"
"net/http"
)
func GetHomePage(w http.ResponseWriter, _ *http.Request) {
navbarTmpl, _ := Container.GetPageUseCase.GetPage("componentNavbar", nil)
homeTmpl, _ := Container.GetPageUseCase.GetPage("home", map[string]interface{}{
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
homeTmpl, _ := api.Container.GetPageUseCase.GetPage("home", map[string]interface{}{
"Navbar": template.HTML(navbarTmpl),
"Head": headTmpl,
})
@@ -1,14 +1,15 @@
package api
package pages
import (
"GoCMS/api"
"html/template"
"net/http"
"os"
)
func GetPageIntegration(w http.ResponseWriter, r *http.Request) {
navbarTmpl, _ := Container.GetPageUseCase.GetPage("componentNavbar", nil)
templ, _ := Container.GetPageUseCase.GetPage("integration", map[string]interface{}{
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
templ, _ := api.Container.GetPageUseCase.GetPage("integration", map[string]interface{}{
"Navbar": template.HTML(navbarTmpl),
"Head": headTmpl,
"Host": os.Getenv("HOST"),
@@ -1,6 +1,8 @@
package api
package pages
import (
"GoCMS/api"
"GoCMS/api/controllers/auth"
"net/http"
"net/url"
)
@@ -19,7 +21,7 @@ var EmptyLoginPage = &LoginPage{
func GetLoginPageHandler(loginPage *LoginPage) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if IsLoggedIn(r) {
if auth.IsLoggedIn(r) {
http.Redirect(w, r, "/home", http.StatusSeeOther)
return
}
@@ -27,13 +29,13 @@ func GetLoginPageHandler(loginPage *LoginPage) http.HandlerFunc {
PostLoginPage(w, r)
return
}
if IsUserTableEmpty() {
if auth.IsUserTableEmpty() {
http.Redirect(w, r, "/register", http.StatusSeeOther)
return
}
success, _ := url.QueryUnescape(r.URL.Query().Get("success"))
failure, _ := url.QueryUnescape(r.URL.Query().Get("failure"))
bs, _ := Container.GetPageUseCase.GetPage("login", map[string]interface{}{
bs, _ := api.Container.GetPageUseCase.GetPage("login", map[string]interface{}{
"PageError": loginPage.PageError,
"Username": loginPage.Username,
"Head": headTmpl,
@@ -47,11 +49,11 @@ func GetLoginPageHandler(loginPage *LoginPage) http.HandlerFunc {
func PostLoginPage(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
credentials := LoginCredentials{
credentials := auth.LoginCredentials{
Username: r.FormValue("username"),
Password: r.FormValue("password"),
}
err := validate.Struct(credentials)
err := api.Validate.Struct(credentials)
if err != nil {
r.Method = http.MethodGet
GetLoginPageHandler(&LoginPage{
@@ -61,7 +63,7 @@ func PostLoginPage(w http.ResponseWriter, r *http.Request) {
return
}
dbUser, err := getUserFromCredentials(credentials)
dbUser, err := auth.GetUserFromCredentials(credentials)
if err != nil {
r.Method = http.MethodGet
GetLoginPageHandler(&LoginPage{
@@ -71,7 +73,7 @@ func PostLoginPage(w http.ResponseWriter, r *http.Request) {
return
}
_ = SetJwtCookie(&w, dbUser.ID)
_ = auth.SetJwtCookie(&w, dbUser.ID)
http.Redirect(w, r, "/home", http.StatusSeeOther)
}
+12 -8
View File
@@ -1,12 +1,16 @@
package api
package pages
import (
"github.com/go-chi/chi/v5"
"GoCMS/api"
"GoCMS/api/controllers/auth"
"GoCMS/api/controllers/image"
"html/template"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/go-chi/chi/v5"
)
var headTmpl template.HTML
@@ -35,7 +39,7 @@ func NewPageError(message string) *PageError {
func IsLoggedInMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !IsLoggedIn(r) {
if !auth.IsLoggedIn(r) {
http.Redirect(w, r, LoginRoute, http.StatusSeeOther)
return
}
@@ -45,7 +49,7 @@ func IsLoggedInMiddleware(next http.Handler) http.Handler {
func IsVerifiedMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !IsVerified(r) {
if !auth.IsVerified(r) {
http.Redirect(w, r, "/register/pending", http.StatusSeeOther)
return
}
@@ -55,7 +59,7 @@ func IsVerifiedMiddleware(next http.Handler) http.Handler {
func IsNotVerifiedMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if IsVerified(r) {
if auth.IsVerified(r) {
http.Redirect(w, r, "/register/pending", http.StatusSeeOther)
return
}
@@ -68,7 +72,7 @@ func GetLogin(w http.ResponseWriter, r *http.Request) {
}
func GetLogout(w http.ResponseWriter, r *http.Request) {
RemoveJwtCookie(w)
auth.RemoveJwtCookie(w)
http.Redirect(w, r, LoginRoute, http.StatusSeeOther)
}
@@ -92,7 +96,7 @@ func StaticFileServerWithContentType(fsys http.FileSystem) http.Handler {
}
func InitHeadTmpl() {
headTmplHtml, _ := Container.GetPageUseCase.GetPage("utilsHead", nil)
headTmplHtml, _ := api.Container.GetPageUseCase.GetPage("utilsHead", nil)
headTmpl = template.HTML(headTmplHtml)
}
@@ -146,7 +150,7 @@ func NewPageRouter() http.Handler {
r.Get("/post/create", GetPostCreatePage)
r.Post("/post/create", PostPostCreatePage)
r.Post("/post/{id}/image/create", postImage)
r.Post("/post/{id}/image/create", image.PostImage)
r.Get("/post/{id}/publish", GetPostPublishPage)
r.Get("/post/{id}/unpublish", GetPostUnpublishPage)
@@ -1,9 +1,11 @@
package api
package pages
import (
"github.com/google/uuid"
"GoCMS/api"
"net/http"
"os"
"github.com/google/uuid"
)
type PasswordResetRequest struct {
@@ -16,7 +18,7 @@ func GetPasswordResetRequest(w http.ResponseWriter, r *http.Request) {
success := r.URL.Query().Get("success")
email := r.URL.Query().Get("email")
bs, _ := Container.GetPageUseCase.GetPage("passwordResetRequest", map[string]interface{}{
bs, _ := api.Container.GetPageUseCase.GetPage("passwordResetRequest", map[string]interface{}{
"Head": headTmpl,
"Email": email,
"Success": success,
@@ -31,22 +33,22 @@ func PostPasswordResetRequest(w http.ResponseWriter, r *http.Request) {
}
var getRedirectUrl = "/register/reset/request?success=" + successMessage + "&email=" + passResetReq.Email
err := validate.Struct(passResetReq)
err := api.Validate.Struct(passResetReq)
if err != nil {
http.Redirect(w, r, getRedirectUrl, http.StatusSeeOther)
return
}
fetchedUser, err := Container.GetUserUseCase.GetUserByEmail(passResetReq.Email)
fetchedUser, err := api.Container.GetUserUseCase.GetUserByEmail(passResetReq.Email)
if err != nil {
http.Redirect(w, r, getRedirectUrl, http.StatusSeeOther)
return
}
verificationCode := uuid.NewString()
updatedUser, _ := Container.UpdateUserUseCase.UpdatePasswordResetCode(fetchedUser.ID, verificationCode)
updatedUser, _ := api.Container.UpdateUserUseCase.UpdatePasswordResetCode(fetchedUser.ID, verificationCode)
_ = Container.SendMailUseCase.SendMail(updatedUser.Email, "passwordReset", map[string]string{
_ = api.Container.SendMailUseCase.SendMail(updatedUser.Email, "passwordReset", map[string]string{
"Host": os.Getenv("HOST"),
"VerificationCode": verificationCode,
"Email": updatedUser.Email,
@@ -1,8 +1,10 @@
package api
package pages
import (
"golang.org/x/crypto/bcrypt"
"GoCMS/api"
"net/http"
"golang.org/x/crypto/bcrypt"
)
var PasswordLinkErrorMessage = "The reset password link you used is invalid."
@@ -14,7 +16,7 @@ func GetPasswordResetValidate(w http.ResponseWriter, r *http.Request) {
if failure != "" {
pageError = NewPageError(failure)
}
template, _ := Container.GetPageUseCase.GetPage("passwordResetValidate", map[string]interface{}{
template, _ := api.Container.GetPageUseCase.GetPage("passwordResetValidate", map[string]interface{}{
"Head": headTmpl,
"Error": pageError,
"Email": r.URL.Query().Get("email"),
@@ -36,7 +38,7 @@ func PostPasswordResetValidate(w http.ResponseWriter, r *http.Request) {
return
}
fetchedUser, err := Container.GetUserUseCase.GetUserByEmail(email)
fetchedUser, err := api.Container.GetUserUseCase.GetUserByEmail(email)
if err != nil {
http.Redirect(w, r, redirectionErrorLink+"&failure="+PasswordLinkErrorMessage, http.StatusSeeOther)
return
@@ -48,8 +50,8 @@ func PostPasswordResetValidate(w http.ResponseWriter, r *http.Request) {
return
}
_, _ = Container.UpdateUserUseCase.UpdatePassword(fetchedUser.ID, password)
_, _ = Container.UpdateUserUseCase.UpdatePasswordResetCode(fetchedUser.ID, "")
_, _ = api.Container.UpdateUserUseCase.UpdatePassword(fetchedUser.ID, password)
_, _ = api.Container.UpdateUserUseCase.UpdatePasswordResetCode(fetchedUser.ID, "")
http.Redirect(w, r, "/login?success="+PasswordLinkSuccessMessage, http.StatusSeeOther)
}
@@ -1,6 +1,7 @@
package api
package pages
import (
"GoCMS/api"
"GoCMS/useCases"
"html/template"
"net/http"
@@ -14,8 +15,8 @@ type PostCreatePageError struct {
}
func GetPostCreatePageTemplate(postName string, errorMessage string) ([]byte, error) {
navbarTmpl, _ := Container.GetPageUseCase.GetPage("componentNavbar", nil)
return Container.GetPageUseCase.GetPage("postCreate", map[string]interface{}{
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
return api.Container.GetPageUseCase.GetPage("postCreate", map[string]interface{}{
"Navbar": template.HTML(navbarTmpl),
"Head": headTmpl,
"PageError": PostCreatePageError{
@@ -38,7 +39,7 @@ func PostPostCreatePage(w http.ResponseWriter, r *http.Request) {
return
}
post, err := Container.CreatePostUseCase.CreatePost(useCases.CreatePostCommand{
post, err := api.Container.CreatePostUseCase.CreatePost(useCases.CreatePostCommand{
Title: postName,
Body: "",
})
@@ -1,20 +1,23 @@
package api
package pages
import (
"GoCMS/api"
"GoCMS/api/controllers/post"
"fmt"
"github.com/go-chi/chi/v5"
"net/http"
"strconv"
"github.com/go-chi/chi/v5"
)
func GetPostDeletePage(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 32)
if err != nil {
http.Error(w, idUint32ErrorMessage, http.StatusBadRequest)
http.Error(w, post.IdUint32ErrorMessage, http.StatusBadRequest)
return
}
localPost, err := Container.GetPostUseCase.GetPost(uint32(id))
localPost, err := api.Container.GetPostUseCase.GetPost(uint32(id))
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
@@ -22,14 +25,14 @@ func GetPostDeletePage(w http.ResponseWriter, r *http.Request) {
fmt.Println(localPost.Images)
for _, image := range localPost.Images {
err = Container.DeleteImageUseCase.DeleteImage(image.ID)
err = api.Container.DeleteImageUseCase.DeleteImage(image.ID)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
}
err = Container.DeletePostUseCase.DeletePost(uint32(id))
err = api.Container.DeletePostUseCase.DeletePost(uint32(id))
if err != nil {
http.Error(w, http.StatusText(400), http.StatusBadRequest)
return
@@ -1,12 +1,14 @@
package api
package pages
import (
"GoCMS/api"
"GoCMS/domain/post"
"github.com/go-chi/chi/v5"
"html/template"
"net/http"
"os"
"strconv"
"github.com/go-chi/chi/v5"
)
type PostEditPageAlert struct {
@@ -15,8 +17,8 @@ type PostEditPageAlert struct {
}
func getPostEditPageTemplate(post post.Post, alert PostEditPageAlert) []byte {
navbarTmpl, _ := Container.GetPageUseCase.GetPage("componentNavbar", nil)
postTmpl, _ := Container.GetPageUseCase.GetPage("postEdit", map[string]interface{}{
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
postTmpl, _ := api.Container.GetPageUseCase.GetPage("postEdit", map[string]interface{}{
"Navbar": template.HTML(navbarTmpl),
"Head": headTmpl,
"Post": post,
@@ -40,8 +42,8 @@ func PostPostEditPage(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
postBody := r.FormValue("postBody")
getPost, _ := Container.GetPostUseCase.GetPost(uint32(postIDint))
updatedPost, err := Container.UpdatePostUseCase.UpdateBody(getPost.ID, postBody)
getPost, _ := api.Container.GetPostUseCase.GetPost(uint32(postIDint))
updatedPost, err := api.Container.UpdatePostUseCase.UpdateBody(getPost.ID, postBody)
if err != nil {
_, _ = w.Write(getPostEditPageTemplate(post.Post{Body: postBody}, PostEditPageAlert{
IsError: true,
@@ -64,7 +66,7 @@ func GetPostEditPage(w http.ResponseWriter, r *http.Request) {
return
}
getPost, _ := Container.GetPostUseCase.GetPost(uint32(postIDint))
getPost, _ := api.Container.GetPostUseCase.GetPost(uint32(postIDint))
_, _ = w.Write(getPostEditPageTemplate(getPost, PostEditPageAlert{
IsError: false,
@@ -1,10 +1,12 @@
package api
package pages
import (
"GoCMS/api"
"errors"
"github.com/go-chi/chi/v5"
"net/http"
"strconv"
"github.com/go-chi/chi/v5"
)
func updateIsOnline(postId string, isOnline bool) (error, int) {
@@ -13,7 +15,7 @@ func updateIsOnline(postId string, isOnline bool) (error, int) {
return errors.New("the server expects the ID to be in the format of an unsigned 32-bit integer (uint32)"), http.StatusBadRequest
}
_, err = Container.UpdatePostUseCase.UpdateIsOnline(uint32(postIdInt), isOnline)
_, err = api.Container.UpdatePostUseCase.UpdateIsOnline(uint32(postIdInt), isOnline)
if err != nil {
return errors.New("the requested resource, identified by its unique ID, could not be found on the server"), http.StatusNotFound
}
@@ -1,12 +1,13 @@
package api
package pages
import (
"GoCMS/api"
"html/template"
"net/http"
)
func GetPostsPage(w http.ResponseWriter, _ *http.Request) {
posts := Container.ListPostsUseCase.ListPosts()
posts := api.Container.ListPostsUseCase.ListPosts()
var formattedPosts []map[string]interface{}
for _, post := range posts {
@@ -19,8 +20,8 @@ func GetPostsPage(w http.ResponseWriter, _ *http.Request) {
})
}
navbarTmpl, _ := Container.GetPageUseCase.GetPage("componentNavbar", nil)
postsTmpl, _ := Container.GetPageUseCase.GetPage("posts", map[string]interface{}{
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
postsTmpl, _ := api.Container.GetPageUseCase.GetPage("posts", map[string]interface{}{
"Navbar": template.HTML(navbarTmpl),
"Head": headTmpl,
"Posts": formattedPosts,
@@ -1,9 +1,12 @@
package api
package pages
import (
"github.com/google/uuid"
"GoCMS/api"
"GoCMS/api/controllers/auth"
"net/http"
"os"
"github.com/google/uuid"
)
type RegisterPageError struct {
@@ -30,10 +33,10 @@ var EmptyRegisterPage = &RegisterPage{
func GetRegisterPageHandler(registerPage *RegisterPage) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !IsLoggedIn(r) && SomeUsersVerified() {
if !auth.IsLoggedIn(r) && auth.SomeUsersVerified() {
http.Redirect(w, r, "/login?failure=There is already a verified account, please login.", http.StatusSeeOther)
}
if (IsLoggedIn(r) && IsVerified(r)) || SomeUsersVerified() {
if (auth.IsLoggedIn(r) && auth.IsVerified(r)) || auth.SomeUsersVerified() {
http.Redirect(w, r, "/home", http.StatusSeeOther)
return
}
@@ -41,7 +44,7 @@ func GetRegisterPageHandler(registerPage *RegisterPage) http.HandlerFunc {
PostRegisterPage(w, r)
return
}
bs, err := Container.GetPageUseCase.GetPage("register", map[string]interface{}{
bs, err := api.Container.GetPageUseCase.GetPage("register", map[string]interface{}{
"PageError": registerPage.PageError,
"Username": registerPage.Username,
"Email": registerPage.Email,
@@ -57,12 +60,12 @@ func GetRegisterPageHandler(registerPage *RegisterPage) http.HandlerFunc {
func PostRegisterPage(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
credentials := RegisterCredentials{
credentials := auth.RegisterCredentials{
Username: r.FormValue("username"),
Password: r.FormValue("password"),
Email: r.FormValue("email"),
}
err := validate.Struct(credentials)
err := api.Validate.Struct(credentials)
if err != nil {
r.Method = http.MethodGet
GetRegisterPageHandler(&RegisterPage{
@@ -78,7 +81,7 @@ func PostRegisterPage(w http.ResponseWriter, r *http.Request) {
}
verificationCode := uuid.NewString()
createdUser, err := getNewUser(credentials, verificationCode)
createdUser, err := auth.GetNewUser(credentials, verificationCode)
if err != nil {
r.Method = http.MethodGet
GetRegisterPageHandler(&RegisterPage{
@@ -93,12 +96,12 @@ func PostRegisterPage(w http.ResponseWriter, r *http.Request) {
return
}
_ = Container.SendMailUseCase.SendMail(createdUser.Email, "mailValidation", map[string]string{
_ = api.Container.SendMailUseCase.SendMail(createdUser.Email, "mailValidation", map[string]string{
"Host": os.Getenv("HOST"),
"VerificationCode": verificationCode,
})
_ = SetJwtCookie(&w, createdUser.ID)
_ = auth.SetJwtCookie(&w, createdUser.ID)
http.Redirect(w, r, "/register/pending", http.StatusSeeOther)
}
@@ -1,32 +1,35 @@
package api
package pages
import (
"github.com/go-chi/jwtauth/v5"
"GoCMS/api"
"GoCMS/api/controllers/auth"
"log"
"net/http"
"github.com/go-chi/jwtauth/v5"
)
func PostRegisterPendingPage(w http.ResponseWriter, r *http.Request) {
token, _ := jwtauth.VerifyRequest(
TokenAuth, r,
auth.Token, r,
jwtauth.TokenFromCookie,
jwtauth.TokenFromHeader,
jwtauth.TokenFromQuery)
userId := token.PrivateClaims()["user_id"].(float64)
err := Container.DeleteUserUseCase.DeleteUser(uint32(userId))
err := api.Container.DeleteUserUseCase.DeleteUser(uint32(userId))
if err != nil {
log.Println(err)
r.Method = http.MethodGet
http.Redirect(w, r, "/register/pending", http.StatusSeeOther)
}
RemoveJwtCookie(w)
auth.RemoveJwtCookie(w)
http.Redirect(w, r, "/register", http.StatusSeeOther)
}
func GetRegisterPendingPage(w http.ResponseWriter, _ *http.Request) {
registerPendingTmpl, _ := Container.GetPageUseCase.GetPage("registerPending", map[string]interface{}{
registerPendingTmpl, _ := api.Container.GetPageUseCase.GetPage("registerPending", map[string]interface{}{
"Head": headTmpl,
})
_, _ = w.Write(registerPendingTmpl)
@@ -1,10 +1,13 @@
package api
package pages
import (
"github.com/go-chi/jwtauth/v5"
"golang.org/x/crypto/bcrypt"
"GoCMS/api"
"GoCMS/api/controllers/auth"
"net/http"
"time"
"github.com/go-chi/jwtauth/v5"
"golang.org/x/crypto/bcrypt"
)
func GetRegisterValidatePage(w http.ResponseWriter, r *http.Request) {
@@ -15,27 +18,27 @@ func GetRegisterValidatePage(w http.ResponseWriter, r *http.Request) {
}
token, _ := jwtauth.VerifyRequest(
TokenAuth,
auth.Token,
r,
jwtauth.TokenFromCookie,
jwtauth.TokenFromHeader,
jwtauth.TokenFromQuery)
userId := token.PrivateClaims()["user_id"].(float64)
user, _ := Container.GetUserUseCase.GetUser(uint32(userId))
user, _ := api.Container.GetUserUseCase.GetUser(uint32(userId))
errorMessage := ""
err := bcrypt.CompareHashAndPassword([]byte(user.VerificationCode), []byte(queryVerificationCode))
if err != nil || user.VerificationExpiration.Before(time.Now()) {
errorMessage = "Verification link is incorrect or has expired."
} else {
_, err := Container.UpdateUserUseCase.UpdateVerificationStatus(user.ID, true)
_, err := api.Container.UpdateUserUseCase.UpdateVerificationStatus(user.ID, true)
if err != nil {
errorMessage = "Something went wrong server-side. User account may not exist."
}
}
registerValidateTmpl, _ := Container.GetPageUseCase.GetPage("registerValidate", map[string]interface{}{
registerValidateTmpl, _ := api.Container.GetPageUseCase.GetPage("registerValidate", map[string]interface{}{
"Head": headTmpl,
"PageError": NewPageError(errorMessage),
})
+14 -11
View File
@@ -1,12 +1,15 @@
package api
package post
import (
"GoCMS/api"
"GoCMS/api/controllers/auth"
"GoCMS/domain/post"
"GoCMS/useCases"
"encoding/json"
"github.com/go-chi/chi/v5"
"net/http"
"strconv"
"github.com/go-chi/chi/v5"
)
type PostPost struct {
@@ -14,16 +17,16 @@ type PostPost struct {
Body string `json:"body" validate:"required,max=10000"`
}
const idUint32ErrorMessage = "The server expects the ID to be in the format of an unsigned 32-bit integer (uint32)."
const IdUint32ErrorMessage = "The server expects the ID to be in the format of an unsigned 32-bit integer (uint32)."
func getPost(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 32)
if err != nil {
http.Error(w, idUint32ErrorMessage, http.StatusBadRequest)
http.Error(w, IdUint32ErrorMessage, http.StatusBadRequest)
return
}
localPost, err := Container.GetPostUseCase.GetPost(uint32(id))
localPost, err := api.Container.GetPostUseCase.GetPost(uint32(id))
if err != nil || !localPost.IsOnline {
http.Error(w, "The requested resource, identified by its unique ID, could not be found on the server.", http.StatusNotFound)
return
@@ -37,17 +40,17 @@ func postPost(w http.ResponseWriter, r *http.Request) {
var localPost PostPost
err := json.NewDecoder(r.Body).Decode(&localPost)
if err != nil {
http.Error(w, bodyErrorMessage, http.StatusBadRequest)
http.Error(w, auth.BodyErrorMessage, http.StatusBadRequest)
return
}
err = validate.Struct(localPost)
err = api.Validate.Struct(localPost)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
createdPost, err := Container.CreatePostUseCase.CreatePost(useCases.CreatePostCommand{
createdPost, err := api.Container.CreatePostUseCase.CreatePost(useCases.CreatePostCommand{
Title: localPost.Title,
Body: localPost.Body,
})
@@ -61,7 +64,7 @@ func postPost(w http.ResponseWriter, r *http.Request) {
}
func listPosts(w http.ResponseWriter, _ *http.Request) {
posts := Container.ListPostsUseCase.ListPosts()
posts := api.Container.ListPostsUseCase.ListPosts()
onlinePosts := make([]post.Post, 0)
for _, localPost := range posts {
if localPost.IsOnline {
@@ -75,10 +78,10 @@ func listPosts(w http.ResponseWriter, _ *http.Request) {
func deletePost(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 32)
if err != nil {
http.Error(w, idUint32ErrorMessage, http.StatusBadRequest)
http.Error(w, IdUint32ErrorMessage, http.StatusBadRequest)
}
err = Container.DeletePostUseCase.DeletePost(uint32(id))
err = api.Container.DeletePostUseCase.DeletePost(uint32(id))
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
}
+2 -2
View File
@@ -2,8 +2,8 @@ package api
import "github.com/go-playground/validator/v10"
var validate *validator.Validate
var Validate *validator.Validate
func InitValidator() {
validate = validator.New()
Validate = validator.New()
}
+1 -2
View File
@@ -8,6 +8,7 @@ require (
github.com/go-chi/cors v1.2.1
github.com/go-chi/jwtauth/v5 v5.3.1
github.com/go-playground/validator/v10 v10.20.0
github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1
github.com/stretchr/testify v1.9.0
go.uber.org/dig v1.17.1
@@ -18,7 +19,6 @@ require (
require (
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect
github.com/beevik/guid v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
@@ -28,7 +28,6 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/text v0.2.0 // indirect
-12
View File
@@ -2,8 +2,6 @@ github.com/MadAppGang/httplog v1.3.0 h1:1XU54TO8kiqTeO+7oZLKAM3RP/cJ7SadzslRcKsp
github.com/MadAppGang/httplog v1.3.0/go.mod h1:gpYEdkjh/Cda6YxtDy4AB7KY+fR7mb3SqBZw74A5hJ4=
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4=
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w=
github.com/beevik/guid v1.0.0 h1:XhTlrl9h5+TlkB7MB3SBwAm2+ZdFE62O0D+g7LDFqqI=
github.com/beevik/guid v1.0.0/go.mod h1:FyB4y08P/8c0J0xhRHR6xVjdXIpGDwpMXzmGV6vWDj4=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -36,8 +34,6 @@ github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaC
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8=
@@ -56,14 +52,10 @@ github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8=
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/httprc v1.0.5 h1:bsTfiH8xaKOJPrg1R+E3iE/AWZr/x0Phj9PBTG/OLUk=
github.com/lestrrat-go/httprc v1.0.5/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
github.com/lestrrat-go/jwx/v2 v2.0.20 h1:sAgXuWS/t8ykxS9Bi2Qtn5Qhpakw1wrcjxChudjolCc=
github.com/lestrrat-go/jwx/v2 v2.0.20/go.mod h1:UlCSmKqw+agm5BsOBfEAbTvKsEApaGNqHAEUTv5PJC4=
github.com/lestrrat-go/jwx/v2 v2.0.21 h1:jAPKupy4uHgrHFEdjVjNkUgoBKtVDgrQPB/h55FHrR0=
github.com/lestrrat-go/jwx/v2 v2.0.21/go.mod h1:09mLW8zto6bWL9GbwnqAli+ArLf+5M33QLQPDggkUWM=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
@@ -86,16 +78,12 @@ github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc=
go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
BIN
View File
Binary file not shown.
+13 -10
View File
@@ -1,15 +1,18 @@
package route
import (
"GoCMS/api"
"GoCMS/api/controllers/auth"
"GoCMS/api/controllers/pages"
"GoCMS/api/controllers/post"
"encoding/json"
"net/http"
"os"
"strings"
"github.com/MadAppGang/httplog"
"github.com/go-chi/chi/v5"
"github.com/go-chi/cors"
"github.com/go-chi/jwtauth/v5"
"net/http"
"os"
"strings"
)
const keyContentType = "Content-Type"
@@ -29,7 +32,7 @@ func HtmlContentTypeMiddleware(next http.Handler) http.Handler {
}
func InitJwt() {
api.TokenAuth = jwtauth.New("HS256", []byte(os.Getenv("JWT_SECRET")), nil)
auth.Token = jwtauth.New("HS256", []byte(os.Getenv("JWT_SECRET")), nil)
}
func GetHelloWorld(w http.ResponseWriter, _ *http.Request) {
@@ -44,11 +47,11 @@ func InitBackendRoutes() *chi.Mux {
r.Use(JsonContentTypeMiddleware)
r.Get("/", GetHelloWorld)
r.Group(func(r chi.Router) {
r.Use(jwtauth.Verifier(api.TokenAuth))
r.Use(jwtauth.Authenticator(api.TokenAuth))
r.Mount("/post", api.NewPostRouter())
r.Use(jwtauth.Verifier(auth.Token))
r.Use(jwtauth.Authenticator(auth.Token))
r.Mount("/post", post.NewPostRouter())
})
r.Mount("/auth", api.NewAuthRouter())
r.Mount("/auth", auth.NewAuthRouter())
return r
}
@@ -58,7 +61,7 @@ func InitFrontendRoutes() *chi.Mux {
r.Use(httplog.LoggerWithName("frontend"))
r.Use(HtmlContentTypeMiddleware)
r.Mount("/", api.NewPageRouter())
r.Mount("/", pages.NewPageRouter())
return r
}
+5 -4
View File
@@ -2,14 +2,15 @@ package test
import (
"GoCMS/adapters/secondary/gateways/models"
"GoCMS/api"
"GoCMS/api/controllers/auth"
"GoCMS/main/server"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
"io"
"net/http"
"os"
"time"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
)
const testDbFile = "test.db"
@@ -45,7 +46,7 @@ func StartServerIfNotAlready() {
}
func getAuthorizationCookie(userId uint32) *http.Cookie {
_, tokenString, err := api.TokenAuth.Encode(map[string]interface{}{"user_id": userId})
_, tokenString, err := auth.Token.Encode(map[string]interface{}{"user_id": userId})
if err != nil {
panic(err)
}