From cfc0d34a584254a9ed76620951c810771aff6f3b Mon Sep 17 00:00:00 2001 From: Alexander Hunt Date: Sun, 21 Jun 2026 12:43:31 -0700 Subject: STUFF --- database/users.go | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'database/users.go') diff --git a/database/users.go b/database/users.go index 169cce1..164a631 100644 --- a/database/users.go +++ b/database/users.go @@ -99,3 +99,44 @@ func AssociateMAC(db *sql.DB, mac, userID string) error { mac, userID, now, now) return err } + +// MACBelongsToUser reports whether a MAC is currently bound to the given user. +func MACBelongsToUser(db *sql.DB, mac, userID string) (bool, error) { + var owner string + err := db.QueryRow("SELECT user_id FROM macs WHERE mac = ?", mac).Scan(&owner) + if errors.Is(err, sql.ErrNoRows) { + return false, nil + } + if err != nil { + return false, err + } + return owner == userID, nil +} + +// SetUserPrimaryMAC sets the user's primary device (the MAC its +// . name points at). +func SetUserPrimaryMAC(db *sql.DB, userID, mac string) error { + _, err := db.Exec("UPDATE users SET primary_mac = ? WHERE id = ?", mac, userID) + return err +} + +// SetPrimaryMACIfUnset atomically makes mac the primary device only when the +// user has none yet. The conditional WHERE makes "first device wins" race-free: +// concurrent associations can't both win, and there's no read-then-write gap. +func SetPrimaryMACIfUnset(db *sql.DB, userID, mac string) error { + _, err := db.Exec("UPDATE users SET primary_mac = ? WHERE id = ? AND primary_mac IS NULL", mac, userID) + return err +} + +// GetUserPrimaryMAC returns the user's primary MAC, or "" if unset. +func GetUserPrimaryMAC(db *sql.DB, userID string) (string, error) { + var mac sql.NullString + err := db.QueryRow("SELECT primary_mac FROM users WHERE id = ?", userID).Scan(&mac) + if errors.Is(err, sql.ErrNoRows) { + return "", ErrNotFound + } + if err != nil { + return "", err + } + return mac.String, nil +} -- cgit v1.3