clean: moved funcs to specific files + GetPage usecase/repo

This commit is contained in:
Florian Sylvain
2023-08-12 20:42:43 +02:00
parent 869fb3f145
commit 1539e06ec8
18 changed files with 190 additions and 136 deletions
@@ -0,0 +1,32 @@
package gateways
import (
. "GohCMS2/domain/gateways"
"bytes"
"embed"
"html/template"
)
type PageRepository struct{}
//go:embed web/templates/*
var templateFiles embed.FS
func NewPageRepository() *PageRepository {
return &PageRepository{}
}
func (p *PageRepository) Get(name string, data interface{}) ([]byte, error) {
var processedHTML bytes.Buffer
tmpl, err := template.ParseFS(templateFiles, "web/templates/"+name+".html")
if err != nil {
return nil, err
}
err = tmpl.Execute(&processedHTML, data)
if err != nil {
return nil, err
}
return processedHTML.Bytes(), nil
}
var _ IPageRepository = &PageRepository{}
+3 -3
View File
@@ -20,7 +20,7 @@ func getArticle(w http.ResponseWriter, r *http.Request) {
return return
} }
article, err := container.GetArticleUseCase.GetArticle(uint32(id)) article, err := Container.GetArticleUseCase.GetArticle(uint32(id))
if err != nil { if err != nil {
http.Error(w, "The requested resource, identified by its unique ID, could not be found on the server.", http.StatusNotFound) http.Error(w, "The requested resource, identified by its unique ID, could not be found on the server.", http.StatusNotFound)
return return
@@ -44,7 +44,7 @@ func postArticle(w http.ResponseWriter, r *http.Request) {
return return
} }
createdArticle, err := container.CreateArticleUseCase.CreateArticle(CreateArticleCommand{ createdArticle, err := Container.CreateArticleUseCase.CreateArticle(CreateArticleCommand{
Title: article.Title, Title: article.Title,
Body: article.Body, Body: article.Body,
}) })
@@ -58,7 +58,7 @@ func postArticle(w http.ResponseWriter, r *http.Request) {
} }
func listArticles(w http.ResponseWriter, _ *http.Request) { func listArticles(w http.ResponseWriter, _ *http.Request) {
articles := container.ListArticlesUseCase.ListArticles() articles := Container.ListArticlesUseCase.ListArticles()
articlesJson, _ := json.Marshal(articles) articlesJson, _ := json.Marshal(articles)
_, _ = w.Write(articlesJson) _, _ = w.Write(articlesJson)
+7 -7
View File
@@ -45,8 +45,8 @@ func SetJwtCookie(w *http.ResponseWriter, userId uint32) error {
return nil return nil
} }
func isUserTableEmpty() bool { func IsUserTableEmpty() bool {
users := container.ListUsersUseCase.ListUsers() users := Container.ListUsersUseCase.ListUsers()
return len(users) == 0 return len(users) == 0
} }
@@ -75,7 +75,7 @@ func login(w http.ResponseWriter, r *http.Request) {
return return
} }
dbUser, err := container.GetUserUseCase.GetUserByUsername(user.Username) dbUser, err := Container.GetUserUseCase.GetUserByUsername(user.Username)
if err != nil { if err != nil {
http.Error(w, logsErrorMessage, http.StatusForbidden) http.Error(w, logsErrorMessage, http.StatusForbidden)
return return
@@ -94,7 +94,7 @@ func login(w http.ResponseWriter, r *http.Request) {
} }
func register(w http.ResponseWriter, r *http.Request) { func register(w http.ResponseWriter, r *http.Request) {
if !IsLoggedIn(r) && !isUserTableEmpty() { if !IsLoggedIn(r) && !IsUserTableEmpty() {
http.Error(w, "You are not allowed to create a user. Log in or reset database.", http.StatusForbidden) http.Error(w, "You are not allowed to create a user. Log in or reset database.", http.StatusForbidden)
return return
} }
@@ -112,7 +112,7 @@ func register(w http.ResponseWriter, r *http.Request) {
return return
} }
createdUser, err := container.CreateUserUseCase.CreateUser(useCases.CreateUserCommand{ createdUser, err := Container.CreateUserUseCase.CreateUser(useCases.CreateUserCommand{
Username: user.Username, Username: user.Username,
Password: user.Password, Password: user.Password,
Email: user.Email, Email: user.Email,
@@ -128,7 +128,7 @@ func register(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(message) _, _ = w.Write(message)
} }
func removeJwtCookie(w http.ResponseWriter) { func RemoveJwtCookie(w http.ResponseWriter) {
http.SetCookie(w, &http.Cookie{ http.SetCookie(w, &http.Cookie{
Name: "jwt", Name: "jwt",
Value: "", Value: "",
@@ -141,7 +141,7 @@ func removeJwtCookie(w http.ResponseWriter) {
} }
func logout(w http.ResponseWriter, _ *http.Request) { func logout(w http.ResponseWriter, _ *http.Request) {
removeJwtCookie(w) RemoveJwtCookie(w)
message, _ := json.Marshal(map[string]interface{}{"message": "User logged out! HTTPonly jwt cookie deleted"}) message, _ := json.Marshal(map[string]interface{}{"message": "User logged out! HTTPonly jwt cookie deleted"})
_, _ = w.Write(message) _, _ = w.Write(message)
} }
+10 -6
View File
@@ -8,16 +8,17 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
) )
type Container struct { type LocalContainer struct {
CreateArticleUseCase *CreateArticleUseCase CreateArticleUseCase *CreateArticleUseCase
GetArticleUseCase *GetArticleUseCase GetArticleUseCase *GetArticleUseCase
ListArticlesUseCase *ListArticlesUseCase ListArticlesUseCase *ListArticlesUseCase
GetUserUseCase *GetUserUseCase GetUserUseCase *GetUserUseCase
CreateUserUseCase *CreateUserUseCase CreateUserUseCase *CreateUserUseCase
ListUsersUseCase *ListUsersUseCase ListUsersUseCase *ListUsersUseCase
GetPageUseCase *GetPageUseCase
} }
var container *Container var Container *LocalContainer
func setContainer( func setContainer(
createArticle *CreateArticleUseCase, createArticle *CreateArticleUseCase,
@@ -26,20 +27,22 @@ func setContainer(
getUser *GetUserUseCase, getUser *GetUserUseCase,
createUser *CreateUserUseCase, createUser *CreateUserUseCase,
listUsers *ListUsersUseCase, listUsers *ListUsersUseCase,
) *Container { getPage *GetPageUseCase,
container = &Container{ ) *LocalContainer {
Container = &LocalContainer{
CreateArticleUseCase: createArticle, CreateArticleUseCase: createArticle,
GetArticleUseCase: getArticle, GetArticleUseCase: getArticle,
ListArticlesUseCase: listArticle, ListArticlesUseCase: listArticle,
GetUserUseCase: getUser, GetUserUseCase: getUser,
CreateUserUseCase: createUser, CreateUserUseCase: createUser,
ListUsersUseCase: listUsers, ListUsersUseCase: listUsers,
GetPageUseCase: getPage,
} }
return container return Container
} }
func InitContainer() { func InitContainer() {
if container != nil { if Container != nil {
return return
} }
@@ -59,6 +62,7 @@ func InitContainer() {
_ = digContainer.Provide(func(db *gorm.DB) *GetUserUseCase { return NewGetUserUseCase(db) }) _ = digContainer.Provide(func(db *gorm.DB) *GetUserUseCase { return NewGetUserUseCase(db) })
_ = digContainer.Provide(func(db *gorm.DB) *CreateUserUseCase { return NewCreateUserUseCase(db) }) _ = digContainer.Provide(func(db *gorm.DB) *CreateUserUseCase { return NewCreateUserUseCase(db) })
_ = digContainer.Provide(func(db *gorm.DB) *ListUsersUseCase { return NewListUsersUseCase(db) }) _ = digContainer.Provide(func(db *gorm.DB) *ListUsersUseCase { return NewListUsersUseCase(db) })
_ = digContainer.Provide(NewGetPageUseCase)
_ = digContainer.Invoke(setContainer) _ = digContainer.Invoke(setContainer)
} }
+9 -120
View File
@@ -1,22 +1,14 @@
package api package api
import ( import (
"bytes"
"embed" "embed"
"encoding/json"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"html/template"
"io/fs" "io/fs"
"net/http" "net/http"
"os"
"path/filepath" "path/filepath"
"strings"
) )
//go:embed web/templates/* //go:embed static
var templateFiles embed.FS
//go:embed web/static
var staticFolder embed.FS var staticFolder embed.FS
var contentTypes = map[string]string{ var contentTypes = map[string]string{
@@ -29,110 +21,7 @@ var contentTypes = map[string]string{
".ico": "image/x-icon", ".ico": "image/x-icon",
} }
const loginRoute = "/login" func StaticFileServerWithContentType(fsys http.FileSystem) http.Handler {
type LoginPage struct {
IsError bool `json:"isError"`
Error string `json:"error"`
Username string `json:"username"`
}
func NewLoginPage(error string, username string) *LoginPage {
return &LoginPage{
IsError: strings.Compare(error, "") != 0,
Error: error,
Username: username,
}
}
func getPage(page string, data interface{}) ([]byte, error) {
var processedHTML bytes.Buffer
tmpl, err := template.ParseFS(templateFiles, "web/templates/"+page+".html")
if err != nil {
return nil, err
}
err = tmpl.Execute(&processedHTML, data)
if err != nil {
return nil, err
}
return processedHTML.Bytes(), nil
}
func getLoginPageHandler(loginPage *LoginPage) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if IsLoggedIn(r) {
http.Redirect(w, r, "/home", http.StatusSeeOther)
return
}
if r.Method == http.MethodPost {
postLoginPage(w, r)
return
}
bs, err := getPage("login", &loginPage)
if err != nil {
_, _ = w.Write([]byte(err.Error()))
}
_, _ = w.Write(bs)
}
}
func postLoginPage(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
credentials, err := json.Marshal(&UserLogin{
Username: r.FormValue("username"),
Password: r.FormValue("password"),
})
if err != nil {
r.Method = http.MethodGet
getLoginPageHandler(NewLoginPage("Invalid username or password.", r.FormValue("username")))(w, r)
return
}
response, err := http.Post(
"http://localhost:"+os.Getenv("PORT")+"/v1/auth/login",
"application/json",
bytes.NewBuffer(credentials))
if err != nil || response.StatusCode != http.StatusOK {
r.Method = http.MethodGet
getLoginPageHandler(NewLoginPage("Invalid username or password.", r.FormValue("username")))(w, r)
return
}
w.Header().Set("Set-Cookie", response.Header.Get("Set-Cookie"))
http.Redirect(w, r, "/home", http.StatusSeeOther)
}
func getHomePage(w http.ResponseWriter, _ *http.Request) {
navbarTmpl, _ := getPage("componentNavbar", nil)
homeTmpl, _ := getPage("home", map[string]interface{}{
"Navbar": template.HTML(navbarTmpl),
})
_, _ = w.Write(homeTmpl)
}
func getLogin(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, loginRoute, http.StatusPermanentRedirect)
}
func getLogout(w http.ResponseWriter, r *http.Request) {
removeJwtCookie(w)
http.Redirect(w, r, loginRoute, http.StatusSeeOther)
}
func IsLoggedInMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !IsLoggedIn(r) {
http.Redirect(w, r, loginRoute, http.StatusSeeOther)
return
}
next.ServeHTTP(w, r)
})
}
func staticFileServerWithContentType(fsys http.FileSystem) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path path := r.URL.Path
if ext := filepath.Ext(path); ext != "" { if ext := filepath.Ext(path); ext != "" {
@@ -147,9 +36,9 @@ func staticFileServerWithContentType(fsys http.FileSystem) http.Handler {
func NewPageRouter() http.Handler { func NewPageRouter() http.Handler {
r := chi.NewRouter() r := chi.NewRouter()
contentStatic, _ := fs.Sub(fs.FS(staticFolder), "web/static") contentStatic := fs.FS(staticFolder)
r.Handle("/static/*", staticFileServerWithContentType(http.FS(contentStatic))) r.Handle("/static/*", StaticFileServerWithContentType(http.FS(contentStatic)))
r.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) { r.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
_, err := http.FS(staticFolder).Open("favicon.ico") _, err := http.FS(staticFolder).Open("favicon.ico")
if err != nil { if err != nil {
@@ -157,14 +46,14 @@ func NewPageRouter() http.Handler {
} }
}) })
r.Get("/", getLogin) r.Get("/", GetLogin)
r.Get(loginRoute, getLoginPageHandler(NewLoginPage("", ""))) r.Get(LoginRoute, GetLoginPageHandler(NewLoginPage("", "")))
r.Post(loginRoute, getLoginPageHandler(NewLoginPage("", ""))) r.Post(LoginRoute, GetLoginPageHandler(NewLoginPage("", "")))
r.Get("/logout", getLogout) r.Get("/logout", GetLogout)
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(IsLoggedInMiddleware) r.Use(IsLoggedInMiddleware)
r.Get("/home", getHomePage) r.Get("/home", GetHomePage)
}) })
return r return r
+91
View File
@@ -0,0 +1,91 @@
package api
import (
"bytes"
"encoding/json"
"net/http"
"os"
"strings"
)
const LoginRoute = "/login"
type LoginPage struct {
IsError bool `json:"isError"`
Error string `json:"error"`
Username string `json:"username"`
}
func NewLoginPage(error string, username string) *LoginPage {
return &LoginPage{
IsError: strings.Compare(error, "") != 0,
Error: error,
Username: username,
}
}
func GetLoginPageHandler(loginPage *LoginPage) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if IsLoggedIn(r) {
http.Redirect(w, r, "/home", http.StatusSeeOther)
return
}
if r.Method == http.MethodPost {
PostLoginPage(w, r)
return
}
bs, err := Container.GetPageUseCase.GetPage("login", &loginPage)
if err != nil {
_, _ = w.Write([]byte(err.Error()))
}
_, _ = w.Write(bs)
}
}
func PostLoginPage(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
credentials, err := json.Marshal(&UserLogin{
Username: r.FormValue("username"),
Password: r.FormValue("password"),
})
if err != nil {
r.Method = http.MethodGet
GetLoginPageHandler(NewLoginPage("Invalid username or password.", r.FormValue("username")))(w, r)
return
}
response, err := http.Post(
"http://localhost:"+os.Getenv("PORT")+"/v1/auth/login",
"application/json",
bytes.NewBuffer(credentials))
if err != nil || response.StatusCode != http.StatusOK {
r.Method = http.MethodGet
GetLoginPageHandler(NewLoginPage("Invalid username or password.", r.FormValue("username")))(w, r)
return
}
w.Header().Set("Set-Cookie", response.Header.Get("Set-Cookie"))
http.Redirect(w, r, "/home", http.StatusSeeOther)
}
func GetLogin(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, LoginRoute, http.StatusPermanentRedirect)
}
func GetLogout(w http.ResponseWriter, r *http.Request) {
RemoveJwtCookie(w)
http.Redirect(w, r, LoginRoute, http.StatusSeeOther)
}
func IsLoggedInMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !IsLoggedIn(r) {
http.Redirect(w, r, LoginRoute, http.StatusSeeOther)
return
}
next.ServeHTTP(w, r)
})
}
+14
View File
@@ -0,0 +1,14 @@
package api
import (
"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{}{
"Navbar": template.HTML(navbarTmpl),
})
_, _ = w.Write(homeTmpl)
}

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

+5
View File
@@ -0,0 +1,5 @@
package gateways
type IPageRepository interface {
Get(name string, data interface{}) ([]byte, error)
}
+19
View File
@@ -0,0 +1,19 @@
package useCases
import (
. "GohCMS2/adapters/secondary/gateways"
)
type GetPageUseCase struct {
pageRepository PageRepository
}
func NewGetPageUseCase() *GetPageUseCase {
return &GetPageUseCase{
pageRepository: *NewPageRepository(),
}
}
func (g *GetPageUseCase) GetPage(name string, data interface{}) ([]byte, error) {
return g.pageRepository.Get(name, data)
}