fix(treasurechest): make parentId actually null/nil instead of uuid.Nil
All checks were successful
Build Docker Image / Build-Docker-Image (push) Successful in 5m0s
Build and Push Docker Image / Build-And-Push-Docker-Image (push) Successful in 5m25s

This commit was merged in pull request #117.
This commit is contained in:
2025-05-19 19:56:06 +02:00
parent b18863038c
commit 7a691ec263
8 changed files with 54 additions and 39 deletions

View File

@@ -228,7 +228,7 @@ func (h TransactionImpl) getTransactionData(accounts []*types.Account, treasureC
treasureChestMap := make(map[uuid.UUID]string, 0) treasureChestMap := make(map[uuid.UUID]string, 0)
root := "" root := ""
for _, treasureChest := range treasureChests { for _, treasureChest := range treasureChests {
if treasureChest.ParentId == uuid.Nil { if treasureChest.ParentId == nil {
root = treasureChest.Name + " > " root = treasureChest.Name + " > "
treasureChestMap[treasureChest.Id] = treasureChest.Name treasureChestMap[treasureChest.Id] = treasureChest.Name
} else { } else {

View File

@@ -0,0 +1,3 @@
UPDATE treasure_chest
SET parent_id = NULL
WHERE parent_id = "00000000-0000-0000-0000-000000000000";

View File

@@ -6,7 +6,7 @@ import (
) )
var ( var (
safeInputRegex = regexp.MustCompile(`^[a-zA-Z0-9ÄÖÜäöüß, -]+$`) safeInputRegex = regexp.MustCompile(`^[a-zA-Z0-9ÄÖÜäöüß,& -]+$`)
) )
func validateString(value string, fieldName string) error { func validateString(value string, fieldName string) error {

View File

@@ -424,6 +424,7 @@ func (s TransactionImpl) RecalculateBalances(user *types.User) error {
if err != nil { if err != nil {
return err return err
} }
} }
} }
@@ -493,14 +494,17 @@ func (s TransactionImpl) validateAndEnrichTransaction(tx *sqlx.Tx, oldTransactio
return nil, fmt.Errorf("could not parse treasureChestId: %w", ErrBadRequest) return nil, fmt.Errorf("could not parse treasureChestId: %w", ErrBadRequest)
} }
treasureChestUuid = &temp treasureChestUuid = &temp
err = tx.Get(&rowCount, `SELECT COUNT(*) FROM treasure_chest WHERE id = ? AND user_id = ?`, treasureChestUuid, userId) var treasureChest types.TreasureChest
err = tx.Get(&treasureChest, `SELECT * FROM treasure_chest WHERE id = ? AND user_id = ?`, treasureChestUuid, userId)
err = db.TransformAndLogDbError("transaction validate", nil, err) err = db.TransformAndLogDbError("transaction validate", nil, err)
if err != nil { if err != nil {
if err == db.ErrNotFound {
return nil, fmt.Errorf("treasure chest not found: %w", ErrBadRequest)
}
return nil, err return nil, err
} }
if rowCount == 0 { if treasureChest.ParentId == nil {
log.Error("transaction validate: %v", err) return nil, fmt.Errorf("treasure chest is a group: %w", ErrBadRequest)
return nil, fmt.Errorf("treasure chest not found: %w", ErrBadRequest)
} }
} }

View File

