Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Summarize accounts, activity, and configuration on the Admin overview

0db980ee6b820127a0310be661b5d2c98fcdde92 · Keenan Nemetz · 4d ago · parent 43e681d8

Summarize accounts, activity, and configuration on the Admin overview

The overview is the whole admin surface at a glance now, so it repeats the
head of the other tabs: active people, bots, instance admins, and retired
accounts from the roster; the newest audit records with their detail and a
link into the log; and the configuration warnings, including a browser that
cannot sign anyone in.

Refs #198 (01M6MK0NNZ2XR1D5TQKNWYT4HN).

server/web/admin_audit.go +41−11

@@ -41,23 +41,31 @@ type auditPageView struct {
41 41 Err string
42 42 }
43 43
44 // adminOverviewAudit is how many recent records the overview shows before it
45 // hands the reader to the full log. It is a glance, not a second audit page.
46 const adminOverviewAudit = 6
47
48 // adminAuditSummary is the overview's short look at the log.
49 type adminAuditSummary struct {
50 Entries []auditEntryView
51 Err string
52 }
53
54 func (w *Web) auditPath() string {
55 if w.Cfg == nil {
56 return ""
57 }
58 return w.Cfg.AuditLog()
59 }
60
44 61 func (w *Web) auditView(r *http.Request) auditPageView {
45 62 v := auditPageView{Page: auditPageNumber(r.URL.Query().Get("page"))}
46 path := ""
47 if w.Cfg != nil {
48 path = w.Cfg.AuditLog()
49 }
50 entries, older, err := audit.Tail(path, (v.Page-1)*auditPerPage, auditPerPage)
63 entries, older, err := audit.Tail(w.auditPath(), (v.Page-1)*auditPerPage, auditPerPage)
51 64 if err != nil {
52 65 v.Err = err.Error()
53 66 return v
54 67 }
55 for _, e := range entries {
56 v.Entries = append(v.Entries, auditEntryView{
57 Time: e.Time, Action: e.Action, Actor: e.Actor,
58 Subject: e.Subject, Detail: e.Detail,
59 })
60 }
68 v.Entries = auditEntryViews(entries)
61 69 v.HasOlder = older
62 70 v.HasNewer = v.Page > 1
63 71 if v.HasNewer {
@@ -69,6 +77,28 @@ func (w *Web) auditView(r *http.Request) auditPageView {
69 77 return v
70 78 }
71 79
80 func (w *Web) recentAudit() adminAuditSummary {
81 var v adminAuditSummary
82 entries, _, err := audit.Tail(w.auditPath(), 0, adminOverviewAudit)
83 if err != nil {
84 v.Err = err.Error()
85 return v
86 }
87 v.Entries = auditEntryViews(entries)
88 return v
89 }
90
91 func auditEntryViews(entries []audit.Entry) []auditEntryView {
92 views := make([]auditEntryView, 0, len(entries))
93 for _, e := range entries {
94 views = append(views, auditEntryView{
95 Time: e.Time, Action: e.Action, Actor: e.Actor,
96 Subject: e.Subject, Detail: e.Detail,
97 })
98 }
99 return views
100 }
101
72 102 func auditPageNumber(raw string) int {
73 103 n, err := strconv.Atoi(raw)
74 104 if err != nil || n < 1 {