diff --git a/backend/00-router.go b/backend/00-router.go index 0c6c018..12b4c14 100644 --- a/backend/00-router.go +++ b/backend/00-router.go @@ -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, ` Mail-Graveyard - + - +
@@ -73,6 +74,7 @@ func renderShell(w http.ResponseWriter, active, readingPane string) { Archiv-Boxen Import/Export Konten-Verwaltung + Archiv-mbox Verwaltung Mail-Transfer Einstellungen @@ -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, ` Konten-Verwaltung - Mail-Graveyard - + - +
@@ -303,6 +314,7 @@ func renderAccountsPage(w http.ResponseWriter, accounts []Account, edit Account, Archiv-Boxen Import/Export Konten-Verwaltung + Archiv-mbox Verwaltung Mail-Transfer Einstellungen @@ -316,13 +328,52 @@ func renderAccountsPage(w http.ResponseWriter, accounts []Account, edit Account, } fmt.Fprint(w, `
bereit
`) } +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, ` + +Archiv-mbox Verwaltung - Mail-Graveyard + + + + +
+ + +
Mail-Graveyard
+
+ + +
`) + if msg != "" { + fmt.Fprintf(w, `
%s
`, html.EscapeString(msg)) + } + if errMsg != "" { + fmt.Fprintf(w, `
%s
`, html.EscapeString(errMsg)) + } + fmt.Fprint(w, `
Archiv-mbox Verwaltung
`) + renderArchiveManager(w, archives, accounts) + fmt.Fprint(w, `
bereit
`) +} + func renderAccountsTable(w http.ResponseWriter, accounts []Account, editName string) { if len(accounts) == 0 { fmt.Fprint(w, `
Noch keine Postfaecher eingetragen.
`) @@ -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) } diff --git a/frontend-js/dist/style.css b/frontend-js/dist/style.css index 30fde03..ef3e12c 100644 --- a/frontend-js/dist/style.css +++ b/frontend-js/dist/style.css @@ -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;