diff --git a/plugins/base/routes.go b/plugins/base/routes.go index 61d92a6..8c230a4 100644 --- a/plugins/base/routes.go +++ b/plugins/base/routes.go @@ -80,6 +80,7 @@ type IMAPBaseRenderData struct { Mailboxes []MailboxInfo Mailbox *MailboxStatus Inbox *MailboxStatus + Subscriptions map[string]*MailboxStatus } type MailboxRenderData struct { @@ -89,17 +90,22 @@ type MailboxRenderData struct { Query string } +type MailboxDetails struct { + Info *MailboxInfo + Status *MailboxStatus +} + // Organizes mailboxes into common/uncommon categories type CategorizedMailboxes struct { Common struct { - Inbox *MailboxInfo - Drafts *MailboxInfo - Sent *MailboxInfo - Junk *MailboxInfo - Trash *MailboxInfo - Archive *MailboxInfo + Inbox MailboxDetails + Drafts MailboxDetails + Sent MailboxDetails + Junk MailboxDetails + Trash MailboxDetails + Archive MailboxDetails } - Additional []*MailboxInfo + Additional []MailboxDetails } func newIMAPBaseRenderData(ctx *alps.Context, @@ -110,6 +116,12 @@ func newIMAPBaseRenderData(ctx *alps.Context, return nil, echo.NewHTTPError(http.StatusBadRequest, err) } + settings, err := loadSettings(ctx.Session.Store()) + if err != nil { + return nil, fmt.Errorf("failed to load settings: %v", err) + } + + subscriptions := make(map[string]*MailboxStatus) var mailboxes []MailboxInfo var active, inbox *MailboxStatus err = ctx.Session.DoIMAP(func(c *imapclient.Client) error { @@ -117,11 +129,13 @@ func newIMAPBaseRenderData(ctx *alps.Context, if mailboxes, err = listMailboxes(c); err != nil { return err } + if mboxName != "" { if active, err = getMailboxStatus(c, mboxName); err != nil { return echo.NewHTTPError(http.StatusNotFound, err) } } + if mboxName == "INBOX" { inbox = active } else { @@ -129,6 +143,14 @@ func newIMAPBaseRenderData(ctx *alps.Context, return err } } + + for _, sub := range settings.Subscriptions { + if status, err := getMailboxStatus(c, sub); err != nil { + return err + } else { + subscriptions[sub] = status + } + } return nil }) if err != nil { @@ -136,7 +158,7 @@ func newIMAPBaseRenderData(ctx *alps.Context, } var categorized CategorizedMailboxes - mmap := map[string]**MailboxInfo{ + mmap := map[string]*MailboxDetails{ "INBOX": &categorized.Common.Inbox, "Drafts": &categorized.Common.Drafts, "Sent": &categorized.Common.Sent, @@ -157,11 +179,16 @@ func newIMAPBaseRenderData(ctx *alps.Context, mailboxes[i].Total = int(inbox.Messages) } + status, _ := subscriptions[mailboxes[i].Name] if ptr, ok := mmap[mailboxes[i].Name]; ok { - *ptr = &mailboxes[i] + ptr.Info = &mailboxes[i] + ptr.Status = status } else { - categorized.Additional = append( - categorized.Additional, &mailboxes[i]) + categorized.Additional = append(categorized.Additional, + MailboxDetails{ + Info: &mailboxes[i], + Status: status, + }) } } @@ -171,6 +198,7 @@ func newIMAPBaseRenderData(ctx *alps.Context, Mailboxes: mailboxes, Inbox: inbox, Mailbox: active, + Subscriptions: subscriptions, }, nil } @@ -1156,6 +1184,7 @@ type Settings struct { MessagesPerPage int Signature string From string + Subscriptions []string } func loadSettings(s alps.Store) (*Settings, error) { @@ -1186,7 +1215,20 @@ func (s *Settings) check() error { type SettingsRenderData struct { alps.BaseRenderData - Settings *Settings + Mailboxes []MailboxInfo + Settings *Settings + Subscriptions Subscriptions +} + +type Subscriptions []string + +func (s Subscriptions) Has(sub string) bool { + for _, cand := range s { + if cand == sub { + return true + } + } + return false } func handleSettings(ctx *alps.Context) error { @@ -1195,6 +1237,15 @@ func handleSettings(ctx *alps.Context) error { return fmt.Errorf("failed to load settings: %v", err) } + var mailboxes []MailboxInfo + err = ctx.Session.DoIMAP(func(c *imapclient.Client) error { + mailboxes, err = listMailboxes(c) + return err + }) + if err != nil { + return err + } + if ctx.Request().Method == http.MethodPost { settings.MessagesPerPage, err = strconv.Atoi(ctx.FormValue("messages_per_page")) if err != nil { @@ -1203,6 +1254,12 @@ func handleSettings(ctx *alps.Context) error { settings.Signature = ctx.FormValue("signature") settings.From = ctx.FormValue("from") + params, err := ctx.FormParams() + if err != nil { + return err + } + settings.Subscriptions = params["subscriptions"] + if err := settings.check(); err != nil { return echo.NewHTTPError(http.StatusBadRequest, err) } @@ -1216,5 +1273,7 @@ func handleSettings(ctx *alps.Context) error { return ctx.Render(http.StatusOK, "settings.html", &SettingsRenderData{ BaseRenderData: *alps.NewBaseRenderData(ctx), Settings: settings, + Mailboxes: mailboxes, + Subscriptions: Subscriptions(settings.Subscriptions), }) } diff --git a/themes/alps/assets/style.css b/themes/alps/assets/style.css index e64c8a3..d652f66 100644 --- a/themes/alps/assets/style.css +++ b/themes/alps/assets/style.css @@ -88,7 +88,8 @@ input[type="file"], input[type="number"], input[type="date"], input[type="time"], -textarea { +textarea, +select { margin: 0; border: none; border: 1px solid #e0e0e0; @@ -157,7 +158,7 @@ aside ul { aside li { width: 100%; display: flex; - padding: 0.4rem 0 0.4rem 0.5rem; + padding: 0.4rem 0.5rem; } aside li a { @@ -654,7 +655,8 @@ main table tfoot { .action-group label, .action-group input, -.action-group textarea { +.action-group textarea, +.action-group select { display: block; width: 100%; } @@ -665,6 +667,10 @@ main table tfoot { float: left; } +.action-group select { + height: 10rem; +} + .actions-message, .actions-contacts { display: flex; diff --git a/themes/alps/settings.html b/themes/alps/settings.html index 9fc58ca..61e76e6 100644 --- a/themes/alps/settings.html +++ b/themes/alps/settings.html @@ -32,6 +32,23 @@ >{{.Settings.Signature}} +
+ + +
+
- - {{- if eq .Name "INBOX" -}} +{{ if not (.Info.HasAttr "\\Noselect") }} +
  • + + {{- if eq .Info.Name "INBOX" -}} Inbox {{- else -}} - {{ .Name }} + {{ .Info.Name }} {{- end -}} - {{- if .HasAttr "\\HasChildren" }}/{{ end }} + {{- if .Info.HasAttr "\\HasChildren" }}/{{ end }} -
  • {{ else }}
  • - {{.Name}}{{- if .HasAttr "\\HasChildren" }}/{{ end }} + {{.Info.Name}}{{- if .Info.HasAttr "\\HasChildren" }}/{{ end }}
  • {{ end }} {{ end }} {{ define "aside" }} -