fix(treasurechest): make parentId actually null/nil instead of uuid.Nil
This commit was merged in pull request #117.
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
3
migration/007_treasure_chest_parent_id_fix.up.sql
Normal file
3
migration/007_treasure_chest_parent_id_fix.up.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
UPDATE treasure_chest
|
||||||
|
SET parent_id = NULL
|
||||||
|
WHERE parent_id = "00000000-0000-0000-0000-000000000000";
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
{ treasureChest.Name }
|
value={ child.Id.String() }
|
||||||
} else {
|
selected?={ treasureChestId == child.Id.String() }
|
||||||
{ treasureChest.Name }
|
>{ child.Name }</option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</optgroup>
|
||||||
}
|
}
|
||||||
</option>
|
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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.ParentId != nil {
|
||||||
if treasureChest.CurrentBalance < 0 {
|
if treasureChest.CurrentBalance < 0 {
|
||||||
<p class="mr-20 text-red-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
|
<p class="mr-20 text-red-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
|
||||||
} else {
|
} else {
|
||||||
<p class="mr-20 text-green-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
|
<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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ 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
|
||||||
|
|||||||
Reference in New Issue
Block a user