Artifact b797a67fc27b3df768b42f6cca91870377a09f898be42e8b7eeb665af09fbcf3:
- File
internal/oltp/praise.go
— part of check-in
[f1a6be9a77]
at
2026-08-24 19:59:53
on branch praise
— Praise: vocabulary, storage, ops
Any signed-in account may praise any repository it can SEE — no capability letter, because the read gate has already decided whether the repository exists for this caller and past that gate praising is not a privilege anyone needs granting.
Per account, not per contributor: someone who has never authored an artifact can still say a repository is worth attention, which is why this cannot hang off the contributor pages.
praise.list filters by the VIEWER, never the owner. Praise is public; the existence of a private repository is not, and this is where the two meet.
UI deferred: the button belongs in the repo stats strip, which is on the unlanded clone-counts branch. (user: dmestas, size: 2883) [annotate] [blame] [check-ins using] [more...]
// praise.go stores praise — the forge's "this is worth your attention" // signal. Forge-local state, never part of the DAG (0001 §8), for the // same reason forum votes are: a clone of the store must carry the work, // not the applause. package oltp import ( "errors" "time" ) const praiseSchema = ` CREATE TABLE IF NOT EXISTS praise ( repo TEXT NOT NULL, account TEXT NOT NULL, at TEXT NOT NULL, -- The key IS the idempotency, exactly as forum_vote's is: one row per -- account per repository. Praising twice is the same fact, and -- withdrawing is a delete rather than a second row saying no. PRIMARY KEY (repo, account) ); CREATE INDEX IF NOT EXISTS praise_by_account ON praise (account, at DESC);` // SetPraise records or withdraws one account's praise. Returns whether // the repository is praised by that account afterwards, so a caller can // name the event it raises without asking again. func (d *DB) SetPraise(repo, account string, on bool) (bool, error) { if repo == "" || account == "" { return false, errors.New("oltp: praise needs a repo and an account") } if !on { _, err := d.db.Exec(`DELETE FROM praise WHERE repo = ? AND account = ?`, repo, account) return false, err } // Insert-or-ignore, not upsert: re-praising must not move the date, // or a listing ordered by when you praised something would reshuffle // every time somebody double-clicked. _, err := d.db.Exec(`INSERT OR IGNORE INTO praise (repo, account, at) VALUES (?, ?, ?)`, repo, account, time.Now().UTC().Format(time.RFC3339)) return true, err } // Praised reports whether one account praises one repository. func (d *DB) Praised(repo, account string) bool { if account == "" { return false } var one int err := d.db.QueryRow(`SELECT 1 FROM praise WHERE repo = ? AND account = ?`, repo, account).Scan(&one) return err == nil } // PraiseCount is how many accounts praise a repository. func (d *DB) PraiseCount(repo string) int { var n int if err := d.db.QueryRow(`SELECT count(*) FROM praise WHERE repo = ?`, repo).Scan(&n); err != nil { return 0 } return n } // PraisedBy lists the repositories one account praises, newest first. // // It returns names only. Deciding which of them the VIEWER may see is // the caller's job and must not be skipped: praise is public, but a // private repository's existence is not, and the two meet here. An // account's own list and a stranger's view of it are different lists. func (d *DB) PraisedBy(account string) ([]string, error) { if account == "" { return nil, nil } rows, err := d.db.Query(`SELECT repo FROM praise WHERE account = ? ORDER BY at DESC`, account) if err != nil { return nil, err } defer rows.Close() var out []string for rows.Next() { var repo string if err := rows.Scan(&repo); err != nil { return nil, err } out = append(out, repo) } return out, rows.Err() }