// chatnotify.go stores what each person hears from a repository's chat
// channel: only messages that name them (the default, and no row), every
// message, or nothing. Like chat_read it is forge-local, per-account
// social state, never part of a repository's history: wiping it puts
// everybody back on mentions, which is what they had before choosing.
package oltp
import (
"fmt"
"time"
)
// The three things a person can hear from a channel. ChatMentions is
// the default and is never stored: no row is mentions.
const (
ChatMentions = "mentions"
ChatEvery = "all"
ChatOff = "off"
)
const chatNotifySchema = `
CREATE TABLE IF NOT EXISTS chat_notify (
repo TEXT NOT NULL,
account TEXT NOT NULL,
mode TEXT NOT NULL, -- 'all' or 'off'; mentions is no row
at TEXT NOT NULL,
PRIMARY KEY (repo, account)
);
CREATE INDEX IF NOT EXISTS chat_notify_repo_mode ON chat_notify (repo, mode);`
// SetChatNotify records what account hears from repo's channel. Mentions
// removes the row, so the table holds only people who chose otherwise.
func (d *DB) SetChatNotify(repo, account, mode string) error {
if account == "" {
return Refusal{"sign in to choose what you hear from a channel"}
}
switch mode {
case ChatMentions:
_, err := d.w.Exec(`DELETE FROM chat_notify WHERE repo = ? AND account = ?`, repo, account)
return err
case ChatEvery, ChatOff:
_, err := d.w.Exec(`INSERT INTO chat_notify (repo, account, mode, at) VALUES (?, ?, ?, ?)
ON CONFLICT (repo, account) DO UPDATE SET mode = excluded.mode, at = excluded.at`,
repo, account, mode, time.Now().UTC().Format(time.RFC3339Nano))
return err
}
return Refusal{fmt.Sprintf("%q is not a choice: use mentions, all or off", mode)}
}
// ChatNotify answers what account hears from repo's channel: mentions
// when they never chose.
func (d *DB) ChatNotify(repo, account string) string {
if account == "" {
return ChatMentions
}
mode := ChatMentions
_ = d.db.QueryRow(`SELECT mode FROM chat_notify WHERE repo = ? AND account = ?`, repo, account).Scan(&mode)
return mode
}
// ChatNotifyEvery lists who hears every message in repo's channel.
func (d *DB) ChatNotifyEvery(repo string) ([]string, error) {
rows, err := d.db.Query(`SELECT account FROM chat_notify WHERE repo = ? AND mode = ? ORDER BY account`, repo, ChatEvery)
if err != nil {
return nil, err
}
defer rows.Close()
var out []string
for rows.Next() {
var a string
if err := rows.Scan(&a); err != nil {
return nil, err
}
out = append(out, a)
}
return out, rows.Err()
}