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