Feat: card_mark repo

This commit is contained in:
Grail Finder
2025-07-05 09:14:45 +03:00
parent 56845e6141
commit 413edae4b6
8 changed files with 70 additions and 35 deletions

View File

@ -201,7 +201,6 @@ func HandleMarkCard(w http.ResponseWriter, r *http.Request) {
abortWithError(w, err.Error())
return
}
// color, exists := fi.Room.WCMap[word]
color, exists := fi.Room.FindColor(word)
log.Debug("got mark-card request", "word", word, "color", color)
if !exists {
@ -221,7 +220,7 @@ func HandleMarkCard(w http.ResponseWriter, r *http.Request) {
// Check if the current user already has an active mark on this card
found := false
var newMarks []models.CardMark
for _, mark := range card.Mark {
for _, mark := range card.Marks {
if mark.Username == fi.State.Username && mark.Active {
found = true
} else {
@ -234,7 +233,7 @@ func HandleMarkCard(w http.ResponseWriter, r *http.Request) {
Active: true,
})
}
fi.Room.Cards[i].Mark = newMarks
fi.Room.Cards[i].Marks = newMarks
cardword = fi.Room.Cards[i]
}
if err := saveFullInfo(r.Context(), fi); err != nil {

View File

@ -28,8 +28,8 @@ func GetSession(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sessionCookie, err := r.Cookie(models.AuthCookie)
if err != nil {
msg := "auth failed; failed to get session token from cookies"
log.Debug(msg, "error", err)
// msg := "auth failed; failed to get session token from cookies"
// log.Debug(msg, "error", err)
next.ServeHTTP(w, r)
return
}

View File

@ -23,10 +23,10 @@ func init() {
func ListenToRequests(port string) *http.Server {
mux := http.NewServeMux()
server := &http.Server{
Handler: handlers.LogRequests(handlers.GetSession(mux)),
Addr: ":" + port,
ReadTimeout: time.Second * 5, // TODO: to cfg
WriteTimeout: 0, // sse streaming
Handler: handlers.LogRequests(handlers.GetSession(mux)),
Addr: ":" + port,
// ReadTimeout: time.Second * 5, // does this timeout conflict with sse connection?
WriteTimeout: 0, // sse streaming
}
fs := http.FileServer(http.Dir("assets/"))
mux.Handle("GET /assets/", http.StripPrefix("/assets/", fs))

View File

@ -128,6 +128,7 @@ type BotPlayer struct {
type CardMark struct {
CardID uint32 `db:"card_id"`
Username string `db:"username"`
MarkType string `db:"mark_type"`
Active bool `db:"active"`
}
@ -147,15 +148,13 @@ type Room struct {
TeamWon UserTeam `db:"team_won"`
RoomLink string `db:"room_link"`
// fields not in db
ActionHistory []Action `db:"-"`
RedTeam Team `db:"-"`
BlueTeam Team `db:"-"`
Cards []WordCard `db:"-"`
// WCMap map[string]WordColor `db:"-"`
BotMap map[string]BotPlayer `db:"-"`
Mark CardMark `db:"-"`
LogJournal []string `db:"-"`
Settings GameSettings `db:"-"`
ActionHistory []Action `db:"-"`
RedTeam Team `db:"-"`
BlueTeam Team `db:"-"`
Cards []WordCard `db:"-"`
BotMap map[string]BotPlayer `db:"-"`
LogJournal []string `db:"-"`
Settings GameSettings `db:"-"`
}
func (r *Room) FindColor(word string) (WordColor, bool) {
@ -169,7 +168,7 @@ func (r *Room) FindColor(word string) (WordColor, bool) {
func (r *Room) ClearMarks() {
for i, _ := range r.Cards {
r.Cards[i].Mark = []CardMark{}
r.Cards[i].Marks = []CardMark{}
}
}
@ -393,7 +392,7 @@ type WordCard struct {
Color WordColor `json:"color" db:"color"`
Revealed bool `json:"revealed" db:"revealed"`
Mime bool `json:"mime" db:"mime_view"` // user who sees that card is mime
Mark []CardMark `json:"marks" db:"-"`
Marks []CardMark `json:"marks" db:"-"`
}
// table: settings

39
repos/card_marks.go Normal file
View File

@ -0,0 +1,39 @@
package repos
import (
"context"
"gralias/models"
"github.com/jmoiron/sqlx"
)
type CardMarksRepo interface {
CardMarksByCardID(ctx context.Context, cardID string) ([]models.CardMark, error)
CardMarksAdd(ctx context.Context, cm *models.CardMark) error
CardMarksRemove(ctx context.Context, cardID, username string) error
}
type cardMarksRepo struct {
db *sqlx.DB
}
func NewCardMarksRepo(db *sqlx.DB) CardMarksRepo {
return &cardMarksRepo{db: db}
}
func (r *cardMarksRepo) CardMarksByCardID(ctx context.Context, cardID string) ([]models.CardMark, error) {
var cardMarks []models.CardMark
err := sqlx.SelectContext(ctx, getDB(ctx, r.db), &cardMarks, "SELECT * FROM card_marks WHERE card_id = ?", cardID)
return cardMarks, err
}
func (r *cardMarksRepo) CardMarksAdd(ctx context.Context, cm *models.CardMark) error {
_, err := getDB(ctx, r.db).ExecContext(ctx, "INSERT INTO card_marks (card_id, username, mark_type) VALUES (?, ?, ?)", cm.CardID, cm.Username, cm.MarkType)
return err
}
func (r *cardMarksRepo) CardMarksRemove(ctx context.Context, cardID, username string) error {
db := getDB(ctx, r.db)
_, err := db.ExecContext(ctx, "DELETE FROM card_marks WHERE card_id = ? AND username = ?", cardID, username)
return err
}

View File

@ -18,6 +18,7 @@ type AllRepos interface {
SessionsRepo
WordCardsRepo
SettingsRepo
CardMarksRepo
InitTx(ctx context.Context) (context.Context, *sqlx.Tx, error)
}
@ -25,6 +26,7 @@ type RepoProvider struct {
DB *sqlx.DB
mu sync.RWMutex
pathToDB string
CardMarksRepo
}
func NewRepoProvider(pathToDB string) *RepoProvider {
@ -42,6 +44,7 @@ func NewRepoProvider(pathToDB string) *RepoProvider {
rp := &RepoProvider{
DB: db,
pathToDB: pathToDB,
CardMarksRepo: NewCardMarksRepo(db),
}
go rp.pingLoop()

View File

@ -7,8 +7,8 @@ import (
"time"
"github.com/jmoiron/sqlx"
"github.com/stretchr/testify/assert"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/assert"
)
func setupTestDB(t *testing.T) (*sqlx.DB, func()) {
@ -181,9 +181,9 @@ func TestRoomsRepo_GetRoomByID(t *testing.T) {
}
// Insert a room directly into the database for testing GetRoomByID
_, err = db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_running, is_over, team_won, room_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room.ID, room.CreatedAt, room.CreatorName, room.TeamTurn, room.ThisTurnLimit, room.OpenedThisTurn, room.BlueCounter, room.RedCounter, room.RedTurn, room.MimeDone, room.IsRunning, room.IsOver, room.TeamWon, room.RoomLink)
_, err := db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_running, is_over, team_won, room_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room.ID, room.CreatedAt, room.CreatorName, room.TeamTurn, room.ThisTurnLimit, room.OpenedThisTurn, room.BlueCounter, room.RedCounter, room.RedTurn, room.MimeDone, room.IsRunning, room.IsOver, room.TeamWon, room.RoomLink)
assert.NoError(t, err)
_, err = db.Exec(`INSERT INTO settings (room_id, language, room_pass, turn_time) VALUES (?, ?, ?, ?)`, room.ID, room.Settings.Language, room.Settings.RoomPass, room.Settings.RoundTime)
_, err = db.Exec(`INSERT INTO settings (room_id, language, room_pass, turn_time) VALUES (?, ?, ?, ?)`, room.ID, room.Settings.Language, room.Settings.RoomPass, room.Settings.RoundTime)
assert.NoError(t, err)
retrievedRoom, err := repo.RoomGetByID(context.Background(), room.ID)
@ -288,7 +288,7 @@ func TestRoomsRepo_DeleteRoomByID(t *testing.T) {
_, err := db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_running, is_over, team_won, room_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room.ID, room.CreatedAt, room.CreatorName, room.TeamTurn, room.ThisTurnLimit, room.OpenedThisTurn, room.BlueCounter, room.RedCounter, room.RedTurn, room.MimeDone, room.IsRunning, room.IsOver, room.TeamWon, room.RoomLink)
assert.NoError(t, err)
_, err = db.Exec(`INSERT INTO settings (room_id, language, room_pass, turn_time) VALUES (?, ?, ?, ?, ?)`, room.ID, room.Settings.Language, room.Settings.RoomPass, room.Settings.RoundTime, room.Settings.TurnSecondsLeft)
_, err = db.Exec(`INSERT INTO settings (room_id, language, room_pass, turn_time) VALUES (?, ?, ?, ?)`, room.ID, room.Settings.Language, room.Settings.RoomPass, room.Settings.RoundTime)
assert.NoError(t, err)
// Insert a word card for the room
@ -347,21 +347,19 @@ func TestRoomsRepo_UpdateRoom(t *testing.T) {
},
}
_, err := db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_running, is_over, team_won, room_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room.ID, room.CreatedAt, room.CreatorName, room.TeamTurn, room.ThisTurnLimit, room.OpenedThisTurn, room.BlueCounter, room.RedCounter, room.RedTurn, room.MimeDone, room.IsRunning, room.IsOver, room.TeamWon, room.RoomLink)
var err error
_, err = db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_running, is_over, team_won, room_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room.ID, room.CreatedAt, room.CreatorName, room.TeamTurn, room.ThisTurnLimit, room.OpenedThisTurn, room.BlueCounter, room.RedCounter, room.RedTurn, room.MimeDone, room.IsRunning, room.IsOver, room.TeamWon, room.RoomLink)
assert.NoError(t, err)
_, err = db.Exec(`INSERT INTO settings (room_id, language, room_pass, turn_time) VALUES (?, ?, ?, ?, ?)`, room.ID, room.Settings.Language, room.Settings.RoomPass, room.Settings.RoundTime, room.Settings.TurnSecondsLeft)
_, err = db.Exec(`INSERT INTO settings (room_id, language, room_pass, turn_time) VALUES (?, ?, ?, ?)`, room.ID, room.Settings.Language, room.Settings.RoomPass, room.Settings.RoundTime)
assert.NoError(t, err)
room.TeamTurn = "red"
room.BlueCounter = 10
room.Settings.RoundTime = 120
err = repo.RoomUpdate(context.Background(), room)
assert.NoError(t, err)
var updatedRoom models.Room
err = db.Get(&updatedRoom, "SELECT * FROM rooms WHERE id = ?", room.ID)
assert.NoError(t, err)
@ -371,6 +369,6 @@ func TestRoomsRepo_UpdateRoom(t *testing.T) {
var updatedSettings models.GameSettings
err = db.Get(&updatedSettings, "SELECT * FROM settings WHERE room_id = ?", room.ID)
assert.NoError(t, err)
assert.Equal(t, uint32(120), updatedSettings.RoundTime)
assert.Equal(t, uint32(30), updatedSettings.TurnSecondsLeft)
}

View File

@ -68,7 +68,4 @@
- bot ends a turn after guessing one word only;
- sync writing to json cache; what happens now: timer (or other side routine) overwrites old room, while mime making clue;
-----------------
- instant timer over;
- bot does not react;
{"time":"2025-07-04T16:01:57.755750352+03:00","level":"INFO","source":{"function":"gralias/handlers.StartTurnTimer.func1","file":"/home/grail/projects/web/gralias/handlers/timer.go","line":43},"msg":"turn time is over","room_id":"d1jt16sg3nfp9p4thgl0"}
looking for bot to move team-turn: red mime-done: false bot-map: map[] is_running: true blueMime: redMime:
- card marks;