From ce85d6b77bf6dd653d5c8f4b28096cb0d66d6e3d Mon Sep 17 00:00:00 2001 From: Maximilian Date: Mon, 1 Jul 2024 21:19:48 -0500 Subject: [PATCH] Begin refactoring structure --- {controllers => app/controllers}/get.go | 4 ++-- {controllers => app/controllers}/post.go | 4 ++-- {static => app/frontend/static}/css/style.css | 0 .../frontend/templates}/base.html | 2 +- .../frontend/templates}/pages/home.html | 0 .../frontend/templates}/pages/login.html | 0 .../frontend/templates}/pages/register.html | 0 app/{app.go => globals.go} | 4 ++-- {middleware => app/middleware}/csrf.go | 0 {middleware => app/middleware}/wrapper.go | 2 ++ {models => app/models}/migrations.go | 2 +- {models => app/models}/session.go | 14 ++++++------ {models => app/models}/user.go | 12 +++++----- {routes => app/routes}/get.go | 4 ++-- {routes => app/routes}/post.go | 6 ++--- app/{schedule.go => scheduler.go} | 22 +++++++++---------- database/connection.go | 2 +- database/migrate.go | 6 ++--- env_example.json | 4 ++-- main.go | 14 ++++++------ middleware/groups.go | 5 ----- {restclient => rest}/client.go | 2 +- templating/{templateHelper.go => builder.go} | 4 ++-- 23 files changed, 55 insertions(+), 58 deletions(-) rename {controllers => app/controllers}/get.go (97%) rename {controllers => app/controllers}/post.go (97%) rename {static => app/frontend/static}/css/style.css (100%) rename {templates => app/frontend/templates}/base.html (82%) rename {templates => app/frontend/templates}/pages/home.html (100%) rename {templates => app/frontend/templates}/pages/login.html (100%) rename {templates => app/frontend/templates}/pages/register.html (100%) rename app/{app.go => globals.go} (80%) rename {middleware => app/middleware}/csrf.go (100%) rename {middleware => app/middleware}/wrapper.go (80%) rename {models => app/models}/migrations.go (94%) rename {models => app/models}/session.go (89%) rename {models => app/models}/user.go (86%) rename {routes => app/routes}/get.go (93%) rename {routes => app/routes}/post.go (82%) rename app/{schedule.go => scheduler.go} (76%) delete mode 100644 middleware/groups.go rename {restclient => rest}/client.go (98%) rename templating/{templateHelper.go => builder.go} (96%) diff --git a/controllers/get.go b/app/controllers/get.go similarity index 97% rename from controllers/get.go rename to app/controllers/get.go index b054546..404ea66 100644 --- a/controllers/get.go +++ b/app/controllers/get.go @@ -2,7 +2,7 @@ package controllers import ( "GoWeb/app" - "GoWeb/models" + "GoWeb/app/models" "GoWeb/security" "GoWeb/templating" "net/http" @@ -10,7 +10,7 @@ import ( // Get is a wrapper struct for the App struct type Get struct { - App *app.App + App *app.Deps } func (g *Get) ShowHome(w http.ResponseWriter, _ *http.Request) { diff --git a/controllers/post.go b/app/controllers/post.go similarity index 97% rename from controllers/post.go rename to app/controllers/post.go index 5b23050..27c6660 100644 --- a/controllers/post.go +++ b/app/controllers/post.go @@ -2,7 +2,7 @@ package controllers import ( "GoWeb/app" - "GoWeb/models" + "GoWeb/app/models" "log/slog" "net/http" "time" @@ -10,7 +10,7 @@ import ( // Post is a wrapper struct for the App struct type Post struct { - App *app.App + App *app.Deps } func (p *Post) Login(w http.ResponseWriter, r *http.Request) { diff --git a/static/css/style.css b/app/frontend/static/css/style.css similarity index 100% rename from static/css/style.css rename to app/frontend/static/css/style.css diff --git a/templates/base.html b/app/frontend/templates/base.html similarity index 82% rename from templates/base.html rename to app/frontend/templates/base.html index 7ad57b9..f4e2ca0 100644 --- a/templates/base.html +++ b/app/frontend/templates/base.html @@ -3,7 +3,7 @@ SiteName - {{ template "pageTitle" }} - + {{ template "content" . }} diff --git a/templates/pages/home.html b/app/frontend/templates/pages/home.html similarity index 100% rename from templates/pages/home.html rename to app/frontend/templates/pages/home.html diff --git a/templates/pages/login.html b/app/frontend/templates/pages/login.html similarity index 100% rename from templates/pages/login.html rename to app/frontend/templates/pages/login.html diff --git a/templates/pages/register.html b/app/frontend/templates/pages/register.html similarity index 100% rename from templates/pages/register.html rename to app/frontend/templates/pages/register.html diff --git a/app/app.go b/app/globals.go similarity index 80% rename from app/app.go rename to app/globals.go index 53db2ec..e3985c7 100644 --- a/app/app.go +++ b/app/globals.go @@ -6,8 +6,8 @@ import ( "embed" ) -// App contains and supplies available configurations and connections -type App struct { +// Deps contains and supplies available configurations and connections +type Deps struct { Config config.Configuration // Configuration file Db *sql.DB // Database connection Res *embed.FS // Resources from the embedded filesystem diff --git a/middleware/csrf.go b/app/middleware/csrf.go similarity index 100% rename from middleware/csrf.go rename to app/middleware/csrf.go diff --git a/middleware/wrapper.go b/app/middleware/wrapper.go similarity index 80% rename from middleware/wrapper.go rename to app/middleware/wrapper.go index ce0d4e6..5e0cf28 100644 --- a/middleware/wrapper.go +++ b/app/middleware/wrapper.go @@ -2,6 +2,8 @@ package middleware import "net/http" +type MiddlewareFunc func(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) + // ProcessGroup is a wrapper function for the http.HandleFunc function // that takes the function you want to execute (f) and the middleware you want // to execute (m) this should be used when processing multiple groups of middleware at a time diff --git a/models/migrations.go b/app/models/migrations.go similarity index 94% rename from models/migrations.go rename to app/models/migrations.go index a26b595..9bdac20 100644 --- a/models/migrations.go +++ b/app/models/migrations.go @@ -7,7 +7,7 @@ import ( ) // RunAllMigrations defines the structs that should be represented in the database -func RunAllMigrations(app *app.App) error { +func RunAllMigrations(app *app.Deps) error { // Declare new dummy user for reflection user := User{ Id: 1, // Id is handled automatically, but it is added here to show it will be skipped during column creation diff --git a/models/session.go b/app/models/session.go similarity index 89% rename from models/session.go rename to app/models/session.go index eae0ac1..438453e 100644 --- a/models/session.go +++ b/app/models/session.go @@ -31,7 +31,7 @@ const ( ) // CreateSession creates a new session for a user -func CreateSession(app *app.App, w http.ResponseWriter, userId int64, remember bool) (Session, error) { +func CreateSession(app *app.Deps, w http.ResponseWriter, userId int64, remember bool) (Session, error) { session := Session{} session.UserId = userId session.AuthToken = generateAuthToken(app) @@ -62,7 +62,7 @@ func CreateSession(app *app.App, w http.ResponseWriter, userId int64, remember b return session, nil } -func SessionByAuthToken(app *app.App, authToken string) (Session, error) { +func SessionByAuthToken(app *app.Deps, authToken string) (Session, error) { session := Session{} err := app.Db.QueryRow(selectSessionByAuthToken, authToken).Scan(&session.Id, &session.UserId, &session.AuthToken, &session.RememberMe, &session.CreatedAt) @@ -74,7 +74,7 @@ func SessionByAuthToken(app *app.App, authToken string) (Session, error) { } // generateAuthToken generates a random 64-byte string -func generateAuthToken(app *app.App) string { +func generateAuthToken(app *app.Deps) string { b := make([]byte, 64) _, err := rand.Read(b) if err != nil { @@ -85,7 +85,7 @@ func generateAuthToken(app *app.App) string { } // createSessionCookie creates a new session cookie -func createSessionCookie(app *app.App, w http.ResponseWriter, session Session) { +func createSessionCookie(app *app.Deps, w http.ResponseWriter, session Session) { cookie := &http.Cookie{} if session.RememberMe { cookie = &http.Cookie{ @@ -111,7 +111,7 @@ func createSessionCookie(app *app.App, w http.ResponseWriter, session Session) { } // deleteSessionCookie deletes the session cookie -func deleteSessionCookie(app *app.App, w http.ResponseWriter) { +func deleteSessionCookie(app *app.Deps, w http.ResponseWriter) { cookie := &http.Cookie{ Name: "session", Value: "", @@ -123,7 +123,7 @@ func deleteSessionCookie(app *app.App, w http.ResponseWriter) { } // DeleteSessionByAuthToken deletes a session from the database by AuthToken -func DeleteSessionByAuthToken(app *app.App, w http.ResponseWriter, authToken string) error { +func DeleteSessionByAuthToken(app *app.Deps, w http.ResponseWriter, authToken string) error { _, err := app.Db.Exec(deleteSessionByAuthToken, authToken) if err != nil { slog.Error("error deleting session from database") @@ -136,7 +136,7 @@ func DeleteSessionByAuthToken(app *app.App, w http.ResponseWriter, authToken str } // ScheduledSessionCleanup deletes expired sessions from the database -func ScheduledSessionCleanup(app *app.App) { +func ScheduledSessionCleanup(app *app.Deps) { // Delete sessions older than 30 days (remember me sessions) _, err := app.Db.Exec(deleteSessionsOlderThan30Days) if err != nil { diff --git a/models/user.go b/app/models/user.go similarity index 86% rename from models/user.go rename to app/models/user.go index 3940e0a..4880e5f 100644 --- a/models/user.go +++ b/app/models/user.go @@ -30,7 +30,7 @@ const ( ) // CurrentUser finds the currently logged-in user by session cookie -func CurrentUser(app *app.App, r *http.Request) (User, error) { +func CurrentUser(app *app.Deps, r *http.Request) (User, error) { cookie, err := r.Cookie("session") if err != nil { return User{}, err @@ -45,7 +45,7 @@ func CurrentUser(app *app.App, r *http.Request) (User, error) { } // UserById finds a User table row in the database by id and returns a struct representing this row -func UserById(app *app.App, id int64) (User, error) { +func UserById(app *app.Deps, id int64) (User, error) { user := User{} err := app.Db.QueryRow(selectUserById, id).Scan(&user.Id, &user.Username, &user.Password, &user.CreatedAt, &user.UpdatedAt) @@ -57,7 +57,7 @@ func UserById(app *app.App, id int64) (User, error) { } // UserByUsername finds a User table row in the database by username and returns a struct representing this row -func UserByUsername(app *app.App, username string) (User, error) { +func UserByUsername(app *app.Deps, username string) (User, error) { user := User{} err := app.Db.QueryRow(selectUserByUsername, username).Scan(&user.Id, &user.Username, &user.Password, &user.CreatedAt, &user.UpdatedAt) @@ -69,7 +69,7 @@ func UserByUsername(app *app.App, username string) (User, error) { } // CreateUser creates a User table row in the database -func CreateUser(app *app.App, username string, password string, createdAt time.Time, updatedAt time.Time) (User, error) { +func CreateUser(app *app.Deps, username string, password string, createdAt time.Time, updatedAt time.Time) (User, error) { // Get sha256 hash of password then get bcrypt hash to store hash256 := sha256.New() hash256.Write([]byte(password)) @@ -93,7 +93,7 @@ func CreateUser(app *app.App, username string, password string, createdAt time.T } // AuthenticateUser validates the password for the specified user -func AuthenticateUser(app *app.App, w http.ResponseWriter, username string, password string, remember bool) (Session, error) { +func AuthenticateUser(app *app.Deps, w http.ResponseWriter, username string, password string, remember bool) (Session, error) { var user User err := app.Db.QueryRow(selectUserByUsername, username).Scan(&user.Id, &user.Username, &user.Password, &user.CreatedAt, &user.UpdatedAt) @@ -117,7 +117,7 @@ func AuthenticateUser(app *app.App, w http.ResponseWriter, username string, pass } // LogoutUser deletes the session cookie and AuthToken from the database -func LogoutUser(app *app.App, w http.ResponseWriter, r *http.Request) { +func LogoutUser(app *app.Deps, w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie("session") if err != nil { return diff --git a/routes/get.go b/app/routes/get.go similarity index 93% rename from routes/get.go rename to app/routes/get.go index 5282fb8..28089d2 100644 --- a/routes/get.go +++ b/app/routes/get.go @@ -2,14 +2,14 @@ package routes import ( "GoWeb/app" - "GoWeb/controllers" + "GoWeb/app/controllers" "io/fs" "log/slog" "net/http" ) // Get defines all project get routes -func Get(app *app.App) { +func Get(app *app.Deps) { // Get controller struct initialize getController := controllers.Get{ App: app, diff --git a/routes/post.go b/app/routes/post.go similarity index 82% rename from routes/post.go rename to app/routes/post.go index ebda5d1..344d8f4 100644 --- a/routes/post.go +++ b/app/routes/post.go @@ -2,13 +2,13 @@ package routes import ( "GoWeb/app" - "GoWeb/controllers" - "GoWeb/middleware" + "GoWeb/app/controllers" + "GoWeb/app/middleware" "net/http" ) // Post defines all project post routes -func Post(app *app.App) { +func Post(app *app.Deps) { // Post controller struct initialize postController := controllers.Post{ App: app, diff --git a/app/schedule.go b/app/scheduler.go similarity index 76% rename from app/schedule.go rename to app/scheduler.go index 56b4b9a..d18d704 100644 --- a/app/schedule.go +++ b/app/scheduler.go @@ -6,22 +6,22 @@ import ( ) type Scheduled struct { - EveryReboot []func(app *App) - EverySecond []func(app *App) - EveryMinute []func(app *App) - EveryHour []func(app *App) - EveryDay []func(app *App) - EveryWeek []func(app *App) - EveryMonth []func(app *App) - EveryYear []func(app *App) + EveryReboot []func(app *Deps) + EverySecond []func(app *Deps) + EveryMinute []func(app *Deps) + EveryHour []func(app *Deps) + EveryDay []func(app *Deps) + EveryWeek []func(app *Deps) + EveryMonth []func(app *Deps) + EveryYear []func(app *Deps) } type Task struct { - Funcs []func(app *App) + Funcs []func(app *Deps) Interval time.Duration } -func RunScheduledTasks(app *App, poolSize int, stop <-chan struct{}) { +func RunScheduledTasks(app *Deps, poolSize int, stop <-chan struct{}) { for _, f := range app.ScheduledTasks.EveryReboot { f(app) } @@ -51,7 +51,7 @@ func RunScheduledTasks(app *App, poolSize int, stop <-chan struct{}) { case <-ticker.C: for _, f := range task.Funcs { runner <- true - go func(f func(app *App)) { + go func(f func(app *Deps)) { defer func() { <-runner }() f(app) }(f) diff --git a/database/connection.go b/database/connection.go index 3978599..c36b088 100644 --- a/database/connection.go +++ b/database/connection.go @@ -9,7 +9,7 @@ import ( ) // Connect returns a new database connection -func Connect(app *app.App) *sql.DB { +func Connect(app *app.Deps) *sql.DB { postgresConfig := fmt.Sprintf("host=%s port=%s user=%s "+ "password=%s dbname=%s sslmode=disable", app.Config.Db.Ip, app.Config.Db.Port, app.Config.Db.User, app.Config.Db.Password, app.Config.Db.Name) diff --git a/database/migrate.go b/database/migrate.go index 69f9ac6..a5b42dc 100644 --- a/database/migrate.go +++ b/database/migrate.go @@ -11,7 +11,7 @@ import ( // Migrate given a dummy object of any type, it will create a table with the same name // as the type and create columns with the same name as the fields of the object -func Migrate(app *app.App, anyStruct interface{}) error { +func Migrate(app *app.Deps, anyStruct interface{}) error { valueOfStruct := reflect.ValueOf(anyStruct) typeOfStruct := valueOfStruct.Type() @@ -41,7 +41,7 @@ func Migrate(app *app.App, anyStruct interface{}) error { } // createTable creates a table with the given name if it doesn't exist, it is assumed that id will be the primary key -func createTable(app *app.App, tableName string) error { +func createTable(app *app.Deps, tableName string) error { var tableExists bool err := app.Db.QueryRow("SELECT EXISTS (SELECT 1 FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname ~ $1 AND pg_catalog.pg_table_is_visible(c.oid))", "^"+tableName+"$").Scan(&tableExists) if err != nil { @@ -67,7 +67,7 @@ func createTable(app *app.App, tableName string) error { } // createColumn creates a column with the given name and type if it doesn't exist -func createColumn(app *app.App, tableName, columnName, columnType string) error { +func createColumn(app *app.Deps, tableName, columnName, columnType string) error { var columnExists bool err := app.Db.QueryRow("SELECT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = $1 AND column_name = $2)", tableName, columnName).Scan(&columnExists) if err != nil { diff --git a/env_example.json b/env_example.json index 53754ff..e70c6d8 100644 --- a/env_example.json +++ b/env_example.json @@ -12,7 +12,7 @@ "HttpPort": "8090" }, "Template": { - "BaseTemplateName": "templates/base.html", - "ContentPath": "templates" + "BaseTemplateName": "app/frontend/templates/base.html", + "ContentPath": "app/frontend/templates" } } \ No newline at end of file diff --git a/main.go b/main.go index 7251d8c..54f6e60 100644 --- a/main.go +++ b/main.go @@ -2,10 +2,10 @@ package main import ( "GoWeb/app" + "GoWeb/app/models" + "GoWeb/app/routes" "GoWeb/config" "GoWeb/database" - "GoWeb/models" - "GoWeb/routes" "GoWeb/templating" "context" "embed" @@ -18,12 +18,12 @@ import ( "time" ) -//go:embed templates static +//go:embed app/frontend/templates app/frontend/static var res embed.FS func main() { - // Create instance of App - appLoaded := app.App{} + // Create instance of Deps + appLoaded := app.Deps{} // Load config file to application appLoaded.Config = config.LoadConfig() @@ -60,8 +60,8 @@ func main() { // Assign and run scheduled tasks appLoaded.ScheduledTasks = app.Scheduled{ - EveryReboot: []func(app *app.App){models.ScheduledSessionCleanup}, - EveryMinute: []func(app *app.App){models.ScheduledSessionCleanup}, + EveryReboot: []func(app *app.Deps){models.ScheduledSessionCleanup}, + EveryMinute: []func(app *app.Deps){models.ScheduledSessionCleanup}, } // Define Routes diff --git a/middleware/groups.go b/middleware/groups.go deleted file mode 100644 index 0bb20a4..0000000 --- a/middleware/groups.go +++ /dev/null @@ -1,5 +0,0 @@ -package middleware - -import "net/http" - -type MiddlewareFunc func(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) diff --git a/restclient/client.go b/rest/client.go similarity index 98% rename from restclient/client.go rename to rest/client.go index 519f62b..e409047 100644 --- a/restclient/client.go +++ b/rest/client.go @@ -1,4 +1,4 @@ -package restclient +package rest import ( "bytes" diff --git a/templating/templateHelper.go b/templating/builder.go similarity index 96% rename from templating/templateHelper.go rename to templating/builder.go index 73def88..d8c1de6 100644 --- a/templating/templateHelper.go +++ b/templating/builder.go @@ -9,9 +9,9 @@ import ( "net/http" ) -var templates = make(map[string]*template.Template) // This is only used here, does not need to be in app.App +var templates = make(map[string]*template.Template) // This is only used here, does not need to be in app.Deps -func BuildPages(app *app.App) error { +func BuildPages(app *app.Deps) error { basePath := app.Config.Template.BaseName baseContent, err := app.Res.ReadFile(basePath)