From 5c13893f23feb647948b2969efd378c5bf196218 Mon Sep 17 00:00:00 2001 From: Teajey <21069848+Teajey@users.noreply.github.com> Date: Thu, 19 Jun 2025 19:52:24 +0900 Subject: [PATCH] feat: wish making --- core/internal/db/init.sql | 4 +- core/internal/fixtures/assert.go | 9 +++ core/internal/fixtures/login.go | 29 ++++++++ core/internal/normalize/name.go | 6 +- core/user.go | 5 ++ core/wish.go | 109 +++++++++++++++++++++++++++++++ core/wish_test.go | 28 ++++++++ 7 files changed, 183 insertions(+), 7 deletions(-) create mode 100644 core/internal/fixtures/assert.go create mode 100644 core/internal/fixtures/login.go create mode 100644 core/wish.go create mode 100644 core/wish_test.go diff --git a/core/internal/db/init.sql b/core/internal/db/init.sql index 8200404..8da1d9b 100644 --- a/core/internal/db/init.sql +++ b/core/internal/db/init.sql @@ -10,7 +10,7 @@ CREATE TABLE IF NOT EXISTS "user" ( "is_live" INTEGER NOT NULL DEFAULT 1, PRIMARY KEY("id" AUTOINCREMENT) ); -CREATE TABLE IF NOT EXISTS "gift" ( +CREATE TABLE IF NOT EXISTS "wish" ( "id" INTEGER NOT NULL UNIQUE, "name" TEXT NOT NULL, "recipient_id" INTEGER NOT NULL, @@ -50,6 +50,6 @@ SELECT * FROM user WHERE user.is_live = 1; -- DROP VIEW IF EXISTS "v_wish"; -- CREATE VIEW "v_wish" -- AS --- SELECT gift.id, gift.name, gift.sent FROM gift JOIN user AS recipient; +-- SELECT wish.id, wish.name, wish.sent FROM wish JOIN user AS recipient; COMMIT; diff --git a/core/internal/fixtures/assert.go b/core/internal/fixtures/assert.go new file mode 100644 index 0000000..3d654d8 --- /dev/null +++ b/core/internal/fixtures/assert.go @@ -0,0 +1,9 @@ +package fixtures + +import "testing" + +func AssertEq[C comparable](t *testing.T, context string, expected, actual C) { + if expected != actual { + t.Errorf("%s: %#v != %#v", context, expected, actual) + } +} diff --git a/core/internal/fixtures/login.go b/core/internal/fixtures/login.go new file mode 100644 index 0000000..99583de --- /dev/null +++ b/core/internal/fixtures/login.go @@ -0,0 +1,29 @@ +package fixtures + +import ( + "log" + "time" + + lishwist "lishwist/core" +) + +func Login(username, password string) *lishwist.Session { + err := lishwist.Init(":memory:") + if err != nil { + log.Fatalf("Failed to init db: %s\n", err) + } + + lw := lishwist.NewSessionManager(time.Second*10, 32) + + err = lishwist.Register("thomas", "123") + if err != nil { + log.Fatalf("Failed to register: %s\n", err) + } + + session, err := lw.Login("thomas", "123") + if err != nil { + log.Fatalf("Failed to login: %s\n", err) + } + + return session +} diff --git a/core/internal/normalize/name.go b/core/internal/normalize/name.go index ccd8574..54a1c59 100644 --- a/core/internal/normalize/name.go +++ b/core/internal/normalize/name.go @@ -4,11 +4,7 @@ import ( "strings" ) -func Trim(s string) string { - return strings.Trim(s, " \t") -} - func Name(name string) string { - name = Trim(name) + name = strings.TrimSpace(name) return strings.ToLower(name) } diff --git a/core/user.go b/core/user.go index e776f42..6b8b5f6 100644 --- a/core/user.go +++ b/core/user.go @@ -96,3 +96,8 @@ func (u *User) getPassHash() ([]byte, error) { } return []byte(passHash), nil } + +func getUserByReference(reference string) (*User, error) { + stmt := "SELECT id, name, display_name, reference, is_admin, is_live FROM v_user WHERE reference = ?" + return queryOneUser(stmt, reference) +} diff --git a/core/wish.go b/core/wish.go new file mode 100644 index 0000000..43befd1 --- /dev/null +++ b/core/wish.go @@ -0,0 +1,109 @@ +package lishwist + +import ( + "database/sql" + "errors" + "fmt" + "strings" + + "lishwist/core/internal/db" +) + +type Wish struct { + Id string + Name string + ClaimantId string `json:",omitempty"` + ClaimantName string `json:",omitempty"` + Sent bool + RecipientId string `json:",omitempty"` + RecipientName string `json:",omitempty"` + RecipientRef string `json:",omitempty"` + CreatorId string `json:",omitempty"` + CreatorName string `json:",omitempty"` +} + +func (s *Session) GetWishes() ([]Wish, error) { + stmt := "SELECT wish.id, wish.name, wish.sent FROM wish WHERE wish.creator_id = ?1 AND wish.recipient_id = ?1" + rows, err := db.Connection.Query(stmt, s.User.Id) + if err != nil { + return nil, fmt.Errorf("Query execution failed: %w", err) + } + defer rows.Close() + wishs := []Wish{} + for rows.Next() { + var id string + var name string + var sent bool + err = rows.Scan(&id, &name, &sent) + if err != nil { + return nil, fmt.Errorf("Failed to scan a row: %w", err) + } + wish := Wish{ + Id: id, + Name: name, + Sent: sent, + } + wishs = append(wishs, wish) + } + err = rows.Err() + if err != nil { + return nil, fmt.Errorf("Rows returned an error: %w", err) + } + return wishs, nil +} + +func (s *Session) MakeWish(name string) error { + stmt := "INSERT INTO wish (name, recipient_id, creator_id) VALUES (?, ?, ?)" + _, err := db.Connection.Exec(stmt, strings.TrimSpace(name), s.User.Id, s.User.Id) + if err != nil { + return fmt.Errorf("Query execution failed: %w", err) + } + return nil +} + +func (s *Session) GetOthersWishes(userReference string) ([]Wish, error) { + otherUser, err := getUserByReference(userReference) + if err != nil { + return nil, fmt.Errorf("Failed to get other user: %w", err) + } + if otherUser.Id == s.User.Id { + return nil, errors.New("Use (s *Session) GetWishes() to view your own wishes") + } + stmt := "SELECT gift.id, gift.name, claimant.id, claimant.name, gift.sent, gift.creator_id, creator.name, gift.recipient_id FROM gift JOIN v_user AS user ON gift.recipient_id = user.id LEFT JOIN v_user AS claimant ON gift.claimant_id = claimant.id LEFT JOIN v_user AS creator ON gift.creator_id = creator.id WHERE user.id = ?" + rows, err := db.Connection.Query(stmt, otherUser.Id) + if err != nil { + return nil, fmt.Errorf("Failed to execute query: %w", err) + } + defer rows.Close() + wishes := []Wish{} + for rows.Next() { + var id string + var name string + var claimantId sql.NullString + var claimantName sql.NullString + var sent bool + var creatorId string + var creatorName string + var recipientId string + err = rows.Scan(&id, &name, &claimantId, &claimantName, &sent, &creatorId, &creatorName, &recipientId) + if err != nil { + return nil, fmt.Errorf("Failed to scan a row: %w", err) + } + wish := Wish{ + Id: id, + Name: name, + ClaimantId: claimantId.String, + ClaimantName: claimantName.String, + Sent: sent, + CreatorId: creatorId, + CreatorName: creatorName, + RecipientId: recipientId, + } + wishes = append(wishes, wish) + } + err = rows.Err() + if err != nil { + return nil, fmt.Errorf("Rows returned an error: %w", err) + } + return wishes, nil +} diff --git a/core/wish_test.go b/core/wish_test.go new file mode 100644 index 0000000..b867b7f --- /dev/null +++ b/core/wish_test.go @@ -0,0 +1,28 @@ +package lishwist_test + +import ( + "testing" + + "lishwist/core/internal/fixtures" +) + +func TestMakeWish(t *testing.T) { + s := fixtures.Login("thomas", "123") + + if err := s.MakeWish("apple"); err != nil { + t.Fatalf("Failed to make wish 1: %s\n", err) + } + + if err := s.MakeWish(" A car "); err != nil { + t.Fatalf("Failed to make wish 2: %s\n", err) + } + + wishes, err := s.GetWishes() + if err != nil { + t.Fatalf("Failed to get wishes: %s\n", err) + } + + fixtures.AssertEq(t, "Number of wishes", 2, len(wishes)) + fixtures.AssertEq(t, "Wish 1 name", wishes[0].Name, "apple") + fixtures.AssertEq(t, "Wish 2 name", wishes[1].Name, "A car") +}