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()) abortWithError(w, err.Error())
return return
} }
// color, exists := fi.Room.WCMap[word]
color, exists := fi.Room.FindColor(word) color, exists := fi.Room.FindColor(word)
log.Debug("got mark-card request", "word", word, "color", color) log.Debug("got mark-card request", "word", word, "color", color)
if !exists { 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 // Check if the current user already has an active mark on this card
found := false found := false
var newMarks []models.CardMark var newMarks []models.CardMark
for _, mark := range card.Mark { for _, mark := range card.Marks {
if mark.Username == fi.State.Username && mark.Active { if mark.Username == fi.State.Username && mark.Active {
found = true found = true
} else { } else {
@ -234,7 +233,7 @@ func HandleMarkCard(w http.ResponseWriter, r *http.Request) {
Active: true, Active: true,
}) })
} }
fi.Room.Cards[i].Mark = newMarks fi.Room.Cards[i].Marks = newMarks
cardword = fi.Room.Cards[i] cardword = fi.Room.Cards[i]
} }
if err := saveFullInfo(r.Context(), fi); err != nil { 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) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sessionCookie, err := r.Cookie(models.AuthCookie) sessionCookie, err := r.Cookie(models.AuthCookie)
if err != nil { if err != nil {
msg := "auth failed; failed to get session token from cookies" // msg := "auth failed; failed to get session token from cookies"
log.Debug(msg, "error", err) // log.Debug(msg, "error", err)
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
return return
} }

View File

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

View File

@ -128,6 +128,7 @@ type BotPlayer struct {
type CardMark struct { type CardMark struct {
CardID uint32 `db:"card_id"` CardID uint32 `db:"card_id"`
Username string `db:"username"` Username string `db:"username"`
MarkType string `db:"mark_type"`
Active bool `db:"active"` Active bool `db:"active"`
} }
@ -151,9 +152,7 @@ type Room struct {
RedTeam Team `db:"-"` RedTeam Team `db:"-"`
BlueTeam Team `db:"-"` BlueTeam Team `db:"-"`
Cards []WordCard `db:"-"` Cards []WordCard `db:"-"`
// WCMap map[string]WordColor `db:"-"`
BotMap map[string]BotPlayer `db:"-"` BotMap map[string]BotPlayer `db:"-"`
Mark CardMark `db:"-"`
LogJournal []string `db:"-"` LogJournal []string `db:"-"`
Settings GameSettings `db:"-"` Settings GameSettings `db:"-"`
} }
@ -169,7 +168,7 @@ func (r *Room) FindColor(word string) (WordColor, bool) {
func (r *Room) ClearMarks() { func (r *Room) ClearMarks() {
for i, _ := range r.Cards { 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"` Color WordColor `json:"color" db:"color"`
Revealed bool `json:"revealed" db:"revealed"` Revealed bool `json:"revealed" db:"revealed"`
Mime bool `json:"mime" db:"mime_view"` // user who sees that card is mime 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 // 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 SessionsRepo
WordCardsRepo WordCardsRepo
SettingsRepo SettingsRepo
CardMarksRepo
InitTx(ctx context.Context) (context.Context, *sqlx.Tx, error) InitTx(ctx context.Context) (context.Context, *sqlx.Tx, error)
} }
@ -25,6 +26,7 @@ type RepoProvider struct {
DB *sqlx.DB DB *sqlx.DB
mu sync.RWMutex mu sync.RWMutex
pathToDB string pathToDB string
CardMarksRepo
} }
func NewRepoProvider(pathToDB string) *RepoProvider { func NewRepoProvider(pathToDB string) *RepoProvider {
@ -42,6 +44,7 @@ func NewRepoProvider(pathToDB string) *RepoProvider {
rp := &RepoProvider{ rp := &RepoProvider{
DB: db, DB: db,
pathToDB: pathToDB, pathToDB: pathToDB,
CardMarksRepo: NewCardMarksRepo(db),
} }
go rp.pingLoop() go rp.pingLoop()

View File

@ -7,8 +7,8 @@ import (
"time" "time"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/assert"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/assert"
) )
func setupTestDB(t *testing.T) (*sqlx.DB, func()) { func setupTestDB(t *testing.T) (*sqlx.DB, func()) {
@ -181,7 +181,7 @@ func TestRoomsRepo_GetRoomByID(t *testing.T) {
} }
// Insert a room directly into the database for testing GetRoomByID // 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) 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) assert.NoError(t, err)
@ -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) _, 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) 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) assert.NoError(t, err)
// Insert a word card for the room // 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) 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) assert.NoError(t, err)
room.TeamTurn = "red" room.TeamTurn = "red"
room.BlueCounter = 10 room.BlueCounter = 10
room.Settings.RoundTime = 120 room.Settings.RoundTime = 120
err = repo.RoomUpdate(context.Background(), room) err = repo.RoomUpdate(context.Background(), room)
assert.NoError(t, err) assert.NoError(t, err)
var updatedRoom models.Room var updatedRoom models.Room
err = db.Get(&updatedRoom, "SELECT * FROM rooms WHERE id = ?", room.ID) err = db.Get(&updatedRoom, "SELECT * FROM rooms WHERE id = ?", room.ID)
assert.NoError(t, err) assert.NoError(t, err)
@ -371,6 +369,6 @@ func TestRoomsRepo_UpdateRoom(t *testing.T) {
var updatedSettings models.GameSettings var updatedSettings models.GameSettings
err = db.Get(&updatedSettings, "SELECT * FROM settings WHERE room_id = ?", room.ID) err = db.Get(&updatedSettings, "SELECT * FROM settings WHERE room_id = ?", room.ID)
assert.NoError(t, err) 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; - 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; - sync writing to json cache; what happens now: timer (or other side routine) overwrites old room, while mime making clue;
----------------- -----------------
- instant timer over; - card marks;
- 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: