From d666849759374953c65f3a3c04bac17b22a0b702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20Jovanovi=C4=87?= Date: Thu, 10 Sep 2026 11:52:32 +0200 Subject: [PATCH] add basis for multiple reps --- server.go | 2 ++ store.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/server.go b/server.go index ef3fadb..3d9f5fa 100644 --- a/server.go +++ b/server.go @@ -35,6 +35,8 @@ type Store interface { UpsertPeople(users []User, eligible map[string]bool) error LastSync() (int64, error) SetLastSync(ts int64) error + RepsFor(chapterID int64, dept string) ([]int64, error) + EligibleMembers(chapterID int64, dept string) ([]int64, error) } // ErrLocked is returned by AcquireLock when a run is already in flight diff --git a/store.go b/store.go index 8409b93..97bf811 100644 --- a/store.go +++ b/store.go @@ -57,6 +57,38 @@ func OpenStore(path string) (*SQLStore, error) { return &SQLStore{db: db}, nil } +// RepsFor returns the user IDs of every rep for a department, ordered by +// ID so assignment is deterministic across runs. +func (s *SQLStore) RepsFor(chapterID int64, dept string) ([]int64, error) { + return s.userIDs(`SELECT id FROM people + WHERE is_rep = 1 AND chapter_id = ? AND department = ? + ORDER BY id`, chapterID, dept) +} + +func (s *SQLStore) EligibleMembers(chapterID int64, dept string) ([]int64, error) { + return s.userIDs(`SELECT id FROM people + WHERE is_eligible = 1 AND chapter_id = ? AND department = ? + ORDER BY id`, chapterID, dept) +} + +func (s *SQLStore) userIDs(query string, args ...any) ([]int64, error) { + rows, err := s.db.Query(query, args...) + if err != nil { + return nil, err + } + defer rows.Close() + + var out []int64 + for rows.Next() { + var id int64 + if err := rows.Scan(&id); err != nil { + return nil, err + } + out = append(out, id) + } + return out, rows.Err() +} + func (s *SQLStore) AcquireLock(chapterID int64, dept string, repID int64) (int64, error) { res, err := s.db.Exec( `INSERT INTO runs (chapter_id, department, rep_user_id, status)