Files
mailgoserver/internal/webui/logs.go
T
2026-08-12 12:56:22 +01:00

119 lines
3.7 KiB
Go

package webui
import (
"net/http"
"sort"
"time"
"mailgoserver/internal/db"
)
const perPage = 50
// logs mirrors logs.py's logs(): type=all|emails|auth, page (mostly cosmetic in "all"
// mode, matching the Python version's own quirk where "all" mode's pagination isn't
// real pagination — see the route inventory). Scoped admins get the fetched page
// filtered down to their domains in-memory (these tables have no domain_id column to
// filter in SQL — see accessibleDomainNames) — pagination counts stay based on the
// unfiltered page, same imprecision the "all" mode already had before scoping existed.
func (a *App) logs(w http.ResponseWriter, r *http.Request) {
allowedNames, isGlobal, err := a.accessibleDomainNames(r)
if err != nil {
setFlash(w, "error", "Error loading logs")
}
emailAllowed := func(e db.EmailLog) bool { return isGlobal || allowedNames[emailDomain(e.MailFrom)] }
authAllowed := func(au db.AuthLog) bool { return isGlobal || allowedNames[authLogDomain(au.Identifier)] }
filterType := r.URL.Query().Get("type")
if filterType == "" {
filterType = "all"
}
page := atoi(r.URL.Query().Get("page"))
if page < 1 {
page = 1
}
offset := (page - 1) * perPage
switch filterType {
case "emails":
fetched, err := a.DB.ListEmailLogsPage(offset, perPage)
if err != nil {
setFlash(w, "error", "Error loading logs")
}
var emails []db.EmailLog
for _, e := range fetched {
if emailAllowed(e) {
emails = append(emails, e)
}
}
recipientMap, attachMap := a.buildLogMaps(emails)
a.render(w, r, "logs.html", M{
"active": "logs", "logs": emails, "filter_type": filterType, "page": page,
"has_next": len(fetched) == perPage, "has_prev": page > 1,
"recipient_logs_map": recipientMap, "attachments_map": attachMap,
})
case "auth":
fetched, err := a.DB.ListAuthLogsPage(offset, perPage)
if err != nil {
setFlash(w, "error", "Error loading logs")
}
var auths []db.AuthLog
for _, au := range fetched {
if authAllowed(au) {
auths = append(auths, au)
}
}
a.render(w, r, "logs.html", M{
"active": "logs", "logs": auths, "filter_type": filterType, "page": page,
"has_next": len(fetched) == perPage, "has_prev": page > 1,
})
default:
half := perPage / 2
fetchedEmails, _ := a.DB.ListEmailLogsPage(0, half)
fetchedAuths, _ := a.DB.ListAuthLogsPage(0, half)
recipientMap, _ := a.buildLogMaps(fetchedEmails)
type combinedEntry struct {
M M
At time.Time
}
var combined []combinedEntry
for _, e := range fetchedEmails {
if !emailAllowed(e) {
continue
}
combined = append(combined, combinedEntry{M: M{"type": "email", "data": e, "recipients": recipientMap[e.ID]}, At: e.Timestamp})
}
for _, au := range fetchedAuths {
if !authAllowed(au) {
continue
}
combined = append(combined, combinedEntry{M: M{"type": "auth", "data": au}, At: au.CreatedAt})
}
sort.SliceStable(combined, func(i, j int) bool { return combined[i].At.After(combined[j].At) })
if len(combined) > perPage {
combined = combined[:perPage]
}
var logs []M
for _, c := range combined {
logs = append(logs, c.M)
}
a.render(w, r, "logs.html", M{
"active": "logs", "logs": logs, "filter_type": filterType, "page": page,
"has_next": len(logs) > perPage, "has_prev": page > 1,
})
}
}
func (a *App) buildLogMaps(emails []db.EmailLog) (map[int64][]db.EmailRecipientLog, map[int64][]db.EmailAttachment) {
recipientMap := map[int64][]db.EmailRecipientLog{}
attachMap := map[int64][]db.EmailAttachment{}
for _, e := range emails {
recs, _ := a.DB.ListRecipientLogsForEmail(e.ID)
recipientMap[e.ID] = recs
atts, _ := a.DB.ListAttachmentsForEmail(e.ID)
attachMap[e.ID] = atts
}
return recipientMap, attachMap
}