package web import ( "encoding/json" "fmt" "os" "strings" ) // Site holds display settings SimpleAdmin has no place for: rank labels, colours and the plain // descriptions on the public staff page. Ranks are keyed by SimpleAdmin group name. type Site struct { Title string `json:"title"` Ranks map[string]Rank `json:"ranks"` } type Rank struct { Label string `json:"label"` Color string `json:"color"` About string `json:"about"` // Supporter ranks (VIPs) are listed apart from staff and don't count as staff online. Supporter bool `json:"supporter"` } func defaultSite() Site { return Site{ Title: "zio.sh", Ranks: map[string]Rank{ "#rank/owner": {Label: "Owner", Color: "#fe113d", About: "Runs the server."}, "#rank/senioradmin": {Label: "Senior admin", Color: "#ff7a45", About: "Manages the staff team and server settings."}, "#rank/admin": {Label: "Admin", Color: "#f0a63a", About: "Handles appeals and longer bans."}, "#rank/trialadmin": {Label: "Trial admin", Color: "#e8d25a", About: "Admins on trial."}, "#rank/mod": {Label: "Moderator", Color: "#37c58f", About: "Keeps matches fair. Can kick, gag and issue short bans."}, "#rank/trialmod": {Label: "Trial mod", Color: "#4fb3d9", About: "Moderators on trial."}, "#rank/helper": {Label: "Helper", Color: "#7c8cf5", About: "Answers questions and handles chat."}, "#rank/guardian": {Label: "Guardian", Color: "#c77dff", About: "Supporters of the server. Not staff, and can't punish anyone.", Supporter: true}, }, } } func loadSite(path string) (Site, error) { s := defaultSite() if path == "" { return s, nil } data, err := os.ReadFile(path) if err != nil { return s, err } var file Site if err := json.Unmarshal(data, &file); err != nil { return s, fmt.Errorf("%s: %w", path, err) } if file.Title != "" { s.Title = file.Title } if file.Ranks != nil { s.Ranks = file.Ranks } return s, nil } var fallbackColors = []string{"#7c8cf5", "#4fb3d9", "#37c58f", "#e8d25a", "#f0a63a", "#ff7a45", "#c77dff"} // rank returns display settings for a group, deriving a label ("#rank/mod" -> "Mod") and a colour // for groups the site config doesn't list. func (s Site) rank(group string, index int) Rank { if r, ok := s.Ranks[group]; ok { if r.Label == "" { r.Label = defaultLabel(group) } if r.Color == "" { r.Color = fallbackColors[index%len(fallbackColors)] } return r } return Rank{Label: defaultLabel(group), Color: fallbackColors[index%len(fallbackColors)]} } func defaultLabel(group string) string { name := strings.TrimPrefix(group, "#") if i := strings.LastIndex(name, "/"); i >= 0 { name = name[i+1:] } if name == "" { return group } return strings.ToUpper(name[:1]) + name[1:] }