From 0c40680d76b7b8d0f30c989621e4df62a1ce7380 Mon Sep 17 00:00:00 2001 From: Tim Wundenberg Date: Thu, 29 May 2025 13:23:13 +0200 Subject: [PATCH] fix: move implementation to "internal" package --- .mockery.yaml | 4 +- {db => internal/db}/auth.go | 4 +- {db => internal/db}/error.go | 4 +- {db => internal/db}/migration.go | 4 +- internal/default.go | 135 ++++++++++++++++++ {handler => internal/handler}/account.go | 10 +- {handler => internal/handler}/auth.go | 12 +- {handler => internal/handler}/error.go | 6 +- .../handler}/middleware/authenticate.go | 4 +- .../handler}/middleware/cache_control.go | 0 .../middleware/cross_site_request_forgery.go | 8 +- .../handler}/middleware/default.go | 0 .../generate_recurring_transactions.go | 2 +- .../handler}/middleware/gzip.go | 2 +- .../handler}/middleware/logger.go | 2 +- .../handler}/middleware/security_headers.go | 2 +- .../handler}/middleware/wrapper.go | 0 {handler => internal/handler}/render.go | 8 +- {handler => internal/handler}/root_and_404.go | 4 +- {handler => internal/handler}/transaction.go | 10 +- .../handler}/transaction_recurring.go | 10 +- .../handler}/treasure_chest.go | 12 +- {log => internal/log}/default.go | 0 {service => internal/service}/account.go | 7 +- {service => internal/service}/auth.go | 9 +- {service => internal/service}/clock.go | 0 {service => internal/service}/default.go | 0 {service => internal/service}/error.go | 0 {service => internal/service}/mail.go | 5 +- .../service}/random_generator.go | 5 +- {service => internal/service}/transaction.go | 6 +- .../service}/transaction_recurring.go | 7 +- .../service}/treasure_chest.go | 7 +- internal/service/treasure_chest_test.go | 10 ++ .../template}/account/account.templ | 4 +- .../template}/account/default.go | 0 .../template}/auth/change_password.templ | 0 .../template}/auth/default.go | 0 .../template}/auth/delete_account.templ | 0 .../template}/auth/reset_password.templ | 0 .../template}/auth/sign_in_or_up.templ | 0 .../template}/auth/user.templ | 0 .../template}/auth/verify.templ | 0 .../template}/auth/verify_response.templ | 0 .../template}/dashboard.templ | 0 {template => internal/template}/default.go | 0 {template => internal/template}/layout.templ | 0 .../template}/mail/default.go | 0 .../template}/mail/register.templ | 0 .../template}/mail/reset-password.templ | 0 .../template}/not_found.templ | 0 {template => internal/template}/root.templ | 0 .../template}/svg/default.templ | 0 .../template}/transaction/default.go | 0 .../template}/transaction/transaction.templ | 4 +- .../transaction_recurring/default.go | 0 .../transaction_recurring.templ | 4 +- .../template}/treasurechest/default.go | 0 .../treasurechest/treasure_chest.templ | 4 +- {types => internal/types}/account.go | 0 {types => internal/types}/auth.go | 0 {types => internal/types}/settings.go | 2 +- {types => internal/types}/transaction.go | 0 .../types}/transaction_recurring.go | 0 {types => internal/types}/treasure_chest.go | 0 {types => internal/types}/types.go | 0 {utils => internal/utils}/http.go | 2 +- main.go | 131 +---------------- service/auth_test.go => test/auth2_test.go | 9 +- {db => test}/auth_test.go | 6 +- main_test.go => test/main_test.go | 9 +- test/treasure_chest_test.go | 1 + 72 files changed, 245 insertions(+), 230 deletions(-) rename {db => internal/db}/auth.go (99%) rename {db => internal/db}/error.go (90%) rename {db => internal/db}/migration.go (94%) create mode 100644 internal/default.go rename {handler => internal/handler}/account.go (93%) rename {handler => internal/handler}/auth.go (97%) rename {handler => internal/handler}/error.go (90%) rename {handler => internal/handler}/middleware/authenticate.go (95%) rename {handler => internal/handler}/middleware/cache_control.go (100%) rename {handler => internal/handler}/middleware/cross_site_request_forgery.go (92%) rename {handler => internal/handler}/middleware/default.go (100%) rename {handler => internal/handler}/middleware/generate_recurring_transactions.go (93%) rename {handler => internal/handler}/middleware/gzip.go (96%) rename {handler => internal/handler}/middleware/logger.go (97%) rename {handler => internal/handler}/middleware/security_headers.go (97%) rename {handler => internal/handler}/middleware/wrapper.go (100%) rename {handler => internal/handler}/render.go (90%) rename {handler => internal/handler}/root_and_404.go (92%) rename {handler => internal/handler}/transaction.go (97%) rename {handler => internal/handler}/transaction_recurring.go (94%) rename {handler => internal/handler}/treasure_chest.go (94%) rename {log => internal/log}/default.go (100%) rename {service => internal/service}/account.go (98%) rename {service => internal/service}/auth.go (98%) rename {service => internal/service}/clock.go (100%) rename {service => internal/service}/default.go (100%) rename {service => internal/service}/error.go (100%) rename {service => internal/service}/mail.go (94%) rename {service => internal/service}/random_generator.go (94%) rename {service => internal/service}/transaction.go (99%) rename {service => internal/service}/transaction_recurring.go (99%) rename {service => internal/service}/treasure_chest.go (98%) create mode 100644 internal/service/treasure_chest_test.go rename {template => internal/template}/account/account.templ (97%) rename {template => internal/template}/account/default.go (100%) rename {template => internal/template}/auth/change_password.templ (100%) rename {template => internal/template}/auth/default.go (100%) rename {template => internal/template}/auth/delete_account.templ (100%) rename {template => internal/template}/auth/reset_password.templ (100%) rename {template => internal/template}/auth/sign_in_or_up.templ (100%) rename {template => internal/template}/auth/user.templ (100%) rename {template => internal/template}/auth/verify.templ (100%) rename {template => internal/template}/auth/verify_response.templ (100%) rename {template => internal/template}/dashboard.templ (100%) rename {template => internal/template}/default.go (100%) rename {template => internal/template}/layout.templ (100%) rename {template => internal/template}/mail/default.go (100%) rename {template => internal/template}/mail/register.templ (100%) rename {template => internal/template}/mail/reset-password.templ (100%) rename {template => internal/template}/not_found.templ (100%) rename {template => internal/template}/root.templ (100%) rename {template => internal/template}/svg/default.templ (100%) rename {template => internal/template}/transaction/default.go (100%) rename {template => internal/template}/transaction/transaction.templ (98%) rename {template => internal/template}/transaction_recurring/default.go (100%) rename {template => internal/template}/transaction_recurring/transaction_recurring.templ (98%) rename {template => internal/template}/treasurechest/default.go (100%) rename {template => internal/template}/treasurechest/treasure_chest.templ (98%) rename {types => internal/types}/account.go (100%) rename {types => internal/types}/auth.go (100%) rename {types => internal/types}/settings.go (98%) rename {types => internal/types}/transaction.go (100%) rename {types => internal/types}/transaction_recurring.go (100%) rename {types => internal/types}/treasure_chest.go (100%) rename {types => internal/types}/types.go (100%) rename {utils => internal/utils}/http.go (97%) rename service/auth_test.go => test/auth2_test.go (97%) rename {db => test}/auth_test.go (98%) rename main_test.go => test/main_test.go (99%) create mode 100644 test/treasure_chest_test.go diff --git a/.mockery.yaml b/.mockery.yaml index 3b0170e..1fd18b8 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -3,11 +3,11 @@ dir: mocks/ outpkg: mocks issue-845-fix: True packages: - spend-sparrow/service: + spend-sparrow/internal/service: interfaces: Random: Clock: Mail: - spend-sparrow/db: + spend-sparrow/internal/db: interfaces: Auth: diff --git a/db/auth.go b/internal/db/auth.go similarity index 99% rename from db/auth.go rename to internal/db/auth.go index d83f659..049003e 100644 --- a/db/auth.go +++ b/internal/db/auth.go @@ -2,8 +2,8 @@ package db import ( "errors" - "spend-sparrow/log" - "spend-sparrow/types" + "spend-sparrow/internal/log" + "spend-sparrow/internal/types" "database/sql" "strings" diff --git a/db/error.go b/internal/db/error.go similarity index 90% rename from db/error.go rename to internal/db/error.go index 194b0e8..11091ae 100644 --- a/db/error.go +++ b/internal/db/error.go @@ -3,8 +3,8 @@ package db import ( "database/sql" "errors" - "spend-sparrow/log" - "spend-sparrow/types" + "spend-sparrow/internal/log" + "spend-sparrow/internal/types" ) var ( diff --git a/db/migration.go b/internal/db/migration.go similarity index 94% rename from db/migration.go rename to internal/db/migration.go index 9f56bcb..17f75c7 100644 --- a/db/migration.go +++ b/internal/db/migration.go @@ -1,8 +1,8 @@ package db import ( - "spend-sparrow/log" - "spend-sparrow/types" + "spend-sparrow/internal/log" + "spend-sparrow/internal/types" "errors" diff --git a/internal/default.go b/internal/default.go new file mode 100644 index 0000000..54203c9 --- /dev/null +++ b/internal/default.go @@ -0,0 +1,135 @@ +package internal + +import ( + "errors" + "fmt" + "spend-sparrow/internal/db" + "spend-sparrow/internal/handler" + "spend-sparrow/internal/handler/middleware" + "spend-sparrow/internal/log" + "spend-sparrow/internal/service" + "spend-sparrow/internal/types" + + "context" + "net/http" + "os/signal" + "sync" + "syscall" + "time" + + "github.com/jmoiron/sqlx" + _ "github.com/mattn/go-sqlite3" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +func Run(ctx context.Context, database *sqlx.DB, migrationsPrefix string, env func(string) string) error { + ctx, cancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) + defer cancel() + + log.Info("Starting server...") + + // init server settings + serverSettings := types.NewSettingsFromEnv(env) + + // init db + err := db.RunMigrations(database, migrationsPrefix) + if err != nil { + return fmt.Errorf("could not run migrations: %w", err) + } + + // init servers + var prometheusServer *http.Server + if serverSettings.PrometheusEnabled { + prometheusServer := &http.Server{ + Addr: ":8081", + Handler: promhttp.Handler(), + ReadHeaderTimeout: 10 * time.Second, + } + go startServer(prometheusServer) + } + + httpServer := &http.Server{ + Addr: ":" + serverSettings.Port, + Handler: createHandler(database, serverSettings), + ReadHeaderTimeout: 10 * time.Second, + } + go startServer(httpServer) + + // graceful shutdown + var wg sync.WaitGroup + wg.Add(2) + go shutdownServer(httpServer, ctx, &wg) + go shutdownServer(prometheusServer, ctx, &wg) + wg.Wait() + + return nil +} + +func startServer(s *http.Server) { + log.Info("Starting server on %q", s.Addr) + if err := s.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + log.Error("error listening and serving: %v", err) + } +} + +func shutdownServer(s *http.Server, ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + if s == nil { + return + } + + <-ctx.Done() + shutdownCtx := context.Background() + shutdownCtx, cancel := context.WithTimeout(shutdownCtx, 10*time.Second) + defer cancel() + if err := s.Shutdown(shutdownCtx); err != nil { + log.Error("error shutting down http server: %v", err) + } else { + log.Info("Gracefully stopped http server on %v", s.Addr) + } +} + +func createHandler(d *sqlx.DB, serverSettings *types.Settings) http.Handler { + var router = http.NewServeMux() + + authDb := db.NewAuthSqlite(d) + + randomService := service.NewRandom() + clockService := service.NewClock() + mailService := service.NewMail(serverSettings) + + authService := service.NewAuth(authDb, randomService, clockService, mailService, serverSettings) + accountService := service.NewAccount(d, randomService, clockService) + treasureChestService := service.NewTreasureChest(d, randomService, clockService) + transactionService := service.NewTransaction(d, randomService, clockService) + transactionRecurringService := service.NewTransactionRecurring(d, randomService, clockService, transactionService) + + render := handler.NewRender() + indexHandler := handler.NewIndex(render) + authHandler := handler.NewAuth(authService, render) + accountHandler := handler.NewAccount(accountService, render) + treasureChestHandler := handler.NewTreasureChest(treasureChestService, transactionRecurringService, render) + transactionHandler := handler.NewTransaction(transactionService, accountService, treasureChestService, render) + transactionRecurringHandler := handler.NewTransactionRecurring(transactionRecurringService, render) + + indexHandler.Handle(router) + accountHandler.Handle(router) + treasureChestHandler.Handle(router) + authHandler.Handle(router) + transactionHandler.Handle(router) + transactionRecurringHandler.Handle(router) + + // Serve static files (CSS, JS and images) + router.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static/")))) + + return middleware.Wrapper( + router, + middleware.GenerateRecurringTransactions(transactionRecurringService), + middleware.SecurityHeaders(serverSettings), + middleware.CacheControl, + middleware.CrossSiteRequestForgery(authService), + middleware.Authenticate(authService), + middleware.Gzip, + middleware.Log, + ) +} diff --git a/handler/account.go b/internal/handler/account.go similarity index 93% rename from handler/account.go rename to internal/handler/account.go index fedcc2e..85765c5 100644 --- a/handler/account.go +++ b/internal/handler/account.go @@ -2,11 +2,11 @@ package handler import ( "net/http" - "spend-sparrow/handler/middleware" - "spend-sparrow/service" - t "spend-sparrow/template/account" - "spend-sparrow/types" - "spend-sparrow/utils" + "spend-sparrow/internal/handler/middleware" + "spend-sparrow/internal/service" + t "spend-sparrow/internal/template/account" + "spend-sparrow/internal/types" + "spend-sparrow/internal/utils" "github.com/a-h/templ" ) diff --git a/handler/auth.go b/internal/handler/auth.go similarity index 97% rename from handler/auth.go rename to internal/handler/auth.go index 88f99cc..75bcb9c 100644 --- a/handler/auth.go +++ b/internal/handler/auth.go @@ -1,12 +1,12 @@ package handler import ( - "spend-sparrow/handler/middleware" - "spend-sparrow/log" - "spend-sparrow/service" - "spend-sparrow/template/auth" - "spend-sparrow/types" - "spend-sparrow/utils" + "spend-sparrow/internal/handler/middleware" + "spend-sparrow/internal/log" + "spend-sparrow/internal/service" + "spend-sparrow/internal/template/auth" + "spend-sparrow/internal/types" + "spend-sparrow/internal/utils" "errors" "net/http" diff --git a/handler/error.go b/internal/handler/error.go similarity index 90% rename from handler/error.go rename to internal/handler/error.go index b5fd1d9..cbf7a77 100644 --- a/handler/error.go +++ b/internal/handler/error.go @@ -3,9 +3,9 @@ package handler import ( "errors" "net/http" - "spend-sparrow/db" - "spend-sparrow/service" - "spend-sparrow/utils" + "spend-sparrow/internal/db" + "spend-sparrow/internal/service" + "spend-sparrow/internal/utils" "strings" ) diff --git a/handler/middleware/authenticate.go b/internal/handler/middleware/authenticate.go similarity index 95% rename from handler/middleware/authenticate.go rename to internal/handler/middleware/authenticate.go index 2742f49..bc7928a 100644 --- a/handler/middleware/authenticate.go +++ b/internal/handler/middleware/authenticate.go @@ -4,8 +4,8 @@ import ( "context" "net/http" - "spend-sparrow/service" - "spend-sparrow/types" + "spend-sparrow/internal/service" + "spend-sparrow/internal/types" ) type ContextKey string diff --git a/handler/middleware/cache_control.go b/internal/handler/middleware/cache_control.go similarity index 100% rename from handler/middleware/cache_control.go rename to internal/handler/middleware/cache_control.go diff --git a/handler/middleware/cross_site_request_forgery.go b/internal/handler/middleware/cross_site_request_forgery.go similarity index 92% rename from handler/middleware/cross_site_request_forgery.go rename to internal/handler/middleware/cross_site_request_forgery.go index d165978..307b886 100644 --- a/handler/middleware/cross_site_request_forgery.go +++ b/internal/handler/middleware/cross_site_request_forgery.go @@ -4,10 +4,10 @@ import ( "net/http" "strings" - "spend-sparrow/log" - "spend-sparrow/service" - "spend-sparrow/types" - "spend-sparrow/utils" + "spend-sparrow/internal/log" + "spend-sparrow/internal/service" + "spend-sparrow/internal/types" + "spend-sparrow/internal/utils" ) type csrfResponseWriter struct { diff --git a/handler/middleware/default.go b/internal/handler/middleware/default.go similarity index 100% rename from handler/middleware/default.go rename to internal/handler/middleware/default.go diff --git a/handler/middleware/generate_recurring_transactions.go b/internal/handler/middleware/generate_recurring_transactions.go similarity index 93% rename from handler/middleware/generate_recurring_transactions.go rename to internal/handler/middleware/generate_recurring_transactions.go index fe8fdee..5a5f1c9 100644 --- a/handler/middleware/generate_recurring_transactions.go +++ b/internal/handler/middleware/generate_recurring_transactions.go @@ -2,7 +2,7 @@ package middleware import ( "net/http" - "spend-sparrow/service" + "spend-sparrow/internal/service" ) func GenerateRecurringTransactions(transactionRecurring service.TransactionRecurring) func(http.Handler) http.Handler { diff --git a/handler/middleware/gzip.go b/internal/handler/middleware/gzip.go similarity index 96% rename from handler/middleware/gzip.go rename to internal/handler/middleware/gzip.go index 1d73f8e..626bba1 100644 --- a/handler/middleware/gzip.go +++ b/internal/handler/middleware/gzip.go @@ -7,7 +7,7 @@ import ( "net/http" "strings" - "spend-sparrow/log" + "spend-sparrow/internal/log" ) type gzipResponseWriter struct { diff --git a/handler/middleware/logger.go b/internal/handler/middleware/logger.go similarity index 97% rename from handler/middleware/logger.go rename to internal/handler/middleware/logger.go index f0ec9a0..c374929 100644 --- a/handler/middleware/logger.go +++ b/internal/handler/middleware/logger.go @@ -5,7 +5,7 @@ import ( "strconv" "time" - "spend-sparrow/log" + "spend-sparrow/internal/log" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" diff --git a/handler/middleware/security_headers.go b/internal/handler/middleware/security_headers.go similarity index 97% rename from handler/middleware/security_headers.go rename to internal/handler/middleware/security_headers.go index 948a159..c024295 100644 --- a/handler/middleware/security_headers.go +++ b/internal/handler/middleware/security_headers.go @@ -3,7 +3,7 @@ package middleware import ( "net/http" - "spend-sparrow/types" + "spend-sparrow/internal/types" ) func SecurityHeaders(serverSettings *types.Settings) func(http.Handler) http.Handler { diff --git a/handler/middleware/wrapper.go b/internal/handler/middleware/wrapper.go similarity index 100% rename from handler/middleware/wrapper.go rename to internal/handler/middleware/wrapper.go diff --git a/handler/render.go b/internal/handler/render.go similarity index 90% rename from handler/render.go rename to internal/handler/render.go index 7a447a1..fd2ac0e 100644 --- a/handler/render.go +++ b/internal/handler/render.go @@ -1,10 +1,10 @@ package handler import ( - "spend-sparrow/log" - "spend-sparrow/template" - "spend-sparrow/template/auth" - "spend-sparrow/types" + "spend-sparrow/internal/log" + "spend-sparrow/internal/template" + "spend-sparrow/internal/template/auth" + "spend-sparrow/internal/types" "net/http" diff --git a/handler/root_and_404.go b/internal/handler/root_and_404.go similarity index 92% rename from handler/root_and_404.go rename to internal/handler/root_and_404.go index 2638244..eab58e6 100644 --- a/handler/root_and_404.go +++ b/internal/handler/root_and_404.go @@ -2,8 +2,8 @@ package handler import ( "net/http" - "spend-sparrow/handler/middleware" - "spend-sparrow/template" + "spend-sparrow/internal/handler/middleware" + "spend-sparrow/internal/template" "github.com/a-h/templ" ) diff --git a/handler/transaction.go b/internal/handler/transaction.go similarity index 97% rename from handler/transaction.go rename to internal/handler/transaction.go index 22a8d59..d335bbf 100644 --- a/handler/transaction.go +++ b/internal/handler/transaction.go @@ -3,11 +3,11 @@ package handler import ( "fmt" "net/http" - "spend-sparrow/handler/middleware" - "spend-sparrow/service" - t "spend-sparrow/template/transaction" - "spend-sparrow/types" - "spend-sparrow/utils" + "spend-sparrow/internal/handler/middleware" + "spend-sparrow/internal/service" + t "spend-sparrow/internal/template/transaction" + "spend-sparrow/internal/types" + "spend-sparrow/internal/utils" "strconv" "time" diff --git a/handler/transaction_recurring.go b/internal/handler/transaction_recurring.go similarity index 94% rename from handler/transaction_recurring.go rename to internal/handler/transaction_recurring.go index cd17f3f..4f8392e 100644 --- a/handler/transaction_recurring.go +++ b/internal/handler/transaction_recurring.go @@ -2,11 +2,11 @@ package handler import ( "net/http" - "spend-sparrow/handler/middleware" - "spend-sparrow/service" - t "spend-sparrow/template/transaction_recurring" - "spend-sparrow/types" - "spend-sparrow/utils" + "spend-sparrow/internal/handler/middleware" + "spend-sparrow/internal/service" + t "spend-sparrow/internal/template/transaction_recurring" + "spend-sparrow/internal/types" + "spend-sparrow/internal/utils" ) type TransactionRecurring interface { diff --git a/handler/treasure_chest.go b/internal/handler/treasure_chest.go similarity index 94% rename from handler/treasure_chest.go rename to internal/handler/treasure_chest.go index 0d016d2..438fd06 100644 --- a/handler/treasure_chest.go +++ b/internal/handler/treasure_chest.go @@ -2,12 +2,12 @@ package handler import ( "net/http" - "spend-sparrow/handler/middleware" - "spend-sparrow/service" - tr "spend-sparrow/template/transaction_recurring" - t "spend-sparrow/template/treasurechest" - "spend-sparrow/types" - "spend-sparrow/utils" + "spend-sparrow/internal/handler/middleware" + "spend-sparrow/internal/service" + tr "spend-sparrow/internal/template/transaction_recurring" + t "spend-sparrow/internal/template/treasurechest" + "spend-sparrow/internal/types" + "spend-sparrow/internal/utils" "github.com/a-h/templ" "github.com/google/uuid" diff --git a/log/default.go b/internal/log/default.go similarity index 100% rename from log/default.go rename to internal/log/default.go diff --git a/service/account.go b/internal/service/account.go similarity index 98% rename from service/account.go rename to internal/service/account.go index ce5174b..0749fc3 100644 --- a/service/account.go +++ b/internal/service/account.go @@ -3,10 +3,9 @@ package service import ( "errors" "fmt" - - "spend-sparrow/db" - "spend-sparrow/log" - "spend-sparrow/types" + "spend-sparrow/internal/db" + "spend-sparrow/internal/log" + "spend-sparrow/internal/types" "github.com/google/uuid" "github.com/jmoiron/sqlx" diff --git a/service/auth.go b/internal/service/auth.go similarity index 98% rename from service/auth.go rename to internal/service/auth.go index 77408cb..f9d80c4 100644 --- a/service/auth.go +++ b/internal/service/auth.go @@ -5,14 +5,13 @@ import ( "crypto/subtle" "errors" "net/mail" + "spend-sparrow/internal/db" + "spend-sparrow/internal/log" + mailTemplate "spend-sparrow/internal/template/mail" + "spend-sparrow/internal/types" "strings" "time" - "spend-sparrow/db" - "spend-sparrow/log" - mailTemplate "spend-sparrow/template/mail" - "spend-sparrow/types" - "github.com/google/uuid" "golang.org/x/crypto/argon2" ) diff --git a/service/clock.go b/internal/service/clock.go similarity index 100% rename from service/clock.go rename to internal/service/clock.go diff --git a/service/default.go b/internal/service/default.go similarity index 100% rename from service/default.go rename to internal/service/default.go diff --git a/service/error.go b/internal/service/error.go similarity index 100% rename from service/error.go rename to internal/service/error.go diff --git a/service/mail.go b/internal/service/mail.go similarity index 94% rename from service/mail.go rename to internal/service/mail.go index 4efa662..7bca066 100644 --- a/service/mail.go +++ b/internal/service/mail.go @@ -1,11 +1,10 @@ package service import ( - "spend-sparrow/log" - "spend-sparrow/types" - "fmt" "net/smtp" + "spend-sparrow/internal/log" + "spend-sparrow/internal/types" ) type Mail interface { diff --git a/service/random_generator.go b/internal/service/random_generator.go similarity index 94% rename from service/random_generator.go rename to internal/service/random_generator.go index 9dbc269..bce038a 100644 --- a/service/random_generator.go +++ b/internal/service/random_generator.go @@ -1,11 +1,10 @@ package service import ( - "spend-sparrow/log" - "spend-sparrow/types" - "crypto/rand" "encoding/base64" + "spend-sparrow/internal/log" + "spend-sparrow/internal/types" "github.com/google/uuid" ) diff --git a/service/transaction.go b/internal/service/transaction.go similarity index 99% rename from service/transaction.go rename to internal/service/transaction.go index ab0a130..9415871 100644 --- a/service/transaction.go +++ b/internal/service/transaction.go @@ -3,9 +3,9 @@ package service import ( "errors" "fmt" - "spend-sparrow/db" - "spend-sparrow/log" - "spend-sparrow/types" + "spend-sparrow/internal/db" + "spend-sparrow/internal/log" + "spend-sparrow/internal/types" "time" "github.com/google/uuid" diff --git a/service/transaction_recurring.go b/internal/service/transaction_recurring.go similarity index 99% rename from service/transaction_recurring.go rename to internal/service/transaction_recurring.go index f5a776c..f010e4d 100644 --- a/service/transaction_recurring.go +++ b/internal/service/transaction_recurring.go @@ -3,13 +3,12 @@ package service import ( "errors" "fmt" + "spend-sparrow/internal/db" + "spend-sparrow/internal/log" + "spend-sparrow/internal/types" "strconv" "time" - "spend-sparrow/db" - "spend-sparrow/log" - "spend-sparrow/types" - "github.com/google/uuid" "github.com/jmoiron/sqlx" "github.com/prometheus/client_golang/prometheus" diff --git a/service/treasure_chest.go b/internal/service/treasure_chest.go similarity index 98% rename from service/treasure_chest.go rename to internal/service/treasure_chest.go index 482db4d..d955482 100644 --- a/service/treasure_chest.go +++ b/internal/service/treasure_chest.go @@ -4,10 +4,9 @@ import ( "errors" "fmt" "slices" - - "spend-sparrow/db" - "spend-sparrow/log" - "spend-sparrow/types" + "spend-sparrow/internal/db" + "spend-sparrow/internal/log" + "spend-sparrow/internal/types" "github.com/google/uuid" "github.com/jmoiron/sqlx" diff --git a/internal/service/treasure_chest_test.go b/internal/service/treasure_chest_test.go new file mode 100644 index 0000000..f5d7fe1 --- /dev/null +++ b/internal/service/treasure_chest_test.go @@ -0,0 +1,10 @@ +package service_test + +// import ( +// "spned-sparrow" +// ) +// +// func TestTreasureChestProhibitDeleteIfTransactionRecurringExists(t *testing.T) { +// service := main.Setup +// +// } diff --git a/template/account/account.templ b/internal/template/account/account.templ similarity index 97% rename from template/account/account.templ rename to internal/template/account/account.templ index 8ad3e07..f0706ae 100644 --- a/template/account/account.templ +++ b/internal/template/account/account.templ @@ -1,8 +1,8 @@ package account import "fmt" -import "spend-sparrow/template/svg" -import "spend-sparrow/types" +import "spend-sparrow/internal/template/svg" +import "spend-sparrow/internal/types" templ Account(accounts []*types.Account) {
diff --git a/template/account/default.go b/internal/template/account/default.go similarity index 100% rename from template/account/default.go rename to internal/template/account/default.go diff --git a/template/auth/change_password.templ b/internal/template/auth/change_password.templ similarity index 100% rename from template/auth/change_password.templ rename to internal/template/auth/change_password.templ diff --git a/template/auth/default.go b/internal/template/auth/default.go similarity index 100% rename from template/auth/default.go rename to internal/template/auth/default.go diff --git a/template/auth/delete_account.templ b/internal/template/auth/delete_account.templ similarity index 100% rename from template/auth/delete_account.templ rename to internal/template/auth/delete_account.templ diff --git a/template/auth/reset_password.templ b/internal/template/auth/reset_password.templ similarity index 100% rename from template/auth/reset_password.templ rename to internal/template/auth/reset_password.templ diff --git a/template/auth/sign_in_or_up.templ b/internal/template/auth/sign_in_or_up.templ similarity index 100% rename from template/auth/sign_in_or_up.templ rename to internal/template/auth/sign_in_or_up.templ diff --git a/template/auth/user.templ b/internal/template/auth/user.templ similarity index 100% rename from template/auth/user.templ rename to internal/template/auth/user.templ diff --git a/template/auth/verify.templ b/internal/template/auth/verify.templ similarity index 100% rename from template/auth/verify.templ rename to internal/template/auth/verify.templ diff --git a/template/auth/verify_response.templ b/internal/template/auth/verify_response.templ similarity index 100% rename from template/auth/verify_response.templ rename to internal/template/auth/verify_response.templ diff --git a/template/dashboard.templ b/internal/template/dashboard.templ similarity index 100% rename from template/dashboard.templ rename to internal/template/dashboard.templ diff --git a/template/default.go b/internal/template/default.go similarity index 100% rename from template/default.go rename to internal/template/default.go diff --git a/template/layout.templ b/internal/template/layout.templ similarity index 100% rename from template/layout.templ rename to internal/template/layout.templ diff --git a/template/mail/default.go b/internal/template/mail/default.go similarity index 100% rename from template/mail/default.go rename to internal/template/mail/default.go diff --git a/template/mail/register.templ b/internal/template/mail/register.templ similarity index 100% rename from template/mail/register.templ rename to internal/template/mail/register.templ diff --git a/template/mail/reset-password.templ b/internal/template/mail/reset-password.templ similarity index 100% rename from template/mail/reset-password.templ rename to internal/template/mail/reset-password.templ diff --git a/template/not_found.templ b/internal/template/not_found.templ similarity index 100% rename from template/not_found.templ rename to internal/template/not_found.templ diff --git a/template/root.templ b/internal/template/root.templ similarity index 100% rename from template/root.templ rename to internal/template/root.templ diff --git a/template/svg/default.templ b/internal/template/svg/default.templ similarity index 100% rename from template/svg/default.templ rename to internal/template/svg/default.templ diff --git a/template/transaction/default.go b/internal/template/transaction/default.go similarity index 100% rename from template/transaction/default.go rename to internal/template/transaction/default.go diff --git a/template/transaction/transaction.templ b/internal/template/transaction/transaction.templ similarity index 98% rename from template/transaction/transaction.templ rename to internal/template/transaction/transaction.templ index ec0a959..1c72c5a 100644 --- a/template/transaction/transaction.templ +++ b/internal/template/transaction/transaction.templ @@ -2,8 +2,8 @@ package transaction import "fmt" import "time" -import "spend-sparrow/template/svg" -import "spend-sparrow/types" +import "spend-sparrow/internal/template/svg" +import "spend-sparrow/internal/types" import "github.com/google/uuid" templ Transaction(items templ.Component, filter types.TransactionItemsFilter, accounts []*types.Account, treasureChests []*types.TreasureChest) { diff --git a/template/transaction_recurring/default.go b/internal/template/transaction_recurring/default.go similarity index 100% rename from template/transaction_recurring/default.go rename to internal/template/transaction_recurring/default.go diff --git a/template/transaction_recurring/transaction_recurring.templ b/internal/template/transaction_recurring/transaction_recurring.templ similarity index 98% rename from template/transaction_recurring/transaction_recurring.templ rename to internal/template/transaction_recurring/transaction_recurring.templ index 0350490..fd19938 100644 --- a/template/transaction_recurring/transaction_recurring.templ +++ b/internal/template/transaction_recurring/transaction_recurring.templ @@ -2,8 +2,8 @@ package transaction_recurring import "fmt" import "time" -import "spend-sparrow/template/svg" -import "spend-sparrow/types" +import "spend-sparrow/internal/template/svg" +import "spend-sparrow/internal/types" templ TransactionRecurringItems(transactionsRecurring []*types.TransactionRecurring, editId, accountId, treasureChestId string) { diff --git a/template/treasurechest/default.go b/internal/template/treasurechest/default.go similarity index 100% rename from template/treasurechest/default.go rename to internal/template/treasurechest/default.go diff --git a/template/treasurechest/treasure_chest.templ b/internal/template/treasurechest/treasure_chest.templ similarity index 98% rename from template/treasurechest/treasure_chest.templ rename to internal/template/treasurechest/treasure_chest.templ index 8e8f981..5115601 100644 --- a/template/treasurechest/treasure_chest.templ +++ b/internal/template/treasurechest/treasure_chest.templ @@ -1,8 +1,8 @@ package treasurechest import "fmt" -import "spend-sparrow/template/svg" -import "spend-sparrow/types" +import "spend-sparrow/internal/template/svg" +import "spend-sparrow/internal/types" import "github.com/google/uuid" templ TreasureChest(treasureChests []*types.TreasureChest, monthlySums map[uuid.UUID]int64) { diff --git a/types/account.go b/internal/types/account.go similarity index 100% rename from types/account.go rename to internal/types/account.go diff --git a/types/auth.go b/internal/types/auth.go similarity index 100% rename from types/auth.go rename to internal/types/auth.go diff --git a/types/settings.go b/internal/types/settings.go similarity index 98% rename from types/settings.go rename to internal/types/settings.go index c8afc8b..3083652 100644 --- a/types/settings.go +++ b/internal/types/settings.go @@ -1,7 +1,7 @@ package types import ( - "spend-sparrow/log" + "spend-sparrow/internal/log" ) type Settings struct { diff --git a/types/transaction.go b/internal/types/transaction.go similarity index 100% rename from types/transaction.go rename to internal/types/transaction.go diff --git a/types/transaction_recurring.go b/internal/types/transaction_recurring.go similarity index 100% rename from types/transaction_recurring.go rename to internal/types/transaction_recurring.go diff --git a/types/treasure_chest.go b/internal/types/treasure_chest.go similarity index 100% rename from types/treasure_chest.go rename to internal/types/treasure_chest.go diff --git a/types/types.go b/internal/types/types.go similarity index 100% rename from types/types.go rename to internal/types/types.go diff --git a/utils/http.go b/internal/utils/http.go similarity index 97% rename from utils/http.go rename to internal/utils/http.go index d4c0c34..233edee 100644 --- a/utils/http.go +++ b/internal/utils/http.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "spend-sparrow/log" + "spend-sparrow/internal/log" ) func TriggerToast(w http.ResponseWriter, r *http.Request, class string, message string) { diff --git a/main.go b/main.go index 760b984..1654383 100644 --- a/main.go +++ b/main.go @@ -1,27 +1,14 @@ package main import ( - "errors" - "fmt" - "spend-sparrow/db" - "spend-sparrow/handler" - "spend-sparrow/handler/middleware" - "spend-sparrow/log" - "spend-sparrow/service" - "spend-sparrow/types" - "context" - "net/http" "os" - "os/signal" - "sync" - "syscall" - "time" + "spend-sparrow/internal" + "spend-sparrow/internal/log" "github.com/jmoiron/sqlx" "github.com/joho/godotenv" _ "github.com/mattn/go-sqlite3" - "github.com/prometheus/client_golang/prometheus/promhttp" ) func main() { @@ -39,121 +26,9 @@ func main() { log.Fatal("Could not close Database data.db: %v", err) }() - err = run(context.Background(), db, os.Getenv) + err = internal.Run(context.Background(), db, "", os.Getenv) if err != nil { log.Error("Error running server: %v", err) return } } - -func run(ctx context.Context, database *sqlx.DB, env func(string) string) error { - ctx, cancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) - defer cancel() - - log.Info("Starting server...") - - // init server settings - serverSettings := types.NewSettingsFromEnv(env) - - // init db - err := db.RunMigrations(database, "") - if err != nil { - return fmt.Errorf("could not run migrations: %w", err) - } - - // init servers - var prometheusServer *http.Server - if serverSettings.PrometheusEnabled { - prometheusServer := &http.Server{ - Addr: ":8081", - Handler: promhttp.Handler(), - ReadHeaderTimeout: 10 * time.Second, - } - go startServer(prometheusServer) - } - - httpServer := &http.Server{ - Addr: ":" + serverSettings.Port, - Handler: createHandler(database, serverSettings), - ReadHeaderTimeout: 10 * time.Second, - } - go startServer(httpServer) - - // graceful shutdown - var wg sync.WaitGroup - wg.Add(2) - go shutdownServer(httpServer, ctx, &wg) - go shutdownServer(prometheusServer, ctx, &wg) - wg.Wait() - - return nil -} - -func startServer(s *http.Server) { - log.Info("Starting server on %q", s.Addr) - if err := s.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Error("error listening and serving: %v", err) - } -} - -func shutdownServer(s *http.Server, ctx context.Context, wg *sync.WaitGroup) { - defer wg.Done() - if s == nil { - return - } - - <-ctx.Done() - shutdownCtx := context.Background() - shutdownCtx, cancel := context.WithTimeout(shutdownCtx, 10*time.Second) - defer cancel() - if err := s.Shutdown(shutdownCtx); err != nil { - log.Error("error shutting down http server: %v", err) - } else { - log.Info("Gracefully stopped http server on %v", s.Addr) - } -} - -func createHandler(d *sqlx.DB, serverSettings *types.Settings) http.Handler { - var router = http.NewServeMux() - - authDb := db.NewAuthSqlite(d) - - randomService := service.NewRandom() - clockService := service.NewClock() - mailService := service.NewMail(serverSettings) - - authService := service.NewAuth(authDb, randomService, clockService, mailService, serverSettings) - accountService := service.NewAccount(d, randomService, clockService) - treasureChestService := service.NewTreasureChest(d, randomService, clockService) - transactionService := service.NewTransaction(d, randomService, clockService) - transactionRecurringService := service.NewTransactionRecurring(d, randomService, clockService, transactionService) - - render := handler.NewRender() - indexHandler := handler.NewIndex(render) - authHandler := handler.NewAuth(authService, render) - accountHandler := handler.NewAccount(accountService, render) - treasureChestHandler := handler.NewTreasureChest(treasureChestService, transactionRecurringService, render) - transactionHandler := handler.NewTransaction(transactionService, accountService, treasureChestService, render) - transactionRecurringHandler := handler.NewTransactionRecurring(transactionRecurringService, render) - - indexHandler.Handle(router) - accountHandler.Handle(router) - treasureChestHandler.Handle(router) - authHandler.Handle(router) - transactionHandler.Handle(router) - transactionRecurringHandler.Handle(router) - - // Serve static files (CSS, JS and images) - router.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static/")))) - - return middleware.Wrapper( - router, - middleware.GenerateRecurringTransactions(transactionRecurringService), - middleware.SecurityHeaders(serverSettings), - middleware.CacheControl, - middleware.CrossSiteRequestForgery(authService), - middleware.Authenticate(authService), - middleware.Gzip, - middleware.Log, - ) -} diff --git a/service/auth_test.go b/test/auth2_test.go similarity index 97% rename from service/auth_test.go rename to test/auth2_test.go index d69330d..6483eb9 100644 --- a/service/auth_test.go +++ b/test/auth2_test.go @@ -1,11 +1,10 @@ -package service_test +package test import ( - "spend-sparrow/db" + "spend-sparrow/internal/db" + "spend-sparrow/internal/service" + "spend-sparrow/internal/types" "spend-sparrow/mocks" - "spend-sparrow/service" - "spend-sparrow/types" - "strings" "testing" "time" diff --git a/db/auth_test.go b/test/auth_test.go similarity index 98% rename from db/auth_test.go rename to test/auth_test.go index 4e87066..3e69fa6 100644 --- a/db/auth_test.go +++ b/test/auth_test.go @@ -1,8 +1,8 @@ -package db_test +package test import ( - "spend-sparrow/db" - "spend-sparrow/types" + "spend-sparrow/internal/db" + "spend-sparrow/internal/types" "testing" "time" diff --git a/main_test.go b/test/main_test.go similarity index 99% rename from main_test.go rename to test/main_test.go index b87ba03..0f59f66 100644 --- a/main_test.go +++ b/test/main_test.go @@ -1,4 +1,4 @@ -package main +package test import ( "context" @@ -12,8 +12,9 @@ import ( "testing" "time" - "spend-sparrow/service" - "spend-sparrow/types" + "spend-sparrow/internal" + "spend-sparrow/internal/service" + "spend-sparrow/internal/types" "github.com/google/uuid" "github.com/jmoiron/sqlx" @@ -1979,7 +1980,7 @@ func setupIntegrationTest(t *testing.T) (*sqlx.DB, string, context.Context) { testPort += 1024 go func() { - _ = run(ctx, db, getEnv(testPort)) + _ = internal.Run(ctx, db, "../", getEnv(testPort)) }() basePath := "http://localhost:" + strconv.Itoa(int(testPort)) diff --git a/test/treasure_chest_test.go b/test/treasure_chest_test.go new file mode 100644 index 0000000..56e5404 --- /dev/null +++ b/test/treasure_chest_test.go @@ -0,0 +1 @@ +package test