diff --git a/db/treasure_chest.go b/db/treasure_chest.go index b0f4566..f0e2dfe 100644 --- a/db/treasure_chest.go +++ b/db/treasure_chest.go @@ -30,8 +30,8 @@ func NewTreasureChestSqlite(db *sqlx.DB) *TreasureChestSqlite { func (db TreasureChestSqlite) Insert(userId uuid.UUID, treasureChest *types.TreasureChest) error { _, err := db.db.Exec(` - INSERT INTO treasure_chest (id, parent_id, user_id, name, account_id, current_balance, created_at, created_by) - VALUES (?,?,?,?,?,?,?,?)`, treasureChest.Id, treasureChest.ParentId, userId, treasureChest.Name, treasureChest.AccountId, 0, treasureChest.CreatedAt, treasureChest.CreatedBy) + INSERT INTO treasure_chest (id, parent_id, user_id, name, current_balance, created_at, created_by) + VALUES (?,?,?,?,?,?,?)`, treasureChest.Id, treasureChest.ParentId, userId, treasureChest.Name, 0, treasureChest.CreatedAt, treasureChest.CreatedBy) if err != nil { log.Error("treasureChest Insert: %v", err) return types.ErrInternal @@ -47,12 +47,11 @@ func (db TreasureChestSqlite) Update(userId uuid.UUID, treasureChest *types.Trea SET parent_id = ?, name = ?, - account_id = ?, current_balance = ?, updated_at = ?, updated_by = ? WHERE id = ? - AND user_id = ?`, treasureChest.ParentId, treasureChest.Name, treasureChest.AccountId, treasureChest.CurrentBalance, treasureChest.UpdatedAt, treasureChest.UpdatedBy, treasureChest.Id, userId) + AND user_id = ?`, treasureChest.ParentId, treasureChest.Name, treasureChest.CurrentBalance, treasureChest.UpdatedAt, treasureChest.UpdatedBy, treasureChest.Id, userId) if err != nil { log.Error("treasureChest Update: %v", err) return types.ErrInternal @@ -76,7 +75,7 @@ func (db TreasureChestSqlite) GetAll(userId uuid.UUID) ([]*types.TreasureChest, treasureChests := make([]*types.TreasureChest, 0) err := db.db.Select(&treasureChests, ` SELECT - id, parent_id, user_id, name, account_id, current_balance, + id, parent_id, user_id, name, current_balance, created_at, created_by, updated_at, updated_by FROM treasure_chest WHERE user_id = ? @@ -94,7 +93,7 @@ func (db TreasureChestSqlite) GetAllByParentId(userId uuid.UUID, parentId uuid.U treasureChests := make([]*types.TreasureChest, 0) err := db.db.Select(&treasureChests, ` SELECT - id, parent_id, user_id, name, account_id, current_balance, + id, parent_id, user_id, name, current_balance, created_at, created_by, updated_at, updated_by FROM treasure_chest WHERE user_id = ? @@ -113,7 +112,7 @@ func (db TreasureChestSqlite) Get(userId uuid.UUID, id uuid.UUID) (*types.Treasu treasureChest := &types.TreasureChest{} err := db.db.Get(treasureChest, ` SELECT - id, parent_id, user_id, name, account_id, current_balance, + id, parent_id, user_id, name, current_balance, created_at, created_by, updated_at, updated_by FROM treasure_chest WHERE user_id = ? diff --git a/handler/treasure_chest.go b/handler/treasure_chest.go index d69890e..38e1e4d 100644 --- a/handler/treasure_chest.go +++ b/handler/treasure_chest.go @@ -3,14 +3,12 @@ package handler import ( "net/http" "spend-sparrow/handler/middleware" - "spend-sparrow/log" "spend-sparrow/service" t "spend-sparrow/template/treasurechest" "spend-sparrow/types" "spend-sparrow/utils" "github.com/a-h/templ" - "github.com/google/uuid" ) type TreasureChest interface { @@ -18,18 +16,16 @@ type TreasureChest interface { } type TreasureChestImpl struct { - s service.TreasureChest - account service.Account - a service.Auth - r *Render + s service.TreasureChest + a service.Auth + r *Render } -func NewTreasureChest(s service.TreasureChest, account service.Account, a service.Auth, r *Render) TreasureChest { +func NewTreasureChest(s service.TreasureChest, a service.Auth, r *Render) TreasureChest { return TreasureChestImpl{ - s: s, - account: account, - a: a, - r: r, + s: s, + a: a, + r: r, } } @@ -53,13 +49,8 @@ func (h TreasureChestImpl) handleTreasureChestPage() http.HandlerFunc { handleError(w, r, err) return } - accounts, err := h.account.GetAll(user) - if err != nil { - handleError(w, r, err) - return - } - comp := t.TreasureChest(treasureChests, accounts) + comp := t.TreasureChest(treasureChests) h.r.RenderLayout(r, w, comp, user) } } @@ -72,7 +63,7 @@ func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc { return } - accounts, err := h.account.GetAll(user) + treasureChests, err := h.s.GetAll(user) if err != nil { handleError(w, r, err) return @@ -80,7 +71,7 @@ func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc { id := r.PathValue("id") if id == "new" { - comp := t.EditTreasureChest(nil, accounts) + comp := t.EditTreasureChest(nil, treasureChests) h.r.Render(r, w, comp) return } @@ -93,23 +84,14 @@ func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc { var comp templ.Component if r.URL.Query().Get("edit") == "true" { - comp = t.EditTreasureChest(treasureChest, accounts) + comp = t.EditTreasureChest(treasureChest, treasureChests) } else { - comp = t.TreasureChestItem(treasureChest, find(accounts, treasureChest.AccountId)) + comp = t.TreasureChestItem(treasureChest) } h.r.Render(r, w, comp) } } -func find(accounts []*types.Account, id uuid.UUID) *types.Account { - for _, account := range accounts { - if account.Id == id { - return account - } - } - return nil -} - func (h TreasureChestImpl) handleUpdateTreasureChest() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { user := middleware.GetUser(r) @@ -125,24 +107,21 @@ func (h TreasureChestImpl) handleUpdateTreasureChest() http.HandlerFunc { id := r.PathValue("id") parentId := r.FormValue("parent-id") name := r.FormValue("name") - accountId := r.FormValue("account-id") - log.Info("accountId: %s", accountId) if id == "new" { - treasureChest, err = h.s.Add(user, parentId, name, accountId) + treasureChest, err = h.s.Add(user, parentId, name) if err != nil { handleError(w, r, err) return } } else { - treasureChest, err = h.s.Update(user, id, parentId, name, accountId) + treasureChest, err = h.s.Update(user, id, parentId, name) if err != nil { handleError(w, r, err) return } } - account, err := h.account.Get(user, accountId) - comp := t.TreasureChestItem(treasureChest, account) + comp := t.TreasureChestItem(treasureChest) h.r.Render(r, w, comp) } } diff --git a/main.go b/main.go index 0d16f65..689791d 100644 --- a/main.go +++ b/main.go @@ -122,7 +122,7 @@ func createHandler(d *sqlx.DB, serverSettings *types.Settings) http.Handler { indexHandler := handler.NewIndex(authService, render) authHandler := handler.NewAuth(authService, render) accountHandler := handler.NewAccount(accountService, authService, render) - treasureChestHandler := handler.NewTreasureChest(treasureChestService, accountService, authService, render) + treasureChestHandler := handler.NewTreasureChest(treasureChestService, authService, render) indexHandler.Handle(router) accountHandler.Handle(router) diff --git a/service/treasure_chest.go b/service/treasure_chest.go index 5b016a7..bdba171 100644 --- a/service/treasure_chest.go +++ b/service/treasure_chest.go @@ -23,8 +23,8 @@ var ( ) type TreasureChest interface { - Add(user *types.User, parentId, name, accountId string) (*types.TreasureChest, error) - Update(user *types.User, id, parentId, name, accountId string) (*types.TreasureChest, error) + Add(user *types.User, parentId, name string) (*types.TreasureChest, error) + Update(user *types.User, id, parentId, name string) (*types.TreasureChest, error) Get(user *types.User, id string) (*types.TreasureChest, error) GetAll(user *types.User) ([]*types.TreasureChest, error) Delete(user *types.User, id string) error @@ -48,7 +48,7 @@ func NewTreasureChest(db db.TreasureChest, account Account, random Random, clock } } -func (s TreasureChestImpl) Add(user *types.User, parentId, name, accountId string) (*types.TreasureChest, error) { +func (s TreasureChestImpl) Add(user *types.User, parentId, name string) (*types.TreasureChest, error) { treasureChestMetric.WithLabelValues("add").Inc() if user == nil { @@ -64,11 +64,6 @@ func (s TreasureChestImpl) Add(user *types.User, parentId, name, accountId strin if err != nil { return nil, err } - accountUuid, err := uuid.Parse(accountId) - if err != nil { - log.Error("treasureChest add: %v", err) - return nil, fmt.Errorf("could not parse accountId: %w", ErrBadRequest) - } parentUuid := uuid.Nil if parentId != "" { @@ -82,18 +77,12 @@ func (s TreasureChestImpl) Add(user *types.User, parentId, name, accountId strin parentUuid = parent.Id } - _, err = s.account.Get(user, accountId) - if err != nil { - return nil, err - } - treasureChest := &types.TreasureChest{ Id: newId, ParentId: parentUuid, UserId: user.Id, - Name: name, - AccountId: accountUuid, + Name: name, CurrentBalance: 0, @@ -116,7 +105,7 @@ func (s TreasureChestImpl) Add(user *types.User, parentId, name, accountId strin return savedtreasureChest, nil } -func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name, accountId string) (*types.TreasureChest, error) { +func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name string) (*types.TreasureChest, error) { treasureChestMetric.WithLabelValues("update").Inc() if user == nil { return nil, ErrUnauthorized @@ -125,11 +114,6 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name, accou if err != nil { return nil, err } - accountUuid, err := uuid.Parse(accountId) - if err != nil { - log.Error("treasureChest update: %v", err) - return nil, fmt.Errorf("could not parse accountId: %w", ErrBadRequest) - } id, err := uuid.Parse(idStr) if err != nil { log.Error("treasureChest update: %v", err) @@ -143,10 +127,6 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name, accou } return nil, types.ErrInternal } - _, err = s.account.Get(user, accountId) - if err != nil { - return nil, err - } parentUuid := uuid.Nil if parentId != "" { @@ -157,13 +137,18 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name, accou if parent.ParentId != uuid.Nil { return nil, fmt.Errorf("Only a depth of 1 allowed: %w", ErrBadRequest) } + + children, err := s.db.GetAllByParentId(user.Id, treasureChest.Id) + if len(children) > 0 { + return nil, fmt.Errorf("Only a depth of 1 allowed: %w", ErrBadRequest) + } + parentUuid = parent.Id } timestamp := s.clock.Now() treasureChest.Name = name treasureChest.ParentId = parentUuid - treasureChest.AccountId = accountUuid treasureChest.UpdatedAt = ×tamp treasureChest.UpdatedBy = &user.Id diff --git a/template/treasurechest/treasure_chest.templ b/template/treasurechest/treasure_chest.templ index 5e1d7e3..16c0d89 100644 --- a/template/treasurechest/treasure_chest.templ +++ b/template/treasurechest/treasure_chest.templ @@ -1,14 +1,47 @@ package treasurechest import "fmt" + import "spend-sparrow/template/svg" import "spend-sparrow/types" + import "github.com/google/uuid" -// TODO: Incorporate parent-id and hirarchical view -xxx +func sortTree(nodes []*types.TreasureChest) []*types.TreasureChest { -templ TreasureChest(treasureChests []*types.TreasureChest, accounts []*types.Account) { + var ( + roots []*types.TreasureChest + result []*types.TreasureChest + ) + children := make(map[uuid.UUID][]*types.TreasureChest) + + for _, node := range nodes { + if node.ParentId == uuid.Nil { + roots = append(roots, node) + } else { + children[node.ParentId] = append(children[node.ParentId], node) + } + } + + for _, root := range roots { + result = append(result, root) + result = append(result, children[root.Id]...) + } + + return result +} + +func compareStrings(a, b string) int { + if a < b { + return -1 + } + if a > b { + return 1 + } + return 0 +} + +templ TreasureChest(treasureChests []*types.TreasureChest) {