From a8e33327233d918d3df618a207f0e1eebd38d722 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Schaetzen Date: Sun, 25 May 2025 13:43:24 +0200 Subject: [PATCH] Add support for colour attribute on allowances in backend (#77) Closes #76 Reviewed-on: https://gitea.seeseepuff.be/seeseemelk/allowance_planner_2000/pulls/77 --- backend/api_test.go | 3 +++ backend/colour.go | 30 +++++++++++++++++++++++++++++ backend/colour_test.go | 30 +++++++++++++++++++++++++++++ backend/db.go | 27 +++++++++++++++++++------- backend/dto.go | 3 +++ backend/migrations/2_add_colour.sql | 2 ++ 6 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 backend/colour.go create mode 100644 backend/colour_test.go create mode 100644 backend/migrations/2_add_colour.sql diff --git a/backend/api_test.go b/backend/api_test.go index 584364b..15e8480 100644 --- a/backend/api_test.go +++ b/backend/api_test.go @@ -516,6 +516,7 @@ func TestPutAllowanceById(t *testing.T) { "name": TestAllowanceName, "target": 5000, "weight": 10, + "colour": "#FF5733", } resp := e.POST("/user/1/allowance").WithJSON(requestBody).Expect().Status(201).JSON().Object() allowanceId := int(resp.Value("id").Number().Raw()) @@ -525,6 +526,7 @@ func TestPutAllowanceById(t *testing.T) { "name": "Updated Allowance", "target": 6000, "weight": 15, + "colour": "#3357FF", } e.PUT("/user/1/allowance/" + strconv.Itoa(allowanceId)).WithJSON(updateRequest).Expect().Status(200) @@ -534,6 +536,7 @@ func TestPutAllowanceById(t *testing.T) { result.Value("name").IsEqual("Updated Allowance") result.Value("target").IsEqual(6000) result.Value("weight").IsEqual(15) + result.Value("colour").IsEqual("#3357FF") } func TestCompleteTask(t *testing.T) { diff --git a/backend/colour.go b/backend/colour.go new file mode 100644 index 0000000..0886ad4 --- /dev/null +++ b/backend/colour.go @@ -0,0 +1,30 @@ +package main + +import ( + "errors" + "fmt" +) + +func ConvertStringToColour(colourStr string) (int, error) { + if len(colourStr) == 0 { + return 0xFF0000, nil // Default colour if no string is provided + } + if colourStr[0] == '#' { + colourStr = colourStr[1:] + } + if len(colourStr) != 6 && len(colourStr) != 3 { + return 0, errors.New("colour must be a valid hex string") + } + var colour int + _, err := fmt.Sscanf(colourStr, "%x", &colour) + if err != nil { + return 0, fmt.Errorf("invalid colour format: %v", err) + } + if len(colourStr) == 3 { + r := (colour & 0xF00) >> 8 + g := (colour & 0x0F0) >> 4 + b := (colour & 0x00F) >> 0 + colour = (r << 16 << 4) | (g << 8 << 4) | (b << 0 << 4) + } + return colour, nil +} diff --git a/backend/colour_test.go b/backend/colour_test.go new file mode 100644 index 0000000..812e8bc --- /dev/null +++ b/backend/colour_test.go @@ -0,0 +1,30 @@ +package main + +import ( + "github.com/stretchr/testify/require" + "testing" +) + +func TestConvertStringToColourWithSign(t *testing.T) { + colour, err := ConvertStringToColour("#123456") + require.NoError(t, err) + require.Equal(t, 0x123456, colour) +} + +func TestConvertStringToColourWithoutSign(t *testing.T) { + colour, err := ConvertStringToColour("123456") + require.NoError(t, err) + require.Equal(t, 0x123456, colour) +} + +func TestConvertStringToColourWithSignThreeDigits(t *testing.T) { + colour, err := ConvertStringToColour("#ABC") + require.NoError(t, err) + require.Equal(t, 0xA0B0C0, colour) +} + +func TestConvertStringToColourWithoutSignThreeDigits(t *testing.T) { + colour, err := ConvertStringToColour("ABC") + require.NoError(t, err) + require.Equal(t, 0xA0B0C0, colour) +} diff --git a/backend/db.go b/backend/db.go index 71bd650..151594d 100644 --- a/backend/db.go +++ b/backend/db.go @@ -2,6 +2,7 @@ package main import ( "errors" + "fmt" "log" "math" "time" @@ -112,12 +113,13 @@ func (db *Db) GetUserAllowanceById(userId int, allowanceId int) (*Allowance, err return nil, err } } else { - var target, progress int64 - err := db.db.Query("select id, name, target, balance, weight from allowances where user_id = ? and id = ?"). + var target, progress, colour int64 + err := db.db.Query("select id, name, target, balance, weight, colour from allowances where user_id = ? and id = ?"). Bind(userId, allowanceId). - ScanSingle(&allowance.ID, &allowance.Name, &target, &progress, &allowance.Weight) + ScanSingle(&allowance.ID, &allowance.Name, &target, &progress, &allowance.Weight, &colour) allowance.Target = float64(target) / 100.0 allowance.Progress = float64(progress) / 100.0 + allowance.Colour = fmt.Sprintf("#%06X", colour) if err != nil { return nil, err } @@ -141,9 +143,15 @@ func (db *Db) CreateAllowance(userId int, allowance *CreateAllowanceRequest) (in } defer tx.MustRollback() + // Convert string colour to a valid hex format + colour, err := ConvertStringToColour(allowance.Colour) + if err != nil { + return 0, err + } + // Insert the new allowance - err = tx.Query("insert into allowances (user_id, name, target, weight) values (?, ?, ?, ?)"). - Bind(userId, allowance.Name, int(math.Round(allowance.Target*100.0)), allowance.Weight). + err = tx.Query("insert into allowances (user_id, name, target, weight, colour) values (?, ?, ?, ?, ?)"). + Bind(userId, allowance.Name, int(math.Round(allowance.Target*100.0)), allowance.Weight, colour). Exec() if err != nil { @@ -255,9 +263,14 @@ func (db *Db) UpdateAllowance(userId int, allowanceId int, allowance *UpdateAllo } defer tx.MustRollback() + colour, err := ConvertStringToColour(allowance.Colour) + if err != nil { + return err + } + target := int(math.Round(allowance.Target * 100.0)) - err = tx.Query("update allowances set name=?, target=?, weight=? where id = ? and user_id = ?"). - Bind(allowance.Name, target, allowance.Weight, allowanceId, userId). + err = tx.Query("update allowances set name=?, target=?, weight=?, colour=? where id = ? and user_id = ?"). + Bind(allowance.Name, target, allowance.Weight, colour, allowanceId, userId). Exec() if err != nil { return err diff --git a/backend/dto.go b/backend/dto.go index 3b859d1..5773f45 100644 --- a/backend/dto.go +++ b/backend/dto.go @@ -36,18 +36,21 @@ type Allowance struct { Target float64 `json:"target"` Progress float64 `json:"progress"` Weight float64 `json:"weight"` + Colour string `json:"colour"` } type CreateAllowanceRequest struct { Name string `json:"name"` Target float64 `json:"target"` Weight float64 `json:"weight"` + Colour string `json:"colour"` } type UpdateAllowanceRequest struct { Name string `json:"name"` Target float64 `json:"target"` Weight float64 `json:"weight"` + Colour string `json:"colour"` } type BulkUpdateAllowanceRequest struct { diff --git a/backend/migrations/2_add_colour.sql b/backend/migrations/2_add_colour.sql new file mode 100644 index 0000000..2381df8 --- /dev/null +++ b/backend/migrations/2_add_colour.sql @@ -0,0 +1,2 @@ +alter table allowances +add column colour integer not null;