package web
import (
"strings"
"craftdesign.group/quarry/internal/oltp"
"craftdesign.group/quarry/internal/ops"
)
// checkedOutsideOps names the letters quarry acts on somewhere other
// than an operation's Caps, and what they do there. The registry alone
// would show every one of these as doing nothing.
// TestEveryCheckedLetterIsInTheReference holds this table to the source.
var checkedOutsideOps = map[rune]string{
'g': "any of g j o h 2 r lets someone reach the repository at all",
'j': "any of g j o h 2 r lets someone reach the repository at all",
'o': "any of g j o h 2 r lets someone reach the repository at all",
'h': "any of g j o h 2 r lets someone reach the repository at all",
'2': "any of g j o h 2 r lets someone reach the repository at all",
'r': "any of g j o h 2 r lets someone reach the repository at all",
'e': "shows email addresses and private ticket fields",
'C': "chat, on a forge with chat turned on",
'4': "forum posts skip moderation",
'5': "forum posts skip moderation",
'8': "shows the CI tab",
'u': "pulls in the reader category",
'v': "pulls in the developer category",
}
// capRefRow is one letter of the capability reference.
type capRefRow struct {
Letter string
Name string // fossil's name
Does string // fossil's description
Here []string
Ops int // operations that require it, in the live registry
Also string // where it is checked outside the operations
Used bool
Roles []string
Grants []string
}
// capRefPanel is the capability reference: every fossil letter, what it
// does in quarry, and who the page's scope hands it to.
type capRefPanel struct {
GrantsHead string
Rows []capRefRow
}
// capReference builds the reference from the live registry, so an
// operation registered only on some forges (chat, CI) counts only there.
func capReference(r *ops.Registry, grantsHead string, grants func(rune) []string) *capRefPanel {
required := map[rune]int{}
if r != nil {
for _, d := range r.All() {
seen := map[rune]bool{}
for _, l := range d.Caps {
if !seen[l] {
seen[l] = true
required[l]++
}
}
}
}
p := &capRefPanel{GrantsHead: grantsHead}
for _, c := range oltp.CapLetters {
row := capRefRow{Letter: string(c.Letter), Name: c.Name, Does: c.Does,
Ops: required[c.Letter], Also: checkedOutsideOps[c.Letter]}
for _, a := range oltp.Abilities {
if strings.ContainsRune(a.Letters, c.Letter) {
row.Here = append(row.Here, a.Sentence)
}
}
row.Used = row.Ops > 0 || row.Also != ""
row.Roles = rolesWith(c.Letter)
if grants != nil {
row.Grants = grants(c.Letter)
}
p.Rows = append(p.Rows, row)
}
return p
}
// rolesWith names the stock roles that hold letter once implications
// and the a umbrella are applied — Admin holds nearly everything.
func rolesWith(letter rune) []string {
var out []string
for _, p := range oltp.Presets {
if oltp.CapSet(oltp.Closure(p.Caps)).HasAny(string(letter)) {
out = append(out, p.Name)
}
}
return out
}
// capRefFor is the reference for a repository's settings, or the fleet
// default when repo is empty: who its categories hand each letter to.
func capRefFor(r *ops.Registry, caps Caps, repo string) *capRefPanel {
head := "this repository gives it to"
if repo == "" {
head = "new repositories give it to"
}
admin, ok := caps.(CapsAdmin)
if !ok || admin == nil {
return capReference(r, head, nil)
}
cats := []string{oltp.SourceNobody, oltp.SourceAnonymous, oltp.SourceReader, oltp.SourceDeveloper}
strs := map[string]oltp.CapSet{}
for _, cat := range cats {
strs[cat] = oltp.CapSet(oltp.Closure(admin.CategoryCaps(repo, cat)))
}
return capReference(r, head, func(l rune) []string {
var out []string
for _, cat := range cats {
if strs[cat].HasAny(string(l)) {
out = append(out, sourceWords(cat))
}
}
return out
})
}
// capRefTeam is the reference for a team: what membership alone gives
// on every repository the team holds.
func capRefTeam(r *ops.Registry) *capRefPanel {
floor := oltp.CapSet(oltp.Closure(oltp.TeamFloor))
return capReference(r, "membership gives it to", func(l rune) []string {
if floor.HasAny(string(l)) {
return []string{"every member"}
}
return nil
})
}