feat: extract account to domain package
All checks were successful
Build and Push Docker Image / Build-And-Push-Docker-Image (push) Successful in 1m17s
All checks were successful
Build and Push Docker Image / Build-And-Push-Docker-Image (push) Successful in 1m17s
This commit is contained in:
@@ -1,44 +1,36 @@
|
||||
package handler
|
||||
package account
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"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"
|
||||
"net/http"
|
||||
"spend-sparrow/internal/core"
|
||||
"spend-sparrow/internal/utils"
|
||||
)
|
||||
|
||||
type Account interface {
|
||||
Handle(router *http.ServeMux)
|
||||
type Handler struct {
|
||||
s Service
|
||||
r *core.Render
|
||||
}
|
||||
|
||||
type AccountImpl struct {
|
||||
s service.Account
|
||||
r *Render
|
||||
}
|
||||
|
||||
func NewAccount(s service.Account, r *Render) Account {
|
||||
return AccountImpl{
|
||||
func NewHandler(s Service, r *core.Render) Handler {
|
||||
return Handler{
|
||||
s: s,
|
||||
r: r,
|
||||
}
|
||||
}
|
||||
|
||||
func (h AccountImpl) Handle(r *http.ServeMux) {
|
||||
func (h Handler) Handle(r *http.ServeMux) {
|
||||
r.Handle("GET /account", h.handleAccountPage())
|
||||
r.Handle("GET /account/{id}", h.handleAccountItemComp())
|
||||
r.Handle("POST /account/{id}", h.handleUpdateAccount())
|
||||
r.Handle("DELETE /account/{id}", h.handleDeleteAccount())
|
||||
}
|
||||
|
||||
func (h AccountImpl) handleAccountPage() http.HandlerFunc {
|
||||
func (h Handler) handleAccountPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -46,20 +38,20 @@ func (h AccountImpl) handleAccountPage() http.HandlerFunc {
|
||||
|
||||
accounts, err := h.s.GetAll(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
comp := t.Account(accounts)
|
||||
comp := template(accounts)
|
||||
h.r.RenderLayout(r, w, comp, user)
|
||||
}
|
||||
}
|
||||
|
||||
func (h AccountImpl) handleAccountItemComp() http.HandlerFunc {
|
||||
func (h Handler) handleAccountItemComp() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -67,39 +59,39 @@ func (h AccountImpl) handleAccountItemComp() http.HandlerFunc {
|
||||
|
||||
id := r.PathValue("id")
|
||||
if id == "new" {
|
||||
comp := t.EditAccount(nil)
|
||||
comp := editAccount(nil)
|
||||
h.r.Render(r, w, comp)
|
||||
return
|
||||
}
|
||||
|
||||
account, err := h.s.Get(r.Context(), user, id)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
var comp templ.Component
|
||||
if r.URL.Query().Get("edit") == "true" {
|
||||
comp = t.EditAccount(account)
|
||||
comp = editAccount(account)
|
||||
} else {
|
||||
comp = t.AccountItem(account)
|
||||
comp = accountItem(account)
|
||||
}
|
||||
h.r.Render(r, w, comp)
|
||||
}
|
||||
}
|
||||
|
||||
func (h AccountImpl) handleUpdateAccount() http.HandlerFunc {
|
||||
func (h Handler) handleUpdateAccount() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
account *types.Account
|
||||
account *Account
|
||||
err error
|
||||
)
|
||||
id := r.PathValue("id")
|
||||
@@ -107,27 +99,27 @@ func (h AccountImpl) handleUpdateAccount() http.HandlerFunc {
|
||||
if id == "new" {
|
||||
account, err = h.s.Add(r.Context(), user, name)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
account, err = h.s.UpdateName(r.Context(), user, id, name)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
comp := t.AccountItem(account)
|
||||
comp := accountItem(account)
|
||||
h.r.Render(r, w, comp)
|
||||
}
|
||||
}
|
||||
|
||||
func (h AccountImpl) handleDeleteAccount() http.HandlerFunc {
|
||||
func (h Handler) handleDeleteAccount() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -137,7 +129,7 @@ func (h AccountImpl) handleDeleteAccount() http.HandlerFunc {
|
||||
|
||||
err := h.s.Delete(r.Context(), user, id)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,42 @@
|
||||
package service
|
||||
package account
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"spend-sparrow/internal/db"
|
||||
"spend-sparrow/internal/types"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"log/slog"
|
||||
"spend-sparrow/internal/db"
|
||||
"spend-sparrow/internal/service"
|
||||
"spend-sparrow/internal/types"
|
||||
)
|
||||
|
||||
type Account interface {
|
||||
Add(ctx context.Context, user *types.User, name string) (*types.Account, error)
|
||||
UpdateName(ctx context.Context, user *types.User, id string, name string) (*types.Account, error)
|
||||
Get(ctx context.Context, user *types.User, id string) (*types.Account, error)
|
||||
GetAll(ctx context.Context, user *types.User) ([]*types.Account, error)
|
||||
type Service interface {
|
||||
Add(ctx context.Context, user *types.User, name string) (*Account, error)
|
||||
UpdateName(ctx context.Context, user *types.User, id string, name string) (*Account, error)
|
||||
Get(ctx context.Context, user *types.User, id string) (*Account, error)
|
||||
GetAll(ctx context.Context, user *types.User) ([]*Account, error)
|
||||
Delete(ctx context.Context, user *types.User, id string) error
|
||||
}
|
||||
|
||||
type AccountImpl struct {
|
||||
type ServiceImpl struct {
|
||||
db *sqlx.DB
|
||||
clock Clock
|
||||
random Random
|
||||
clock service.Clock
|
||||
random service.Random
|
||||
}
|
||||
|
||||
func NewAccount(db *sqlx.DB, random Random, clock Clock) Account {
|
||||
return AccountImpl{
|
||||
func NewServiceImpl(db *sqlx.DB, random service.Random, clock service.Clock) Service {
|
||||
return ServiceImpl{
|
||||
db: db,
|
||||
clock: clock,
|
||||
random: random,
|
||||
}
|
||||
}
|
||||
|
||||
func (s AccountImpl) Add(ctx context.Context, user *types.User, name string) (*types.Account, error) {
|
||||
func (s ServiceImpl) Add(ctx context.Context, user *types.User, name string) (*Account, error) {
|
||||
if user == nil {
|
||||
return nil, ErrUnauthorized
|
||||
return nil, types.ErrUnauthorized
|
||||
}
|
||||
|
||||
newId, err := s.random.UUID(ctx)
|
||||
@@ -44,12 +44,12 @@ func (s AccountImpl) Add(ctx context.Context, user *types.User, name string) (*t
|
||||
return nil, types.ErrInternal
|
||||
}
|
||||
|
||||
err = validateString(name, "name")
|
||||
err = service.ValidateString(name, "name")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
account := &types.Account{
|
||||
account := &Account{
|
||||
Id: newId,
|
||||
UserId: user.Id,
|
||||
|
||||
@@ -76,18 +76,18 @@ func (s AccountImpl) Add(ctx context.Context, user *types.User, name string) (*t
|
||||
return account, nil
|
||||
}
|
||||
|
||||
func (s AccountImpl) UpdateName(ctx context.Context, user *types.User, id string, name string) (*types.Account, error) {
|
||||
func (s ServiceImpl) UpdateName(ctx context.Context, user *types.User, id string, name string) (*Account, error) {
|
||||
if user == nil {
|
||||
return nil, ErrUnauthorized
|
||||
return nil, types.ErrUnauthorized
|
||||
}
|
||||
err := validateString(name, "name")
|
||||
err := service.ValidateString(name, "name")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uuid, err := uuid.Parse(id)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "account update", "err", err)
|
||||
return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest)
|
||||
return nil, fmt.Errorf("could not parse Id: %w", service.ErrBadRequest)
|
||||
}
|
||||
|
||||
tx, err := s.db.BeginTxx(ctx, nil)
|
||||
@@ -99,12 +99,12 @@ func (s AccountImpl) UpdateName(ctx context.Context, user *types.User, id string
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
var account types.Account
|
||||
var account Account
|
||||
err = tx.GetContext(ctx, &account, `SELECT * FROM account WHERE user_id = ? AND id = ?`, user.Id, uuid)
|
||||
err = db.TransformAndLogDbError(ctx, "account Update", nil, err)
|
||||
if err != nil {
|
||||
if errors.Is(err, db.ErrNotFound) {
|
||||
return nil, fmt.Errorf("account %v not found: %w", id, ErrBadRequest)
|
||||
return nil, fmt.Errorf("account %v not found: %w", id, service.ErrBadRequest)
|
||||
}
|
||||
return nil, types.ErrInternal
|
||||
}
|
||||
@@ -136,17 +136,17 @@ func (s AccountImpl) UpdateName(ctx context.Context, user *types.User, id string
|
||||
return &account, nil
|
||||
}
|
||||
|
||||
func (s AccountImpl) Get(ctx context.Context, user *types.User, id string) (*types.Account, error) {
|
||||
func (s ServiceImpl) Get(ctx context.Context, user *types.User, id string) (*Account, error) {
|
||||
if user == nil {
|
||||
return nil, ErrUnauthorized
|
||||
return nil, service.ErrUnauthorized
|
||||
}
|
||||
uuid, err := uuid.Parse(id)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "account get", "err", err)
|
||||
return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest)
|
||||
return nil, fmt.Errorf("could not parse Id: %w", service.ErrBadRequest)
|
||||
}
|
||||
|
||||
var account types.Account
|
||||
var account Account
|
||||
err = s.db.GetContext(ctx, &account, `
|
||||
SELECT * FROM account WHERE user_id = ? AND id = ?`, user.Id, uuid)
|
||||
err = db.TransformAndLogDbError(ctx, "account Get", nil, err)
|
||||
@@ -158,12 +158,12 @@ func (s AccountImpl) Get(ctx context.Context, user *types.User, id string) (*typ
|
||||
return &account, nil
|
||||
}
|
||||
|
||||
func (s AccountImpl) GetAll(ctx context.Context, user *types.User) ([]*types.Account, error) {
|
||||
func (s ServiceImpl) GetAll(ctx context.Context, user *types.User) ([]*Account, error) {
|
||||
if user == nil {
|
||||
return nil, ErrUnauthorized
|
||||
return nil, service.ErrUnauthorized
|
||||
}
|
||||
|
||||
accounts := make([]*types.Account, 0)
|
||||
accounts := make([]*Account, 0)
|
||||
err := s.db.SelectContext(ctx, &accounts, `
|
||||
SELECT * FROM account WHERE user_id = ? ORDER BY name`, user.Id)
|
||||
err = db.TransformAndLogDbError(ctx, "account GetAll", nil, err)
|
||||
@@ -174,14 +174,14 @@ func (s AccountImpl) GetAll(ctx context.Context, user *types.User) ([]*types.Acc
|
||||
return accounts, nil
|
||||
}
|
||||
|
||||
func (s AccountImpl) Delete(ctx context.Context, user *types.User, id string) error {
|
||||
func (s ServiceImpl) Delete(ctx context.Context, user *types.User, id string) error {
|
||||
if user == nil {
|
||||
return ErrUnauthorized
|
||||
return service.ErrUnauthorized
|
||||
}
|
||||
uuid, err := uuid.Parse(id)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "account delete", "err", err)
|
||||
return fmt.Errorf("could not parse Id: %w", ErrBadRequest)
|
||||
return fmt.Errorf("could not parse Id: %w", service.ErrBadRequest)
|
||||
}
|
||||
|
||||
tx, err := s.db.BeginTxx(ctx, nil)
|
||||
@@ -200,7 +200,7 @@ func (s AccountImpl) Delete(ctx context.Context, user *types.User, id string) er
|
||||
return err
|
||||
}
|
||||
if transactionsCount > 0 {
|
||||
return fmt.Errorf("account has transactions, cannot delete: %w", ErrBadRequest)
|
||||
return fmt.Errorf("account has transactions, cannot delete: %w", service.ErrBadRequest)
|
||||
}
|
||||
|
||||
res, err := tx.ExecContext(ctx, "DELETE FROM account WHERE id = ? and user_id = ?", uuid, user.Id)
|
||||
@@ -3,7 +3,7 @@ package account
|
||||
import "spend-sparrow/internal/template/svg"
|
||||
import "spend-sparrow/internal/types"
|
||||
|
||||
templ Account(accounts []*types.Account) {
|
||||
templ template(accounts []*Account) {
|
||||
<div class="max-w-6xl mt-10 mx-auto">
|
||||
<button
|
||||
hx-get="/account/new"
|
||||
@@ -16,28 +16,28 @@ templ Account(accounts []*types.Account) {
|
||||
</button>
|
||||
<div id="account-items" class="my-6 flex flex-col items-center">
|
||||
for _, account := range accounts {
|
||||
@AccountItem(account)
|
||||
@accountItem(account)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ EditAccount(account *types.Account) {
|
||||
templ editAccount(account *Account) {
|
||||
{{
|
||||
var (
|
||||
name string
|
||||
id string
|
||||
cancelUrl string
|
||||
)
|
||||
if account == nil {
|
||||
name = ""
|
||||
id = "new"
|
||||
cancelUrl = "/empty"
|
||||
} else {
|
||||
name = account.Name
|
||||
id = account.Id.String()
|
||||
cancelUrl = "/account/" + id
|
||||
}
|
||||
var (
|
||||
name string
|
||||
id string
|
||||
cancelUrl string
|
||||
)
|
||||
if account == nil {
|
||||
name = ""
|
||||
id = "new"
|
||||
cancelUrl = "/empty"
|
||||
} else {
|
||||
name = account.Name
|
||||
id = account.Id.String()
|
||||
cancelUrl = "/account/" + id
|
||||
}
|
||||
}}
|
||||
<div id="account" class="border-1 border-gray-300 w-full my-4 p-4 bg-gray-50 rounded-lg">
|
||||
<form
|
||||
@@ -77,7 +77,7 @@ templ EditAccount(account *types.Account) {
|
||||
</div>
|
||||
}
|
||||
|
||||
templ AccountItem(account *types.Account) {
|
||||
templ accountItem(account *Account) {
|
||||
<div id="account" class="border-1 border-gray-300 w-full my-4 p-4 bg-gray-50 rounded-lg">
|
||||
<div class="text-xl flex justify-end gap-4">
|
||||
<p class="mr-auto">{ account.Name }</p>
|
||||
@@ -1,9 +1,8 @@
|
||||
package types
|
||||
package account
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The Account holds money.
|
||||
39
internal/core/auth.go
Normal file
39
internal/core/auth.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"spend-sparrow/internal/types"
|
||||
)
|
||||
|
||||
type ContextKey string
|
||||
|
||||
var SessionKey ContextKey = "session"
|
||||
var UserKey ContextKey = "user"
|
||||
|
||||
func GetUser(r *http.Request) *types.User {
|
||||
obj := r.Context().Value(UserKey)
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
user, ok := obj.(*types.User)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func GetSession(r *http.Request) *types.Session {
|
||||
obj := r.Context().Value(SessionKey)
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
session, ok := obj.(*types.Session)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
func handleError(w http.ResponseWriter, r *http.Request, err error) {
|
||||
func HandleError(w http.ResponseWriter, r *http.Request, err error) {
|
||||
switch {
|
||||
case errors.Is(err, service.ErrUnauthorized):
|
||||
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "You are not autorized to perform this operation.", http.StatusUnauthorized)
|
||||
@@ -37,7 +37,7 @@ func extractErrorMessage(err error) string {
|
||||
return strings.SplitN(errMsg, ":", 2)[0]
|
||||
}
|
||||
|
||||
func updateSpan(r *http.Request) {
|
||||
func UpdateSpan(r *http.Request) {
|
||||
currentSpan := trace.SpanFromContext(r.Context())
|
||||
if currentSpan != nil {
|
||||
currentSpan.SetAttributes(attribute.String("http.pattern", r.Pattern))
|
||||
@@ -1,4 +1,4 @@
|
||||
package template
|
||||
package core
|
||||
|
||||
import "spend-sparrow/internal/template/svg"
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package handler
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/a-h/templ"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"spend-sparrow/internal/template"
|
||||
"spend-sparrow/internal/template/auth"
|
||||
"spend-sparrow/internal/types"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
)
|
||||
|
||||
type Render struct {
|
||||
@@ -37,15 +34,15 @@ func (render *Render) RenderLayout(r *http.Request, w http.ResponseWriter, slot
|
||||
|
||||
func (render *Render) RenderLayoutWithStatus(r *http.Request, w http.ResponseWriter, slot templ.Component, user *types.User, status int) {
|
||||
userComp := render.getUserComp(user)
|
||||
layout := template.Layout(slot, userComp, user != nil, r.URL.Path)
|
||||
layout := Layout(slot, userComp, user != nil, r.URL.Path)
|
||||
|
||||
render.RenderWithStatus(r, w, layout, status)
|
||||
}
|
||||
|
||||
func (render *Render) getUserComp(user *types.User) templ.Component {
|
||||
if user != nil {
|
||||
return auth.UserComp(user.Email)
|
||||
return UserComp(user.Email)
|
||||
} else {
|
||||
return auth.UserComp("")
|
||||
return UserComp("")
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package auth
|
||||
package core
|
||||
|
||||
templ UserComp(user string) {
|
||||
<div id="user-info" class="flex items-center gap-2 text-nowrap">
|
||||
@@ -1,19 +1,20 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os/signal"
|
||||
"spend-sparrow/internal/account"
|
||||
"spend-sparrow/internal/core"
|
||||
"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"
|
||||
@@ -113,17 +114,17 @@ func createHandlerWithServices(ctx context.Context, d *sqlx.DB, serverSettings *
|
||||
mailService := service.NewMail(serverSettings)
|
||||
|
||||
authService := service.NewAuth(authDb, randomService, clockService, mailService, serverSettings)
|
||||
accountService := service.NewAccount(d, randomService, clockService)
|
||||
accountService := account.NewServiceImpl(d, randomService, clockService)
|
||||
treasureChestService := service.NewTreasureChest(d, randomService, clockService)
|
||||
transactionService := service.NewTransaction(d, randomService, clockService)
|
||||
transactionRecurringService := service.NewTransactionRecurring(d, randomService, clockService, transactionService)
|
||||
dashboardService := service.NewDashboard(d)
|
||||
|
||||
render := handler.NewRender()
|
||||
render := core.NewRender()
|
||||
indexHandler := handler.NewIndex(render, clockService)
|
||||
dashboardHandler := handler.NewDashboard(render, dashboardService, treasureChestService)
|
||||
authHandler := handler.NewAuth(authService, render)
|
||||
accountHandler := handler.NewAccount(accountService, render)
|
||||
accountHandler := account.NewHandler(accountService, render)
|
||||
treasureChestHandler := handler.NewTreasureChest(treasureChestService, transactionRecurringService, render)
|
||||
transactionHandler := handler.NewTransaction(transactionService, accountService, treasureChestService, render)
|
||||
transactionRecurringHandler := handler.NewTransactionRecurring(transactionRecurringService, render)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"spend-sparrow/internal/core"
|
||||
"spend-sparrow/internal/handler/middleware"
|
||||
"spend-sparrow/internal/service"
|
||||
"spend-sparrow/internal/template/auth"
|
||||
@@ -19,10 +20,10 @@ type Auth interface {
|
||||
|
||||
type AuthImpl struct {
|
||||
service service.Auth
|
||||
render *Render
|
||||
render *core.Render
|
||||
}
|
||||
|
||||
func NewAuth(service service.Auth, render *Render) Auth {
|
||||
func NewAuth(service service.Auth, render *core.Render) Auth {
|
||||
return AuthImpl{
|
||||
service: service,
|
||||
render: render,
|
||||
@@ -58,9 +59,9 @@ var (
|
||||
|
||||
func (handler AuthImpl) handleSignInPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user != nil {
|
||||
if !user.EmailVerified {
|
||||
utils.DoRedirect(w, r, "/auth/verify")
|
||||
@@ -78,10 +79,10 @@ func (handler AuthImpl) handleSignInPage() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleSignIn() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user, err := utils.WaitMinimumTime(securityWaitDuration, func() (*types.User, error) {
|
||||
session := middleware.GetSession(r)
|
||||
session := core.GetSession(r)
|
||||
email := r.FormValue("email")
|
||||
password := r.FormValue("password")
|
||||
|
||||
@@ -115,9 +116,9 @@ func (handler AuthImpl) handleSignIn() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleSignUpPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
|
||||
if user != nil {
|
||||
if !user.EmailVerified {
|
||||
@@ -135,9 +136,9 @@ func (handler AuthImpl) handleSignUpPage() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleSignUpVerifyPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -155,9 +156,9 @@ func (handler AuthImpl) handleSignUpVerifyPage() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleVerifyResendComp() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -174,7 +175,7 @@ func (handler AuthImpl) handleVerifyResendComp() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleSignUpVerifyResponsePage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
token := r.URL.Query().Get("token")
|
||||
|
||||
@@ -196,7 +197,7 @@ func (handler AuthImpl) handleSignUpVerifyResponsePage() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleSignUp() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
var email = r.FormValue("email")
|
||||
var password = r.FormValue("password")
|
||||
@@ -234,9 +235,9 @@ func (handler AuthImpl) handleSignUp() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleSignOut() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
session := middleware.GetSession(r)
|
||||
session := core.GetSession(r)
|
||||
|
||||
if session != nil {
|
||||
err := handler.service.SignOut(r.Context(), session.Id)
|
||||
@@ -263,9 +264,9 @@ func (handler AuthImpl) handleSignOut() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleDeleteAccountPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -278,9 +279,9 @@ func (handler AuthImpl) handleDeleteAccountPage() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleDeleteAccountComp() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -304,11 +305,11 @@ func (handler AuthImpl) handleDeleteAccountComp() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleChangePasswordPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
isPasswordReset := r.URL.Query().Has("token")
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
|
||||
if user == nil && !isPasswordReset {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
@@ -322,10 +323,10 @@ func (handler AuthImpl) handleChangePasswordPage() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleChangePasswordComp() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
session := middleware.GetSession(r)
|
||||
user := middleware.GetUser(r)
|
||||
session := core.GetSession(r)
|
||||
user := core.GetUser(r)
|
||||
if session == nil || user == nil {
|
||||
utils.TriggerToastWithStatus(r.Context(), w, r, "error", "Unathorized", http.StatusUnauthorized)
|
||||
return
|
||||
@@ -346,9 +347,9 @@ func (handler AuthImpl) handleChangePasswordComp() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleForgotPasswordPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user != nil {
|
||||
utils.DoRedirect(w, r, "/")
|
||||
return
|
||||
@@ -361,7 +362,7 @@ func (handler AuthImpl) handleForgotPasswordPage() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleForgotPasswordComp() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
email := r.FormValue("email")
|
||||
if email == "" {
|
||||
@@ -384,7 +385,7 @@ func (handler AuthImpl) handleForgotPasswordComp() http.HandlerFunc {
|
||||
|
||||
func (handler AuthImpl) handleForgotPasswordResponseComp() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
pageUrl, err := url.Parse(r.Header.Get("Hx-Current-Url"))
|
||||
if err != nil {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"spend-sparrow/internal/handler/middleware"
|
||||
"spend-sparrow/internal/core"
|
||||
"spend-sparrow/internal/service"
|
||||
"spend-sparrow/internal/template/dashboard"
|
||||
"spend-sparrow/internal/utils"
|
||||
@@ -19,12 +19,12 @@ type Dashboard interface {
|
||||
}
|
||||
|
||||
type DashboardImpl struct {
|
||||
r *Render
|
||||
r *core.Render
|
||||
d *service.Dashboard
|
||||
treasureChest service.TreasureChest
|
||||
}
|
||||
|
||||
func NewDashboard(r *Render, d *service.Dashboard, treasureChest service.TreasureChest) Dashboard {
|
||||
func NewDashboard(r *core.Render, d *service.Dashboard, treasureChest service.TreasureChest) Dashboard {
|
||||
return DashboardImpl{
|
||||
r: r,
|
||||
d: d,
|
||||
@@ -41,9 +41,9 @@ func (handler DashboardImpl) Handle(router *http.ServeMux) {
|
||||
|
||||
func (handler DashboardImpl) handleDashboard() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -51,7 +51,7 @@ func (handler DashboardImpl) handleDashboard() http.HandlerFunc {
|
||||
|
||||
treasureChests, err := handler.treasureChest.GetAll(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -62,13 +62,13 @@ func (handler DashboardImpl) handleDashboard() http.HandlerFunc {
|
||||
|
||||
func (handler DashboardImpl) handleDashboardMainChart() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
|
||||
series, err := handler.d.MainChart(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -128,13 +128,13 @@ func (handler DashboardImpl) handleDashboardMainChart() http.HandlerFunc {
|
||||
|
||||
func (handler DashboardImpl) handleDashboardTreasureChests() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
|
||||
treeList, err := handler.d.TreasureChests(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -183,9 +183,9 @@ func (handler DashboardImpl) handleDashboardTreasureChests() http.HandlerFunc {
|
||||
|
||||
func (handler DashboardImpl) handleDashboardTreasureChest() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
|
||||
var treasureChestId *uuid.UUID
|
||||
|
||||
@@ -193,7 +193,7 @@ func (handler DashboardImpl) handleDashboardTreasureChest() http.HandlerFunc {
|
||||
if treasureChestStr != "" {
|
||||
id, err := uuid.Parse(treasureChestStr)
|
||||
if err != nil {
|
||||
handleError(w, r, fmt.Errorf("could not parse treasure chest: %w", service.ErrBadRequest))
|
||||
core.HandleError(w, r, fmt.Errorf("could not parse treasure chest: %w", service.ErrBadRequest))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ func (handler DashboardImpl) handleDashboardTreasureChest() http.HandlerFunc {
|
||||
|
||||
series, err := handler.d.TreasureChest(r.Context(), user, treasureChestId)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -3,17 +3,11 @@ package middleware
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"spend-sparrow/internal/core"
|
||||
"spend-sparrow/internal/service"
|
||||
"spend-sparrow/internal/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ContextKey string
|
||||
|
||||
var SessionKey ContextKey = "session"
|
||||
var UserKey ContextKey = "user"
|
||||
|
||||
func Authenticate(service service.Auth) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -41,42 +35,14 @@ func Authenticate(service service.Auth) func(http.Handler) http.Handler {
|
||||
http.SetCookie(w, &cookie)
|
||||
}
|
||||
|
||||
ctx = context.WithValue(ctx, UserKey, user)
|
||||
ctx = context.WithValue(ctx, SessionKey, session)
|
||||
ctx = context.WithValue(ctx, core.UserKey, user)
|
||||
ctx = context.WithValue(ctx, core.SessionKey, session)
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func GetUser(r *http.Request) *types.User {
|
||||
obj := r.Context().Value(UserKey)
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
user, ok := obj.(*types.User)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func GetSession(r *http.Request) *types.Session {
|
||||
obj := r.Context().Value(SessionKey)
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
session, ok := obj.(*types.Session)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
func getSessionID(r *http.Request) string {
|
||||
cookie, err := r.Cookie("id")
|
||||
if err != nil {
|
||||
|
||||
@@ -3,6 +3,7 @@ package middleware
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"spend-sparrow/internal/core"
|
||||
"spend-sparrow/internal/service"
|
||||
"spend-sparrow/internal/utils"
|
||||
"strings"
|
||||
@@ -40,7 +41,7 @@ func CrossSiteRequestForgery(auth service.Auth) func(http.Handler) http.Handler
|
||||
return
|
||||
}
|
||||
|
||||
session := GetSession(r)
|
||||
session := core.GetSession(r)
|
||||
|
||||
if r.Method == http.MethodPost ||
|
||||
r.Method == http.MethodPut ||
|
||||
|
||||
@@ -2,7 +2,7 @@ package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"spend-sparrow/internal/handler/middleware"
|
||||
"spend-sparrow/internal/core"
|
||||
"spend-sparrow/internal/service"
|
||||
"spend-sparrow/internal/template"
|
||||
"spend-sparrow/internal/utils"
|
||||
@@ -15,11 +15,11 @@ type Index interface {
|
||||
}
|
||||
|
||||
type IndexImpl struct {
|
||||
r *Render
|
||||
r *core.Render
|
||||
c service.Clock
|
||||
}
|
||||
|
||||
func NewIndex(r *Render, c service.Clock) Index {
|
||||
func NewIndex(r *core.Render, c service.Clock) Index {
|
||||
return IndexImpl{
|
||||
r: r,
|
||||
c: c,
|
||||
@@ -33,9 +33,9 @@ func (handler IndexImpl) Handle(router *http.ServeMux) {
|
||||
|
||||
func (handler IndexImpl) handleRootAnd404() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
|
||||
htmx := utils.IsHtmx(r)
|
||||
|
||||
@@ -65,7 +65,7 @@ func (handler IndexImpl) handleRootAnd404() http.HandlerFunc {
|
||||
|
||||
func (handler IndexImpl) handleEmpty() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
// Return nothing
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"spend-sparrow/internal/handler/middleware"
|
||||
"spend-sparrow/internal/account"
|
||||
"spend-sparrow/internal/core"
|
||||
"spend-sparrow/internal/service"
|
||||
t "spend-sparrow/internal/template/transaction"
|
||||
"spend-sparrow/internal/types"
|
||||
@@ -22,12 +23,12 @@ type Transaction interface {
|
||||
|
||||
type TransactionImpl struct {
|
||||
s service.Transaction
|
||||
account service.Account
|
||||
account account.Service
|
||||
treasureChest service.TreasureChest
|
||||
r *Render
|
||||
r *core.Render
|
||||
}
|
||||
|
||||
func NewTransaction(s service.Transaction, account service.Account, treasureChest service.TreasureChest, r *Render) Transaction {
|
||||
func NewTransaction(s service.Transaction, account account.Service, treasureChest service.TreasureChest, r *core.Render) Transaction {
|
||||
return TransactionImpl{
|
||||
s: s,
|
||||
account: account,
|
||||
@@ -46,9 +47,9 @@ func (h TransactionImpl) Handle(r *http.ServeMux) {
|
||||
|
||||
func (h TransactionImpl) handleTransactionPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -63,19 +64,19 @@ func (h TransactionImpl) handleTransactionPage() http.HandlerFunc {
|
||||
|
||||
transactions, err := h.s.GetAll(r.Context(), user, filter)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
accounts, err := h.account.GetAll(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
treasureChests, err := h.treasureChest.GetAll(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -93,9 +94,9 @@ func (h TransactionImpl) handleTransactionPage() http.HandlerFunc {
|
||||
|
||||
func (h TransactionImpl) handleTransactionItemComp() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -103,13 +104,13 @@ func (h TransactionImpl) handleTransactionItemComp() http.HandlerFunc {
|
||||
|
||||
accounts, err := h.account.GetAll(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
treasureChests, err := h.treasureChest.GetAll(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -122,7 +123,7 @@ func (h TransactionImpl) handleTransactionItemComp() http.HandlerFunc {
|
||||
|
||||
transaction, err := h.s.Get(r.Context(), user, id)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -139,9 +140,9 @@ func (h TransactionImpl) handleTransactionItemComp() http.HandlerFunc {
|
||||
|
||||
func (h TransactionImpl) handleUpdateTransaction() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -156,7 +157,7 @@ func (h TransactionImpl) handleUpdateTransaction() http.HandlerFunc {
|
||||
if idStr != "new" {
|
||||
id, err = uuid.Parse(idStr)
|
||||
if err != nil {
|
||||
handleError(w, r, fmt.Errorf("could not parse Id: %w", service.ErrBadRequest))
|
||||
core.HandleError(w, r, fmt.Errorf("could not parse Id: %w", service.ErrBadRequest))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -166,7 +167,7 @@ func (h TransactionImpl) handleUpdateTransaction() http.HandlerFunc {
|
||||
if accountIdStr != "" {
|
||||
i, err := uuid.Parse(accountIdStr)
|
||||
if err != nil {
|
||||
handleError(w, r, fmt.Errorf("could not parse account id: %w", service.ErrBadRequest))
|
||||
core.HandleError(w, r, fmt.Errorf("could not parse account id: %w", service.ErrBadRequest))
|
||||
return
|
||||
}
|
||||
accountId = &i
|
||||
@@ -177,7 +178,7 @@ func (h TransactionImpl) handleUpdateTransaction() http.HandlerFunc {
|
||||
if treasureChestIdStr != "" {
|
||||
i, err := uuid.Parse(treasureChestIdStr)
|
||||
if err != nil {
|
||||
handleError(w, r, fmt.Errorf("could not parse treasure chest id: %w", service.ErrBadRequest))
|
||||
core.HandleError(w, r, fmt.Errorf("could not parse treasure chest id: %w", service.ErrBadRequest))
|
||||
return
|
||||
}
|
||||
treasureChestId = &i
|
||||
@@ -185,14 +186,14 @@ func (h TransactionImpl) handleUpdateTransaction() http.HandlerFunc {
|
||||
|
||||
valueF, err := strconv.ParseFloat(r.FormValue("value"), 64)
|
||||
if err != nil {
|
||||
handleError(w, r, fmt.Errorf("could not parse value: %w", service.ErrBadRequest))
|
||||
core.HandleError(w, r, fmt.Errorf("could not parse value: %w", service.ErrBadRequest))
|
||||
return
|
||||
}
|
||||
value := int64(math.Round(valueF * service.DECIMALS_MULTIPLIER))
|
||||
|
||||
timestamp, err := time.Parse("2006-01-02", r.FormValue("timestamp"))
|
||||
if err != nil {
|
||||
handleError(w, r, fmt.Errorf("could not parse timestamp: %w", service.ErrBadRequest))
|
||||
core.HandleError(w, r, fmt.Errorf("could not parse timestamp: %w", service.ErrBadRequest))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -210,26 +211,26 @@ func (h TransactionImpl) handleUpdateTransaction() http.HandlerFunc {
|
||||
if idStr == "new" {
|
||||
transaction, err = h.s.Add(r.Context(), nil, user, input)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
transaction, err = h.s.Update(r.Context(), user, input)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
accounts, err := h.account.GetAll(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
treasureChests, err := h.treasureChest.GetAll(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -241,9 +242,9 @@ func (h TransactionImpl) handleUpdateTransaction() http.HandlerFunc {
|
||||
|
||||
func (h TransactionImpl) handleRecalculate() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -251,7 +252,7 @@ func (h TransactionImpl) handleRecalculate() http.HandlerFunc {
|
||||
|
||||
err := h.s.RecalculateBalances(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -261,9 +262,9 @@ func (h TransactionImpl) handleRecalculate() http.HandlerFunc {
|
||||
|
||||
func (h TransactionImpl) handleDeleteTransaction() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -273,13 +274,13 @@ func (h TransactionImpl) handleDeleteTransaction() http.HandlerFunc {
|
||||
|
||||
err := h.s.Delete(r.Context(), user, id)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h TransactionImpl) getTransactionData(accounts []*types.Account, treasureChests []*types.TreasureChest) (map[uuid.UUID]string, map[uuid.UUID]string) {
|
||||
func (h TransactionImpl) getTransactionData(accounts []*account.Account, treasureChests []*types.TreasureChest) (map[uuid.UUID]string, map[uuid.UUID]string) {
|
||||
accountMap := make(map[uuid.UUID]string, 0)
|
||||
for _, account := range accounts {
|
||||
accountMap[account.Id] = account.Name
|
||||
|
||||
@@ -2,7 +2,7 @@ package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"spend-sparrow/internal/handler/middleware"
|
||||
"spend-sparrow/internal/core"
|
||||
"spend-sparrow/internal/service"
|
||||
t "spend-sparrow/internal/template/transaction_recurring"
|
||||
"spend-sparrow/internal/types"
|
||||
@@ -15,10 +15,10 @@ type TransactionRecurring interface {
|
||||
|
||||
type TransactionRecurringImpl struct {
|
||||
s service.TransactionRecurring
|
||||
r *Render
|
||||
r *core.Render
|
||||
}
|
||||
|
||||
func NewTransactionRecurring(s service.TransactionRecurring, r *Render) TransactionRecurring {
|
||||
func NewTransactionRecurring(s service.TransactionRecurring, r *core.Render) TransactionRecurring {
|
||||
return TransactionRecurringImpl{
|
||||
s: s,
|
||||
r: r,
|
||||
@@ -33,9 +33,9 @@ func (h TransactionRecurringImpl) Handle(r *http.ServeMux) {
|
||||
|
||||
func (h TransactionRecurringImpl) handleTransactionRecurringItemComp() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -50,9 +50,9 @@ func (h TransactionRecurringImpl) handleTransactionRecurringItemComp() http.Hand
|
||||
|
||||
func (h TransactionRecurringImpl) handleUpdateTransactionRecurring() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -72,13 +72,13 @@ func (h TransactionRecurringImpl) handleUpdateTransactionRecurring() http.Handle
|
||||
if input.Id == "new" {
|
||||
_, err := h.s.Add(r.Context(), user, input)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
_, err := h.s.Update(r.Context(), user, input)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -89,9 +89,9 @@ func (h TransactionRecurringImpl) handleUpdateTransactionRecurring() http.Handle
|
||||
|
||||
func (h TransactionRecurringImpl) handleDeleteTransactionRecurring() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -103,7 +103,7 @@ func (h TransactionRecurringImpl) handleDeleteTransactionRecurring() http.Handle
|
||||
|
||||
err := h.s.Delete(r.Context(), user, id)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -120,13 +120,13 @@ func (h TransactionRecurringImpl) renderItems(w http.ResponseWriter, r *http.Req
|
||||
if accountId != "" {
|
||||
transactionsRecurring, err = h.s.GetAllByAccount(r.Context(), user, accountId)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
transactionsRecurring, err = h.s.GetAllByTreasureChest(r.Context(), user, treasureChestId)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"spend-sparrow/internal/handler/middleware"
|
||||
"spend-sparrow/internal/core"
|
||||
"spend-sparrow/internal/service"
|
||||
tr "spend-sparrow/internal/template/transaction_recurring"
|
||||
t "spend-sparrow/internal/template/treasurechest"
|
||||
@@ -20,10 +20,10 @@ type TreasureChest interface {
|
||||
type TreasureChestImpl struct {
|
||||
s service.TreasureChest
|
||||
transactionRecurring service.TransactionRecurring
|
||||
r *Render
|
||||
r *core.Render
|
||||
}
|
||||
|
||||
func NewTreasureChest(s service.TreasureChest, transactionRecurring service.TransactionRecurring, r *Render) TreasureChest {
|
||||
func NewTreasureChest(s service.TreasureChest, transactionRecurring service.TransactionRecurring, r *core.Render) TreasureChest {
|
||||
return TreasureChestImpl{
|
||||
s: s,
|
||||
transactionRecurring: transactionRecurring,
|
||||
@@ -40,9 +40,9 @@ func (h TreasureChestImpl) Handle(r *http.ServeMux) {
|
||||
|
||||
func (h TreasureChestImpl) handleTreasureChestPage() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -50,13 +50,13 @@ func (h TreasureChestImpl) handleTreasureChestPage() http.HandlerFunc {
|
||||
|
||||
treasureChests, err := h.s.GetAll(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
transactionsRecurring, err := h.transactionRecurring.GetAll(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -69,9 +69,9 @@ func (h TreasureChestImpl) handleTreasureChestPage() http.HandlerFunc {
|
||||
|
||||
func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -79,7 +79,7 @@ func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc {
|
||||
|
||||
treasureChests, err := h.s.GetAll(r.Context(), user)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -92,13 +92,13 @@ func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc {
|
||||
|
||||
treasureChest, err := h.s.Get(r.Context(), user, id)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
transactionsRecurring, err := h.transactionRecurring.GetAllByTreasureChest(r.Context(), user, treasureChest.Id.String())
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
transactionsRec := tr.TransactionRecurringItems(transactionsRecurring, "", "", treasureChest.Id.String())
|
||||
@@ -116,9 +116,9 @@ func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc {
|
||||
|
||||
func (h TreasureChestImpl) handleUpdateTreasureChest() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -134,20 +134,20 @@ func (h TreasureChestImpl) handleUpdateTreasureChest() http.HandlerFunc {
|
||||
if id == "new" {
|
||||
treasureChest, err = h.s.Add(r.Context(), user, parentId, name)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
treasureChest, err = h.s.Update(r.Context(), user, id, parentId, name)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
transactionsRecurring, err := h.transactionRecurring.GetAllByTreasureChest(r.Context(), user, treasureChest.Id.String())
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -161,9 +161,9 @@ func (h TreasureChestImpl) handleUpdateTreasureChest() http.HandlerFunc {
|
||||
|
||||
func (h TreasureChestImpl) handleDeleteTreasureChest() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateSpan(r)
|
||||
core.UpdateSpan(r)
|
||||
|
||||
user := middleware.GetUser(r)
|
||||
user := core.GetUser(r)
|
||||
if user == nil {
|
||||
utils.DoRedirect(w, r, "/auth/signin")
|
||||
return
|
||||
@@ -173,7 +173,7 @@ func (h TreasureChestImpl) handleDeleteTreasureChest() http.HandlerFunc {
|
||||
|
||||
err := h.s.Delete(r.Context(), user, id)
|
||||
if err != nil {
|
||||
handleError(w, r, err)
|
||||
core.HandleError(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ var (
|
||||
safeInputRegex = regexp.MustCompile(`^[a-zA-Z0-9ÄÖÜäöüß,&'". \-\?]+$`)
|
||||
)
|
||||
|
||||
func validateString(value string, fieldName string) error {
|
||||
func ValidateString(value string, fieldName string) error {
|
||||
switch {
|
||||
case value == "":
|
||||
return fmt.Errorf("field \"%s\" needs to be set: %w", fieldName, ErrBadRequest)
|
||||
|
||||
@@ -499,13 +499,13 @@ func (s TransactionImpl) validateAndEnrichTransaction(ctx context.Context, tx *s
|
||||
}
|
||||
|
||||
if input.Party != "" {
|
||||
err = validateString(input.Party, "party")
|
||||
err = ValidateString(input.Party, "party")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if input.Description != "" {
|
||||
err = validateString(input.Description, "description")
|
||||
err = ValidateString(input.Description, "description")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -471,13 +471,13 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
|
||||
value := int64(math.Round(valueFloat * DECIMALS_MULTIPLIER))
|
||||
|
||||
if input.Party != "" {
|
||||
err = validateString(input.Party, "party")
|
||||
err = ValidateString(input.Party, "party")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if input.Description != "" {
|
||||
err = validateString(input.Description, "description")
|
||||
err = ValidateString(input.Description, "description")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func (s TreasureChestImpl) Add(ctx context.Context, user *types.User, parentId,
|
||||
return nil, types.ErrInternal
|
||||
}
|
||||
|
||||
err = validateString(name, "name")
|
||||
err = ValidateString(name, "name")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -92,7 +92,7 @@ func (s TreasureChestImpl) Update(ctx context.Context, user *types.User, idStr,
|
||||
if user == nil {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
err := validateString(name, "name")
|
||||
err := ValidateString(name, "name")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
package account
|
||||
@@ -4,9 +4,10 @@ import "fmt"
|
||||
import "time"
|
||||
import "spend-sparrow/internal/template/svg"
|
||||
import "spend-sparrow/internal/types"
|
||||
import "spend-sparrow/internal/account"
|
||||
import "github.com/google/uuid"
|
||||
|
||||
templ Transaction(items templ.Component, filter types.TransactionItemsFilter, accounts []*types.Account, treasureChests []*types.TreasureChest) {
|
||||
templ Transaction(items templ.Component, filter types.TransactionItemsFilter, accounts []*account.Account, treasureChests []*types.TreasureChest) {
|
||||
<div class="max-w-6xl mt-10 mx-auto">
|
||||
<div class="flex items-center gap-4">
|
||||
<form
|
||||
@@ -95,7 +96,7 @@ templ TransactionItems(transactions []*types.Transaction, accounts, treasureChes
|
||||
</div>
|
||||
}
|
||||
|
||||
templ EditTransaction(transaction *types.Transaction, accounts []*types.Account, treasureChests []*types.TreasureChest) {
|
||||
templ EditTransaction(transaction *types.Transaction, accounts []*account.Account, treasureChests []*types.TreasureChest) {
|
||||
{{
|
||||
var (
|
||||
timestamp time.Time
|
||||
|
||||
Reference in New Issue
Block a user