119 lines
3.7 KiB
Go
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
|
|
}
|