feat: extract into remaining packages
All checks were successful
Build and Push Docker Image / Build-And-Push-Docker-Image (push) Successful in 1m19s

There has been a cyclic dependency.
transaction
	-> treasure_chest
	-> transaction_recurring
	-> transaction

This has been temporarily solved by moving the GenerateTransactions
function into the transaction package. In the future, this function has
to be rewritten to use a proper Service insteas of direct DB access or
replaced with a different system entirely.
This commit is contained in:
2025-12-31 22:24:21 +01:00
parent 6de8d8fb10
commit 1be46780bb
29 changed files with 230 additions and 251 deletions

View File

@@ -8,7 +8,6 @@ import (
"spend-sparrow/internal/auth_types"
"spend-sparrow/internal/authentication/template"
"spend-sparrow/internal/core"
"spend-sparrow/internal/utils"
"time"
)
@@ -62,9 +61,9 @@ func (handler HandlerImpl) handleSignInPage() http.HandlerFunc {
user := core.GetUser(r)
if user != nil {
if !user.EmailVerified {
utils.DoRedirect(w, r, "/auth/verify")
core.DoRedirect(w, r, "/auth/verify")
} else {
utils.DoRedirect(w, r, "/")
core.DoRedirect(w, r, "/")
}
return
}
@@ -79,7 +78,7 @@ func (handler HandlerImpl) handleSignIn() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
core.UpdateSpan(r)
user, err := utils.WaitMinimumTime(securityWaitDuration, func() (*auth_types.User, error) {
user, err := core.WaitMinimumTime(securityWaitDuration, func() (*auth_types.User, error) {
session := core.GetSession(r)
email := r.FormValue("email")
password := r.FormValue("password")
@@ -97,17 +96,17 @@ func (handler HandlerImpl) handleSignIn() http.HandlerFunc {
if err != nil {
if errors.Is(err, ErrInvalidCredentials) {
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "Invalid email or password", http.StatusUnauthorized)
core.TriggerToastWithStatus(r.Context(), w, r, "error", "Invalid email or password", http.StatusUnauthorized)
} else {
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "An error occurred", http.StatusInternalServerError)
core.TriggerToastWithStatus(r.Context(), w, r, "error", "An error occurred", http.StatusInternalServerError)
}
return
}
if user.EmailVerified {
utils.DoRedirect(w, r, "/")
core.DoRedirect(w, r, "/")
} else {
utils.DoRedirect(w, r, "/auth/verify")
core.DoRedirect(w, r, "/auth/verify")
}
}
}
@@ -120,9 +119,9 @@ func (handler HandlerImpl) handleSignUpPage() http.HandlerFunc {
if user != nil {
if !user.EmailVerified {
utils.DoRedirect(w, r, "/auth/verify")
core.DoRedirect(w, r, "/auth/verify")
} else {
utils.DoRedirect(w, r, "/")
core.DoRedirect(w, r, "/")
}
return
}
@@ -138,12 +137,12 @@ func (handler HandlerImpl) handleSignUpVerifyPage() http.HandlerFunc {
user := core.GetUser(r)
if user == nil {
utils.DoRedirect(w, r, "/auth/signin")
core.DoRedirect(w, r, "/auth/signin")
return
}
if user.EmailVerified {
utils.DoRedirect(w, r, "/")
core.DoRedirect(w, r, "/")
return
}
@@ -158,7 +157,7 @@ func (handler HandlerImpl) handleVerifyResendComp() http.HandlerFunc {
user := core.GetUser(r)
if user == nil {
utils.DoRedirect(w, r, "/auth/signin")
core.DoRedirect(w, r, "/auth/signin")
return
}
@@ -200,7 +199,7 @@ func (handler HandlerImpl) handleSignUp() http.HandlerFunc {
var email = r.FormValue("email")
var password = r.FormValue("password")
_, err := utils.WaitMinimumTime(securityWaitDuration, func() (any, error) {
_, err := core.WaitMinimumTime(securityWaitDuration, func() (any, error) {
slog.InfoContext(r.Context(), "signing up", "email", email)
user, err := handler.service.SignUp(r.Context(), email, password)
if err != nil {
@@ -215,19 +214,19 @@ func (handler HandlerImpl) handleSignUp() http.HandlerFunc {
if err != nil {
switch {
case errors.Is(err, core.ErrInternal):
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "An error occurred", http.StatusInternalServerError)
core.TriggerToastWithStatus(r.Context(), w, r, "error", "An error occurred", http.StatusInternalServerError)
return
case errors.Is(err, ErrInvalidEmail):
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "The email provided is invalid", http.StatusBadRequest)
core.TriggerToastWithStatus(r.Context(), w, r, "error", "The email provided is invalid", http.StatusBadRequest)
return
case errors.Is(err, ErrInvalidPassword):
utils.TriggerToastWithStatus(r.Context(), w, r, "error", ErrInvalidPassword.Error(), http.StatusBadRequest)
core.TriggerToastWithStatus(r.Context(), w, r, "error", ErrInvalidPassword.Error(), http.StatusBadRequest)
return
}
// If err is "service.ErrAccountExists", then just continue
}
utils.TriggerToastWithStatus(r.Context(), w, r, "success", "An activation link has been send to your email", http.StatusOK)
core.TriggerToastWithStatus(r.Context(), w, r, "success", "An activation link has been send to your email", http.StatusOK)
}
}
@@ -256,7 +255,7 @@ func (handler HandlerImpl) handleSignOut() http.HandlerFunc {
}
http.SetCookie(w, &c)
utils.DoRedirect(w, r, "/")
core.DoRedirect(w, r, "/")
}
}
@@ -266,7 +265,7 @@ func (handler HandlerImpl) handleDeleteAccountPage() http.HandlerFunc {
user := core.GetUser(r)
if user == nil {
utils.DoRedirect(w, r, "/auth/signin")
core.DoRedirect(w, r, "/auth/signin")
return
}
@@ -281,7 +280,7 @@ func (handler HandlerImpl) handleDeleteAccountComp() http.HandlerFunc {
user := core.GetUser(r)
if user == nil {
utils.DoRedirect(w, r, "/auth/signin")
core.DoRedirect(w, r, "/auth/signin")
return
}
@@ -290,14 +289,14 @@ func (handler HandlerImpl) handleDeleteAccountComp() http.HandlerFunc {
err := handler.service.DeleteAccount(r.Context(), user, password)
if err != nil {
if errors.Is(err, ErrInvalidCredentials) {
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "Password not correct", http.StatusBadRequest)
core.TriggerToastWithStatus(r.Context(), w, r, "error", "Password not correct", http.StatusBadRequest)
} else {
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "Internal Server Error", http.StatusInternalServerError)
core.TriggerToastWithStatus(r.Context(), w, r, "error", "Internal Server Error", http.StatusInternalServerError)
}
return
}
utils.DoRedirect(w, r, "/")
core.DoRedirect(w, r, "/")
}
}
@@ -310,7 +309,7 @@ func (handler HandlerImpl) handleChangePasswordPage() http.HandlerFunc {
user := core.GetUser(r)
if user == nil && !isPasswordReset {
utils.DoRedirect(w, r, "/auth/signin")
core.DoRedirect(w, r, "/auth/signin")
return
}
@@ -326,7 +325,7 @@ func (handler HandlerImpl) handleChangePasswordComp() http.HandlerFunc {
session := core.GetSession(r)
user := core.GetUser(r)
if session == nil || user == nil {
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "Unathorized", http.StatusUnauthorized)
core.TriggerToastWithStatus(r.Context(), w, r, "error", "Unathorized", http.StatusUnauthorized)
return
}
@@ -335,11 +334,11 @@ func (handler HandlerImpl) handleChangePasswordComp() http.HandlerFunc {
err := handler.service.ChangePassword(r.Context(), user, session.Id, currPass, newPass)
if err != nil {
utils.TriggerToastWithStatus(r.Context(), w, r, "error", err.Error(), http.StatusBadRequest)
core.TriggerToastWithStatus(r.Context(), w, r, "error", err.Error(), http.StatusBadRequest)
return
}
utils.TriggerToastWithStatus(r.Context(), w, r, "success", "Password changed", http.StatusOK)
core.TriggerToastWithStatus(r.Context(), w, r, "success", "Password changed", http.StatusOK)
}
}
@@ -349,7 +348,7 @@ func (handler HandlerImpl) handleForgotPasswordPage() http.HandlerFunc {
user := core.GetUser(r)
if user != nil {
utils.DoRedirect(w, r, "/")
core.DoRedirect(w, r, "/")
return
}
@@ -364,19 +363,19 @@ func (handler HandlerImpl) handleForgotPasswordComp() http.HandlerFunc {
email := r.FormValue("email")
if email == "" {
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "Please enter an email", http.StatusBadRequest)
core.TriggerToastWithStatus(r.Context(), w, r, "error", "Please enter an email", http.StatusBadRequest)
return
}
_, err := utils.WaitMinimumTime(securityWaitDuration, func() (any, error) {
_, err := core.WaitMinimumTime(securityWaitDuration, func() (any, error) {
err := handler.service.SendForgotPasswordMail(r.Context(), email)
return nil, err
})
if err != nil {
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "Internal Server Error", http.StatusInternalServerError)
core.TriggerToastWithStatus(r.Context(), w, r, "error", "Internal Server Error", http.StatusInternalServerError)
} else {
utils.TriggerToastWithStatus(r.Context(), w, r, "info", "If the address exists, an email has been sent.", http.StatusOK)
core.TriggerToastWithStatus(r.Context(), w, r, "info", "If the address exists, an email has been sent.", http.StatusOK)
}
}
}
@@ -388,7 +387,7 @@ func (handler HandlerImpl) handleForgotPasswordResponseComp() http.HandlerFunc {
pageUrl, err := url.Parse(r.Header.Get("Hx-Current-Url"))
if err != nil {
slog.ErrorContext(r.Context(), "Could not get current URL", "err", err)
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "Internal Server Error", http.StatusInternalServerError)
core.TriggerToastWithStatus(r.Context(), w, r, "error", "Internal Server Error", http.StatusInternalServerError)
return
}
@@ -397,9 +396,9 @@ func (handler HandlerImpl) handleForgotPasswordResponseComp() http.HandlerFunc {
err = handler.service.ForgotPassword(r.Context(), token, newPass)
if err != nil {
utils.TriggerToastWithStatus(r.Context(), w, r, "error", err.Error(), http.StatusBadRequest)
core.TriggerToastWithStatus(r.Context(), w, r, "error", err.Error(), http.StatusBadRequest)
} else {
utils.TriggerToastWithStatus(r.Context(), w, r, "success", "Password changed", http.StatusOK)
core.TriggerToastWithStatus(r.Context(), w, r, "success", "Password changed", http.StatusOK)
}
}
}

View File

@@ -9,7 +9,6 @@ import (
"spend-sparrow/internal/auth_types"
"spend-sparrow/internal/core"
mailTemplate "spend-sparrow/internal/template/mail"
"spend-sparrow/internal/types"
"strings"
"time"
@@ -54,10 +53,10 @@ type ServiceImpl struct {
random core.Random
clock core.Clock
mail core.Mail
serverSettings *types.Settings
serverSettings *core.Settings
}
func NewService(db Db, random core.Random, clock core.Clock, mail core.Mail, serverSettings *types.Settings) *ServiceImpl {
func NewService(db Db, random core.Random, clock core.Clock, mail core.Mail, serverSettings *core.Settings) *ServiceImpl {
return &ServiceImpl{
db: db,
random: random,