added IMAP, LetsEncrypt, update layout

This commit is contained in:
2026-08-12 21:14:19 +01:00
parent 6e103959b0
commit 70fa1a5f2c
222 changed files with 42947 additions and 14038 deletions
+31 -3
View File
@@ -20,7 +20,21 @@ type M map[string]any
func (a *App) funcMap() template.FuncMap {
return template.FuncMap{
"formatDatetime": func(t time.Time) string { return formatDatetimeInZone(t, a.Cfg) },
"strftime": func(layout string, t time.Time) string {
// strftime accepts either time.Time or *time.Time (nullable DB columns like
// MailboxAppPassword.LastUsedAt) so callers don't need a separate deref helper.
"strftime": func(layout string, v any) string {
var t time.Time
switch tv := v.(type) {
case time.Time:
t = tv
case *time.Time:
if tv == nil {
return ""
}
t = *tv
default:
return ""
}
if t.IsZero() {
return ""
}
@@ -109,16 +123,21 @@ func humanFileSize(size int64) string {
var pages = []string{
"dashboard.html", "domains.html", "add_domain.html", "edit_domain.html",
"senders.html", "add_sender.html", "edit_sender.html",
"mailboxes.html", "add_mailbox.html", "edit_mailbox.html", "mailbox_apppasswords.html", "mailbox_aliases.html",
"mailbox_lists.html", "mailbox_rules.html",
"ips.html", "add_ip.html", "edit_ip.html",
"dkim.html", "edit_dkim.html",
"settings.html", "logs.html", "view_message_content.html", "error.html",
"settings.html", "letsencrypt.html", "logs.html", "view_message_content.html", "error.html",
"account.html", "first_login.html", "totp_setup.html",
"admins.html", "add_admin.html", "edit_admin.html",
}
// standalonePages are pre-login screens — they intentionally don't use base.html's
// sidebar/dashboard chrome, since the visitor isn't authenticated yet.
var standalonePages = []string{"login.html", "login_mfa.html"}
var standalonePages = []string{
"login.html", "login_mfa.html",
"webmail_login.html", "webmail_login_mfa.html", "webmail_account.html", "webmail_totp_setup.html",
}
// loadTemplates parses from the embedded assets FS (see embed.go), not the
// filesystem — the binary carries its own templates, so it runs from any working
@@ -173,6 +192,15 @@ func (a *App) render(w http.ResponseWriter, r *http.Request, page string, data M
}
data["flashes"] = popFlashes(w, r)
data["health"] = a.checkHealth()
// Sidebar badge counts (Domains/Senders/Mailboxes/IPs/DKIM Keys) — computed here,
// centrally, so every authenticated page shows them, not just the dashboard (which
// used to compute these itself and nowhere else did).
counts := a.computeNavCounts(r)
data["domain_count"] = counts.DomainCount
data["sender_count"] = counts.SenderCount
data["mailbox_count"] = counts.MailboxCount
data["ip_count"] = counts.IPCount
data["dkim_count"] = counts.DKIMCount
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := t.ExecuteTemplate(w, "base.html", data); err != nil {
a.Logger.Error("template render error (%s): %v", page, err)