Move archive mailbox management to own menu
This commit is contained in:
parent
9a5fb89518
commit
fe3ece17ba
2 changed files with 87 additions and 16 deletions
|
|
@ -22,6 +22,7 @@ func RegisterRoutes(mux *http.ServeMux) {
|
|||
mux.HandleFunc("/accounts/save", accountSaveHandler) // TODO Codex
|
||||
mux.HandleFunc("/accounts/delete", accountDeleteHandler) // TODO Codex
|
||||
mux.HandleFunc("/accounts/test", accountTestHandler) // TODO Codex: Quelle+Ziel-Login pruefen
|
||||
mux.HandleFunc("/archives", archivesHandler)
|
||||
mux.HandleFunc("/archives/create", archiveCreateHandler)
|
||||
mux.HandleFunc("/archives/delete", archiveDeleteHandler)
|
||||
mux.HandleFunc("/migrate/run", migrateRunHandler) // TODO Codex: RunMigration im Hintergrund
|
||||
|
|
@ -54,9 +55,9 @@ func renderShell(w http.ResponseWriter, active, readingPane string) {
|
|||
fmt.Fprintf(w, `<!doctype html><html lang="de"><head><meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Mail-Graveyard</title>
|
||||
<link rel="stylesheet" href="/static/style.css?v=20260712-7">
|
||||
<link rel="stylesheet" href="/static/style.css?v=20260712-8">
|
||||
<script src="/static/htmx.min.js"></script>
|
||||
<script src="/static/app.js?v=20260712-7" defer></script></head>
|
||||
<script src="/static/app.js?v=20260712-8" defer></script></head>
|
||||
<body class="ol2013">
|
||||
<header class="ribbon">
|
||||
<button class="app-menu-button" type="button" aria-label="Mail-Graveyard-Menue" aria-expanded="false" data-backstage-toggle><span class="mail-logo" aria-hidden="true"></span></button>
|
||||
|
|
@ -73,6 +74,7 @@ func renderShell(w http.ResponseWriter, active, readingPane string) {
|
|||
<a class="backstage-item active" href="/view">Archiv-Boxen</a>
|
||||
<a class="backstage-item" href="/view">Import/Export</a>
|
||||
<a class="backstage-item" href="/accounts">Konten-Verwaltung</a>
|
||||
<a class="backstage-item sub" href="/archives">Archiv-mbox Verwaltung</a>
|
||||
<a class="backstage-item" href="/view">Mail-Transfer</a>
|
||||
<a class="backstage-item" href="/accounts">Einstellungen</a>
|
||||
</aside>
|
||||
|
|
@ -177,6 +179,15 @@ func accountTestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
redirectAccounts(w, r, name, "Quelle und Ziel erfolgreich getestet.")
|
||||
}
|
||||
|
||||
func archivesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
accounts, err := ListAccounts()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
renderArchivesPage(w, archiveMailboxes(accounts), accounts, r.URL.Query().Get("msg"), r.URL.Query().Get("err"))
|
||||
}
|
||||
|
||||
func archiveCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
|
|
@ -184,14 +195,14 @@ func archiveCreateHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
name, err := safeArchiveName(r.FormValue("archive_name"))
|
||||
if err != nil {
|
||||
redirectAccounts(w, r, "", err.Error())
|
||||
redirectArchives(w, r, err.Error())
|
||||
return
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Join(Cfg.MboxRoot, name), 0o700); err != nil {
|
||||
redirectAccounts(w, r, "", err.Error())
|
||||
redirectArchives(w, r, err.Error())
|
||||
return
|
||||
}
|
||||
redirectAccounts(w, r, "", "Archiv-Mailbox angelegt.")
|
||||
redirectArchives(w, r, "Archiv-Mailbox angelegt.")
|
||||
}
|
||||
|
||||
func archiveDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -201,32 +212,32 @@ func archiveDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
name, err := safeArchiveName(r.FormValue("archive_name"))
|
||||
if err != nil {
|
||||
redirectAccounts(w, r, "", err.Error())
|
||||
redirectArchives(w, r, err.Error())
|
||||
return
|
||||
}
|
||||
if archiveInUse(name) {
|
||||
redirectAccounts(w, r, "", "Archiv-Mailbox ist noch einem Postfach zugeordnet.")
|
||||
redirectArchives(w, r, "Archiv-Mailbox ist noch einem Postfach zugeordnet.")
|
||||
return
|
||||
}
|
||||
path := filepath.Join(Cfg.MboxRoot, name)
|
||||
entries, err := os.ReadDir(path)
|
||||
if os.IsNotExist(err) {
|
||||
redirectAccounts(w, r, "", "Archiv-Mailbox existiert nicht.")
|
||||
redirectArchives(w, r, "Archiv-Mailbox existiert nicht.")
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
redirectAccounts(w, r, "", err.Error())
|
||||
redirectArchives(w, r, err.Error())
|
||||
return
|
||||
}
|
||||
if len(entries) > 0 {
|
||||
redirectAccounts(w, r, "", "Archiv-Mailbox ist nicht leer und wurde nicht entfernt.")
|
||||
redirectArchives(w, r, "Archiv-Mailbox ist nicht leer und wurde nicht entfernt.")
|
||||
return
|
||||
}
|
||||
if err := os.Remove(path); err != nil {
|
||||
redirectAccounts(w, r, "", err.Error())
|
||||
redirectArchives(w, r, err.Error())
|
||||
return
|
||||
}
|
||||
redirectAccounts(w, r, "", "Leere Archiv-Mailbox entfernt.")
|
||||
redirectArchives(w, r, "Leere Archiv-Mailbox entfernt.")
|
||||
}
|
||||
|
||||
func migrateRunHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -284,9 +295,9 @@ func renderAccountsPage(w http.ResponseWriter, accounts []Account, edit Account,
|
|||
fmt.Fprintf(w, `<!doctype html><html lang="de"><head><meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Konten-Verwaltung - Mail-Graveyard</title>
|
||||
<link rel="stylesheet" href="/static/style.css?v=20260712-7">
|
||||
<link rel="stylesheet" href="/static/style.css?v=20260712-8">
|
||||
<script src="/static/htmx.min.js"></script>
|
||||
<script src="/static/app.js?v=20260712-7" defer></script></head>
|
||||
<script src="/static/app.js?v=20260712-8" defer></script></head>
|
||||
<body class="ol2013">
|
||||
<header class="ribbon">
|
||||
<button class="app-menu-button" type="button" aria-label="Mail-Graveyard-Menue" aria-expanded="false" data-backstage-toggle><span class="mail-logo" aria-hidden="true"></span></button>
|
||||
|
|
@ -303,6 +314,7 @@ func renderAccountsPage(w http.ResponseWriter, accounts []Account, edit Account,
|
|||
<a class="backstage-item" href="/view">Archiv-Boxen</a>
|
||||
<a class="backstage-item" href="/view">Import/Export</a>
|
||||
<a class="backstage-item active" href="/accounts">Konten-Verwaltung</a>
|
||||
<a class="backstage-item sub" href="/archives">Archiv-mbox Verwaltung</a>
|
||||
<a class="backstage-item" href="/view">Mail-Transfer</a>
|
||||
<a class="backstage-item" href="/accounts">Einstellungen</a>
|
||||
</aside>
|
||||
|
|
@ -316,13 +328,52 @@ func renderAccountsPage(w http.ResponseWriter, accounts []Account, edit Account,
|
|||
}
|
||||
fmt.Fprint(w, `<section class="account-layout"><div class="account-list"><div class="pane-head">Eingetragene Postfaecher</div>`)
|
||||
renderAccountsTable(w, accounts, edit.Name)
|
||||
fmt.Fprint(w, `<div class="pane-head">Archiv-mbox verwalten</div>`)
|
||||
renderArchiveManager(w, archives, accounts)
|
||||
fmt.Fprint(w, `</div><div class="account-form-panel"><div class="pane-head">Postfach eintragen</div>`)
|
||||
renderAccountForm(w, edit, archives)
|
||||
fmt.Fprint(w, `</div></section></main><footer class="statusbar"><span id="mig-status" hx-get="/migrate/status" hx-trigger="load,every 3s" hx-swap="innerHTML">bereit</span></footer></body></html>`)
|
||||
}
|
||||
|
||||
func renderArchivesPage(w http.ResponseWriter, archives []string, accounts []Account, msg, errMsg string) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
fmt.Fprintf(w, `<!doctype html><html lang="de"><head><meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Archiv-mbox Verwaltung - Mail-Graveyard</title>
|
||||
<link rel="stylesheet" href="/static/style.css?v=20260712-8">
|
||||
<script src="/static/htmx.min.js"></script>
|
||||
<script src="/static/app.js?v=20260712-8" defer></script></head>
|
||||
<body class="ol2013">
|
||||
<header class="ribbon">
|
||||
<button class="app-menu-button" type="button" aria-label="Mail-Graveyard-Menue" aria-expanded="false" data-backstage-toggle><span class="mail-logo" aria-hidden="true"></span></button>
|
||||
<nav class="ribbon-tabs">
|
||||
<a class="tab" href="/view">Archiv-Boxen</a>
|
||||
<a class="tab" href="/view">Import/Export</a>
|
||||
<a class="tab" href="/accounts">Konten-Verwaltung</a>
|
||||
<a class="tab" href="/view">Mail-Transfer</a>
|
||||
<a class="tab" href="/accounts">Einstellungen</a>
|
||||
</nav>
|
||||
<div class="ribbon-title">Mail-Graveyard</div>
|
||||
</header>
|
||||
<aside class="backstage-menu" aria-label="Mail-Graveyard-Menue">
|
||||
<a class="backstage-item" href="/view">Archiv-Boxen</a>
|
||||
<a class="backstage-item" href="/view">Import/Export</a>
|
||||
<a class="backstage-item" href="/accounts">Konten-Verwaltung</a>
|
||||
<a class="backstage-item sub active" href="/archives">Archiv-mbox Verwaltung</a>
|
||||
<a class="backstage-item" href="/view">Mail-Transfer</a>
|
||||
<a class="backstage-item" href="/accounts">Einstellungen</a>
|
||||
</aside>
|
||||
<button class="backstage-shade" type="button" aria-label="Menue schliessen" data-backstage-close></button>
|
||||
<main class="accounts-page archive-page">`)
|
||||
if msg != "" {
|
||||
fmt.Fprintf(w, `<div class="notice ok">%s</div>`, html.EscapeString(msg))
|
||||
}
|
||||
if errMsg != "" {
|
||||
fmt.Fprintf(w, `<div class="notice bad">%s</div>`, html.EscapeString(errMsg))
|
||||
}
|
||||
fmt.Fprint(w, `<section class="archive-page-layout"><div class="pane-head">Archiv-mbox Verwaltung</div>`)
|
||||
renderArchiveManager(w, archives, accounts)
|
||||
fmt.Fprint(w, `</section></main><footer class="statusbar"><span id="mig-status" hx-get="/migrate/status" hx-trigger="load,every 3s" hx-swap="innerHTML">bereit</span></footer></body></html>`)
|
||||
}
|
||||
|
||||
func renderAccountsTable(w http.ResponseWriter, accounts []Account, editName string) {
|
||||
if len(accounts) == 0 {
|
||||
fmt.Fprint(w, `<div class="ef-empty">Noch keine Postfaecher eingetragen.</div>`)
|
||||
|
|
@ -581,6 +632,14 @@ func redirectAccounts(w http.ResponseWriter, r *http.Request, edit, msg string)
|
|||
http.Redirect(w, r, target, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func redirectArchives(w http.ResponseWriter, r *http.Request, msg string) {
|
||||
key := "msg"
|
||||
if strings.Contains(strings.ToLower(msg), "fehl") || strings.Contains(strings.ToLower(msg), "ungueltig") || strings.Contains(strings.ToLower(msg), "nicht") || strings.Contains(strings.ToLower(msg), "error") {
|
||||
key = "err"
|
||||
}
|
||||
http.Redirect(w, r, "/archives?"+key+"="+urlQuery(msg), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func urlQuery(value string) string {
|
||||
return url.QueryEscape(value)
|
||||
}
|
||||
|
|
|
|||
12
frontend-js/dist/style.css
vendored
12
frontend-js/dist/style.css
vendored
|
|
@ -120,6 +120,10 @@ body.ol2013 {
|
|||
color: var(--ol-blue);
|
||||
border-left-color: #fff;
|
||||
}
|
||||
.backstage-item.sub {
|
||||
padding-left: 38px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.backstage-shade {
|
||||
position: fixed;
|
||||
inset: 44px 0 22px 0;
|
||||
|
|
@ -348,6 +352,14 @@ a.tree-node { display: block; color: inherit; text-decoration: none; }
|
|||
background: #fff;
|
||||
}
|
||||
.account-form-panel { border-right: 0; }
|
||||
.archive-page {
|
||||
background: #fff;
|
||||
}
|
||||
.archive-page-layout {
|
||||
max-width: 900px;
|
||||
min-height: 100%;
|
||||
border-right: 1px solid var(--ol-border);
|
||||
}
|
||||
.account-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue