Skip to content
quarry Artifact [00e17fa4af]
Login

Artifact [00e17fa4af]

Artifact 00e17fa4af5e20a029fb65980ef5ca9d4e59e52649fda40c19c9bdfc47564f83:


// 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()
}