@@ -65,16 +65,16 @@ func (s TreasureChestImpl) Add(user *types.User, parentId, name string) (*types.
return nil, err return nil, err
} }
parentUuid := uuid.Nil var parentUuid *uuid.UUID
if parentId != "" { if parentId != "" {
parent, err := s.Get(user, parentId) parent, err := s.Get(user, parentId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if parent.ParentId != uuid.Nil { if parent.ParentId != nil {
return nil, fmt.Errorf("only a depth of 1 allowed: %w", ErrBadRequest) return nil, fmt.Errorf("only a depth of 1 allowed: %w", ErrBadRequest)
} }
parentUuid = parent.Id parentUuid = &parent.Id
} }
treasureChest := &types.TreasureChest{ treasureChest := &types.TreasureChest{
@@ -137,7 +137,7 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name string
return nil, types.ErrInternal return nil, types.ErrInternal
} }
parentUuid := uuid.Nil var parentUuid *uuid.UUID
if parentId != "" { if parentId != "" {
parent, err := s.Get(user, parentId) parent, err := s.Get(user, parentId)
if err != nil { if err != nil {
@@ -149,11 +149,11 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name string
if err != nil { if err != nil {
return nil, err return nil, err
} }
if parent.ParentId != uuid.Nil || childCount > 0 { if parent.ParentId != nil || childCount > 0 {
return nil, fmt.Errorf("only one level allowed: %w", ErrBadRequest) return nil, fmt.Errorf("only one level allowed: %w", ErrBadRequest)
} }
parentUuid = parent.Id parentUuid = &parent.Id
} }
timestamp := s.clock.Now() timestamp := s.clock.Now()
@@ -292,10 +292,10 @@ func sortTree(nodes []*types.TreasureChest) []*types.TreasureChest {
children := make(map[uuid.UUID][]*types.TreasureChest) children := make(map[uuid.UUID][]*types.TreasureChest)
for _, node := range nodes { for _, node := range nodes {
if node.ParentId == uuid.Nil { if node.ParentId == nil {
roots = append(roots, node) roots = append(roots, node)
} else { } else {
children[node.ParentId] = append(children[node.ParentId], node) children[*node.ParentId] = append(children[*node.ParentId], node)
} }
} }

View File

@@ -27,10 +27,10 @@ templ Transaction(items templ.Component, filter types.TransactionItemsFilter, ac
<select name="treasure-chest-id" class="bg-white input"> <select name="treasure-chest-id" class="bg-white input">
<option value="">- Filter Treasure Chest -</option> <option value="">- Filter Treasure Chest -</option>
for _, parent := range treasureChests { for _, parent := range treasureChests {
if parent.ParentId == uuid.Nil { if parent.ParentId == nil {
<optgroup label={ parent.Name }> <optgroup label={ parent.Name }>
for _, child := range treasureChests { for _, child := range treasureChests {
if child.ParentId == parent.Id { if *child.ParentId == parent.Id {
<option <option
value={ child.Id.String() } value={ child.Id.String() }
selected?={ filter.TreasureChestId == child.Id.String() } selected?={ filter.TreasureChestId == child.Id.String() }
@@ -158,19 +158,21 @@ templ EditTransaction(transaction *types.Transaction, accounts []*types.Account,
} }
</select> </select>
<label for="treasure-chest-id" class="text-sm text-gray-500">Treasure Chest</label> <label for="treasure-chest-id" class="text-sm text-gray-500">Treasure Chest</label>
<select <select name="treasure-chest-id" class="bg-white input">
name="treasure-chest-id" <option value="">- Filter Treasure Chest -</option>
class="bg-white input" for _, parent := range treasureChests {
> if parent.ParentId == nil {
<option value="">-</option> <optgroup label={ parent.Name }>
for _, treasureChest := range treasureChests { for _, child := range treasureChests {
<option selected?={ treasureChest.Id.String() == treasureChestId } value={ treasureChest.Id.String() }> if *child.ParentId == parent.Id {
if treasureChest.ParentId != uuid.Nil { <option
&nbsp;&nbsp;&nbsp;{ treasureChest.Name } value={ child.Id.String() }
} else { selected?={ treasureChestId == child.Id.String() }
{ treasureChest.Name } >{ child.Name }</option>
} }
</option> }
</optgroup>
}
} }
</select> </select>
</div> </div>

View File

@@ -41,7 +41,9 @@ templ EditTreasureChest(treasureChest *types.TreasureChest, parents []*types.Tre
} else { } else {
id = treasureChest.Id.String() id = treasureChest.Id.String()
name = treasureChest.Name name = treasureChest.Name
parentId = treasureChest.ParentId if treasureChest.ParentId != nil {
parentId = *treasureChest.ParentId
}
cancelUrl = "/treasurechest/" + id cancelUrl = "/treasurechest/" + id
} }
}} }}
@@ -93,23 +95,27 @@ templ EditTreasureChest(treasureChest *types.TreasureChest, parents []*types.Tre
templ TreasureChestItem(treasureChest *types.TreasureChest) { templ TreasureChestItem(treasureChest *types.TreasureChest) {
{{ {{
var identation string var identation string
if treasureChest.ParentId != uuid.Nil { viewTransactions := ""
if treasureChest.ParentId != nil {
identation = " mt-2 ml-36" identation = " mt-2 ml-36"
} else { } else {
identation = " mt-8" identation = " mt-8"
viewTransactions = "hidden"
} }
}} }}
<div id="treasurechest" class={ "border-1 border-gray-300 w-full p-4 bg-gray-50 rounded-lg" + identation }> <div id="treasurechest" class={ "border-1 border-gray-300 w-full p-4 bg-gray-50 rounded-lg" + identation }>
<div class="text-xl flex justify-end items-center gap-4"> <div class="text-xl flex justify-end items-center gap-4">
<p class="mr-auto">{ treasureChest.Name }</p> <p class="mr-auto">{ treasureChest.Name }</p>
if treasureChest.CurrentBalance < 0 { if treasureChest.ParentId != nil {
<p class="mr-20 text-red-700">{ displayBalance(treasureChest.CurrentBalance) }</p> if treasureChest.CurrentBalance < 0 {
} else { <p class="mr-20 text-red-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
<p class="mr-20 text-green-700">{ displayBalance(treasureChest.CurrentBalance) }</p> } else {
<p class="mr-20 text-green-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
}
} }
<a <a
href={ templ.URL("/transaction?treasure-chest-id=" + treasureChest.Id.String()) } href={ templ.URL("/transaction?treasure-chest-id=" + treasureChest.Id.String()) }
class="button button-neglect px-1 flex items-center gap-2" class={ "button button-neglect px-1 flex items-center gap-2 " + viewTransactions }
title="View transactions" title="View transactions"
> >
@svg.Eye() @svg.Eye()
@@ -147,7 +153,7 @@ func filterNoChildNoSelf(nodes []*types.TreasureChest, selfId string) []*types.T
var result []*types.TreasureChest var result []*types.TreasureChest
for _, node := range nodes { for _, node := range nodes {
if node.ParentId == uuid.Nil && node.Id.String() != selfId { if node.ParentId == nil && node.Id.String() != selfId {
result = append(result, node) result = append(result, node)
} }
} }

View File

@@ -13,8 +13,8 @@ import (
// Imagne a TreasureChest for free time activities, where some money is spend in cash and some other with credit card // Imagne a TreasureChest for free time activities, where some money is spend in cash and some other with credit card
type TreasureChest struct { type TreasureChest struct {
Id uuid.UUID Id uuid.UUID
ParentId uuid.UUID `db:"parent_id"` ParentId *uuid.UUID `db:"parent_id"`
UserId uuid.UUID `db:"user_id"` UserId uuid.UUID `db:"user_id"`
Name string Name string