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

This commit is contained in:
Florian Sylvain committed 2025-03-13 19:43:12 +01:00
1 parent 7e29c08ea9
commit 4d6054e22b
38 files changed
+181 -152

No files matched your search

+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)
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.