Merge branch 'main' into users

This commit is contained in:
Huffle 2025-05-14 15:46:26 +02:00
commit fd14c12a4a
8 changed files with 119 additions and 47 deletions

View File

@ -5,6 +5,7 @@ import (
"github.com/gavv/httpexpect/v2" "github.com/gavv/httpexpect/v2"
"strconv" "strconv"
"testing" "testing"
"time"
) )
const ( const (
@ -35,6 +36,7 @@ func TestGetUser(t *testing.T) {
result := e.GET("/user/1").Expect().Status(200).JSON().Object() result := e.GET("/user/1").Expect().Status(200).JSON().Object()
result.Value("name").IsEqual("Seeseemelk") result.Value("name").IsEqual("Seeseemelk")
result.Value("id").IsEqual(1) result.Value("id").IsEqual(1)
result.Value("allowance").IsEqual(0)
} }
func TestGetUserUnknown(t *testing.T) { func TestGetUserUnknown(t *testing.T) {
@ -402,5 +404,25 @@ func TestPostAllowanceInvalidUserId(t *testing.T) {
e.POST("/user/999/allowance").WithJSON(PostAllowance{Allowance: 100}).Expect(). e.POST("/user/999/allowance").WithJSON(PostAllowance{Allowance: 100}).Expect().
Status(404) Status(404)
}
func TestGetHistory(t *testing.T) {
e := startServer(t)
e.POST("/user/1/allowance").WithJSON(PostAllowance{Allowance: 100}).Expect().Status(200)
e.POST("/user/1/allowance").WithJSON(PostAllowance{Allowance: 20}).Expect().Status(200)
e.POST("/user/1/allowance").WithJSON(PostAllowance{Allowance: -10}).Expect().Status(200)
response := e.GET("/user/1/history").Expect().Status(200).JSON().Array()
response.Length().IsEqual(3)
response.Value(0).Object().Value("allowance").Number().IsEqual(100)
response.Value(0).Object().Value("timestamp").String().AsDateTime().InRange(getDelta(time.Now(), 2.0))
response.Value(1).Object().Value("allowance").Number().IsEqual(20)
response.Value(2).Object().Value("allowance").Number().IsEqual(-10)
}
func getDelta(base time.Time, delta float64) (time.Time, time.Time) {
start := base.Add(-time.Duration(delta) * time.Second)
end := base.Add(time.Duration(delta) * time.Second)
return start, end
} }

View File

@ -243,7 +243,7 @@ func (db *Db) AddAllowance(userId int, allowance *PostAllowance) error {
} }
defer tx.MustRollback() defer tx.MustRollback()
err = tx.Query("insert into history (user_id, date, amount) values (?, ?, ?)"). err = tx.Query("insert into history (user_id, timestamp, amount) values (?, ?, ?)").
Bind(userId, time.Now().Unix(), allowance.Allowance). Bind(userId, time.Now().Unix(), allowance.Allowance).
Exec() Exec()
if err != nil { if err != nil {
@ -251,3 +251,24 @@ func (db *Db) AddAllowance(userId int, allowance *PostAllowance) error {
} }
return tx.Commit() return tx.Commit()
} }
func (db *Db) GetHistory(userId int) ([]Allowance, error) {
history := make([]Allowance, 0)
var err error
for row := range db.db.Query("select amount, `timestamp` from history where user_id = ? order by `timestamp` desc").
Bind(userId).Range(&err) {
allowance := Allowance{}
var timestamp int64
err = row.Scan(&allowance.Allowance, &timestamp)
if err != nil {
return nil, err
}
allowance.Timestamp = time.Unix(timestamp, 0)
history = append(history, allowance)
}
if err != nil {
return nil, err
}
return history, nil
}

View File

@ -1,5 +1,7 @@
package main package main
import "time"
type User struct { type User struct {
ID int `json:"id"` ID int `json:"id"`
Name string `json:"name"` Name string `json:"name"`
@ -13,7 +15,7 @@ type UserWithAllowance struct {
type Allowance struct { type Allowance struct {
Allowance int `json:"allowance"` Allowance int `json:"allowance"`
Goals []Goal `json:"goals"` Timestamp time.Time `json:"timestamp"`
} }
type PostAllowance struct { type PostAllowance struct {

View File

@ -3,8 +3,9 @@ module allowance_planner
go 1.24.2 go 1.24.2
require ( require (
gitea.seeseepuff.be/seeseemelk/mysqlite v0.11.1 gitea.seeseepuff.be/seeseemelk/mysqlite v0.12.0
github.com/gavv/httpexpect/v2 v2.17.0 github.com/gavv/httpexpect/v2 v2.17.0
github.com/gin-contrib/cors v1.7.5
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
) )
@ -67,7 +68,7 @@ require (
gopkg.in/fsnotify.v1 v1.4.7 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.65.2 // indirect modernc.org/libc v1.65.6 // indirect
modernc.org/mathutil v1.7.1 // indirect modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.10.0 // indirect modernc.org/memory v1.10.0 // indirect
modernc.org/sqlite v1.37.0 // indirect modernc.org/sqlite v1.37.0 // indirect

View File

@ -1,5 +1,5 @@
gitea.seeseepuff.be/seeseemelk/mysqlite v0.11.1 h1:5s0r2IRpomGJC6pjirdMk7HAcAYEydLK5AhBZy+V1Ys= gitea.seeseepuff.be/seeseemelk/mysqlite v0.12.0 h1:kl0VFgvm52UKxJhZpf1hvucxZdOoXY50g/VmzsWH+/8=
gitea.seeseepuff.be/seeseemelk/mysqlite v0.11.1/go.mod h1:cgswydOxJjMlNwfcBIXnKjr47LwXnMT9BInkiHb0tXE= gitea.seeseepuff.be/seeseemelk/mysqlite v0.12.0/go.mod h1:cgswydOxJjMlNwfcBIXnKjr47LwXnMT9BInkiHb0tXE=
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4= github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4=
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w= github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
@ -28,6 +28,8 @@ github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBv
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
github.com/gavv/httpexpect/v2 v2.17.0 h1:nIJqt5v5e4P7/0jODpX2gtSw+pHXUqdP28YcjqwDZmE= github.com/gavv/httpexpect/v2 v2.17.0 h1:nIJqt5v5e4P7/0jODpX2gtSw+pHXUqdP28YcjqwDZmE=
github.com/gavv/httpexpect/v2 v2.17.0/go.mod h1:E8ENFlT9MZ3Si2sfM6c6ONdwXV2noBCGkhA+lkJgkP0= github.com/gavv/httpexpect/v2 v2.17.0/go.mod h1:E8ENFlT9MZ3Si2sfM6c6ONdwXV2noBCGkhA+lkJgkP0=
github.com/gin-contrib/cors v1.7.5 h1:cXC9SmofOrRg0w9PigwGlHG3ztswH6bqq4vJVXnvYMk=
github.com/gin-contrib/cors v1.7.5/go.mod h1:4q3yi7xBEDDWKapjT2o1V7mScKDDr8k+jZ0fSquGoy0=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
@ -68,8 +70,9 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@ -100,6 +103,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/sanity-io/litter v1.5.8 h1:uM/2lKrWdGbRXDrIq08Lh9XtVYoeGtcQxk9rtQ7+rYg= github.com/sanity-io/litter v1.5.8 h1:uM/2lKrWdGbRXDrIq08Lh9XtVYoeGtcQxk9rtQ7+rYg=
github.com/sanity-io/litter v1.5.8/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= github.com/sanity-io/litter v1.5.8/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
@ -188,8 +193,9 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@ -202,14 +208,14 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s= modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s=
modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.27.1 h1:emhLB4uoOmkZUnTDFcMI3AbkmU/Evjuerit9Taqe6Ss= modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
modernc.org/ccgo/v4 v4.27.1/go.mod h1:543Q0qQhJWekKVS5P6yL5fO6liNhla9Lbm2/B3rEKDE= modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
modernc.org/fileutil v1.3.1 h1:8vq5fe7jdtEvoCf3Zf9Nm0Q05sH6kGx0Op2CPx1wTC8= modernc.org/fileutil v1.3.1 h1:8vq5fe7jdtEvoCf3Zf9Nm0Q05sH6kGx0Op2CPx1wTC8=
modernc.org/fileutil v1.3.1/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= modernc.org/fileutil v1.3.1/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/libc v1.65.2 h1:drWL1QO9fKXr3kXDN8y+4lKyBr8bA3mtUBQpftq3IJw= modernc.org/libc v1.65.6 h1:OhJUhmuJ6MVZdqL5qmnd0/my46DKGFhSX4WOR7ijfyE=
modernc.org/libc v1.65.2/go.mod h1:VI3V2S5mNka4deJErQ0jsMXe7jgxojE2fOB/mWoHlbc= modernc.org/libc v1.65.6/go.mod h1:MOiGAM9lrMBT9L8xT1nO41qYl5eg9gCp9/kWhz5L7WA=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.10.0 h1:fzumd51yQ1DxcOxSO+S6X7+QTuVU+n8/Aj7swYjFfC4= modernc.org/memory v1.10.0 h1:fzumd51yQ1DxcOxSO+S6X7+QTuVU+n8/Aj7swYjFfC4=

View File

@ -11,6 +11,7 @@ import (
"os" "os"
"strconv" "strconv"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -185,7 +186,7 @@ func deleteUserGoal(c *gin.Context) {
return return
} }
c.JSON(http.StatusOK, gin.H{"message": "Goal deleted successfully"}) c.IndentedJSON(http.StatusOK, gin.H{"message": "Goal deleted successfully"})
} }
func createTask(c *gin.Context) { func createTask(c *gin.Context) {
@ -233,7 +234,7 @@ func getTasks(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": ErrInternalServerError}) c.JSON(http.StatusInternalServerError, gin.H{"error": ErrInternalServerError})
return return
} }
c.JSON(http.StatusOK, &response) c.IndentedJSON(http.StatusOK, &response)
} }
func getTask(c *gin.Context) { func getTask(c *gin.Context) {
@ -325,8 +326,26 @@ func postAllowance(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "Allowance updated successfully"}) c.JSON(http.StatusOK, gin.H{"message": "Allowance updated successfully"})
} }
func getHistory(c *gin.Context) {
userIdStr := c.Param("userId")
userId, err := strconv.Atoi(userIdStr)
if err != nil {
log.Printf("Invalid user ID: %v", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
return
}
history, err := db.GetHistory(userId)
if err != nil {
log.Printf("Error getting history: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": ErrInternalServerError})
return
}
c.IndentedJSON(http.StatusOK, history)
}
/* /*
*
Initialises the database, and then starts the server. Initialises the database, and then starts the server.
If the context gets cancelled, the server is shutdown and the database is closed. If the context gets cancelled, the server is shutdown and the database is closed.
*/ */
@ -335,8 +354,11 @@ func start(ctx context.Context, config *ServerConfig) {
defer db.db.MustClose() defer db.db.MustClose()
router := gin.Default() router := gin.Default()
router.Use(cors.Default())
router.GET("/api/users", getUsers) router.GET("/api/users", getUsers)
router.GET("/api/user/:userId", getUser) router.GET("/api/user/:userId", getUser)
router.POST("/api/user/:userId/allowance", postAllowance)
router.GET("/api/user/:userId/history", getHistory)
router.GET("/api/user/:userId/goals", getUserGoals) router.GET("/api/user/:userId/goals", getUserGoals)
router.POST("/api/user/:userId/goals", createUserGoal) router.POST("/api/user/:userId/goals", createUserGoal)
router.DELETE("/api/user/:userId/goal/:goalId", deleteUserGoal) router.DELETE("/api/user/:userId/goal/:goalId", deleteUserGoal)
@ -344,7 +366,6 @@ func start(ctx context.Context, config *ServerConfig) {
router.GET("/api/tasks", getTasks) router.GET("/api/tasks", getTasks)
router.GET("/api/task/:taskId", getTask) router.GET("/api/task/:taskId", getTask)
router.PUT("/api/task/:taskId", putTask) router.PUT("/api/task/:taskId", putTask)
router.POST("/api/user/:userId/allowance", postAllowance)
srv := &http.Server{ srv := &http.Server{
Addr: config.Addr, Addr: config.Addr,
@ -377,6 +398,7 @@ func start(ctx context.Context, config *ServerConfig) {
func main() { func main() {
config := ServerConfig{ config := ServerConfig{
Datasource: os.Getenv("DB_PATH"), Datasource: os.Getenv("DB_PATH"),
Addr: ":8080",
} }
start(context.Background(), &config) start(context.Background(), &config)
} }

View File

@ -8,7 +8,7 @@ create table history
( (
id integer primary key, id integer primary key,
user_id integer not null, user_id integer not null,
date date not null, timestamp date not null,
amount integer not null amount integer not null
); );

View File

@ -60,6 +60,32 @@ paths:
description: The users could not be found. description: The users could not be found.
/user/{userId}/allowance: /user/{userId}/allowance:
get:
summary: Gets the allowance history of a user
parameters:
- in: path
name: userId
description: The user ID
required: true
schema:
type: integer
responses:
200:
description: Information about the allowance history of the user
content:
application/json:
schema:
type: array
items:
type: object
properties:
date:
type: string
format: date-time
description: The date of the allowance or expense.
amount:
type: integer
description: The amount of the allowance to be added, in cents. A negative value
post: post:
summary: Updates the allowance of a user summary: Updates the allowance of a user
parameters: parameters:
@ -88,34 +114,6 @@ paths:
400: 400:
description: The allowance could not be updated. description: The allowance could not be updated.
/user/{userId}/history:
get:
summary: Gets the allowance history of a user
parameters:
- in: path
name: userId
description: The user ID
required: true
schema:
type: integer
responses:
200:
description: Information about the allowance history of the user
content:
application/json:
schema:
type: array
items:
type: object
properties:
date:
type: string
format: date-time
description: The date of the allowance or expense.
amount:
type: integer
description: The amount of the allowance to be added, in cents. A negative value
/user/{userId}/goals: /user/{userId}/goals:
get: get:
summary: Gets all goals summary: Gets all goals