Skip to content
quarry Artifact [edf9a7e615]
Login

Artifact [edf9a7e615]

Artifact edf9a7e6151167e960b481b9f36d2c233291055a3650c62178bea7486dbcba89:


package oltp

import "time"

// forgeActSchema records what the forge's operator did to a repository
// somebody else holds.
//
// The ownership model says the operator administers the forge and not
// the repositories under it. That is not enforced -- a site admin holds
// the setup letter, which answers yes to every capability check, so
// they can still reach anything. This table is the other half of the
// promise and the one that can be kept today: the power stays, and it
// stops being invisible to the person whose repository it was used on.
//
// Only acts on somebody ELSE's repository are here. An owner acting on
// their own is not being watched, and an operator acting on a store
// nobody holds is administering the forge, which is their job.
const forgeActSchema = `
CREATE TABLE IF NOT EXISTS forge_act (
	at    TEXT NOT NULL,
	actor TEXT NOT NULL,   -- the operator, as the session named them
	op    TEXT NOT NULL,   -- the op, by name
	repo  TEXT NOT NULL,
	owner TEXT NOT NULL    -- who held it AT THE TIME, which can change later
);
CREATE INDEX IF NOT EXISTS forge_act_by_repo ON forge_act (repo, at DESC);`

// ForgeAct is one operator action on a repository somebody else holds.
type ForgeAct struct {
	At    string `json:"at"`
	Actor string `json:"actor"`
	Op    string `json:"op"`
	Repo  string `json:"repo"`
	Owner string `json:"owner"`
}

// RecordForgeAct writes the receipt. Failure to write one must never
// fail the act it describes: a forge that refuses to work because it
// cannot journal is worse than one whose journal has a hole, and the
// hole is visible in the log.
func (d *DB) RecordForgeAct(actor, op, repo, owner string) error {
	_, err := d.db.Exec(
		`INSERT INTO forge_act (at, actor, op, repo, owner) VALUES (?, ?, ?, ?, ?)`,
		time.Now().UTC().Format(time.RFC3339), actor, op, repo, owner)
	return err
}

// ForgeActs is what was done to one repository, newest first.
func (d *DB) ForgeActs(repo string, limit int) ([]ForgeAct, error) {
	if limit <= 0 || limit > 500 {
		limit = 100
	}
	rows, err := d.db.Query(
		`SELECT at, actor, op, repo, owner FROM forge_act WHERE repo = ? ORDER BY at DESC, rowid DESC LIMIT ?`,
		repo, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var out []ForgeAct
	for rows.Next() {
		var a ForgeAct
		if err := rows.Scan(&a.At, &a.Actor, &a.Op, &a.Repo, &a.Owner); err != nil {
			return nil, err
		}
		out = append(out, a)
	}
	return out, rows.Err()
}