diff --git a/plugins/base/imap.go b/plugins/base/imap.go index 0c36baa..e7b526e 100755 --- a/plugins/base/imap.go +++ b/plugins/base/imap.go @@ -237,7 +237,7 @@ func (msg *IMAPMessage) HasFlag(flag string) bool { return false } -func listMessages(conn *imapclient.Client, mboxName string, page int) ([]IMAPMessage, error) { +func listMessages(conn *imapclient.Client, mboxName string, page, messagesPerPage int) ([]IMAPMessage, error) { if err := ensureMailboxSelected(conn, mboxName); err != nil { return nil, err } @@ -281,7 +281,7 @@ func listMessages(conn *imapclient.Client, mboxName string, page int) ([]IMAPMes return msgs, nil } -func searchMessages(conn *imapclient.Client, mboxName, query string, page int) (msgs []IMAPMessage, total int, err error) { +func searchMessages(conn *imapclient.Client, mboxName, query string, page, messagesPerPage int) (msgs []IMAPMessage, total int, err error) { if err := ensureMailboxSelected(conn, mboxName); err != nil { return nil, 0, err } diff --git a/plugins/base/plugin.go b/plugins/base/plugin.go index 16eaf1d..5743977 100644 --- a/plugins/base/plugin.go +++ b/plugins/base/plugin.go @@ -4,8 +4,6 @@ import ( "git.sr.ht/~emersion/koushin" ) -const messagesPerPage = 50 - func init() { p := koushin.GoPlugin{Name: "base"} diff --git a/plugins/base/public/mailbox.html b/plugins/base/public/mailbox.html index d19c73d..9e2a0a2 100644 --- a/plugins/base/public/mailbox.html +++ b/plugins/base/public/mailbox.html @@ -3,7 +3,9 @@

koushin

- Logout · Compose + Logout + · Compose + · Settings

{{.Mailbox.Name}}

diff --git a/plugins/base/public/settings.html b/plugins/base/public/settings.html new file mode 100644 index 0000000..c0d715c --- /dev/null +++ b/plugins/base/public/settings.html @@ -0,0 +1,18 @@ +{{template "head.html"}} + +

koushin

+ +

+ Back +

+ +

Settings

+ +
+ + +

+ +
+ +{{template "foot.html"}} diff --git a/plugins/base/routes.go b/plugins/base/routes.go index f7b85e6..ec22d1b 100644 --- a/plugins/base/routes.go +++ b/plugins/base/routes.go @@ -55,6 +55,9 @@ func registerRoutes(p *koushin.GoPlugin) { p.POST("/message/:mbox/:uid/delete", handleDelete) p.POST("/message/:mbox/:uid/flag", handleSetFlags) + + p.GET("/settings", handleSettings) + p.POST("/settings", handleSettings) } type MailboxRenderData struct { @@ -80,6 +83,12 @@ func handleGetMailbox(ctx *koushin.Context) error { } } + settings, err := loadSettings(ctx.Session.Store()) + if err != nil { + return err + } + messagesPerPage := settings.MessagesPerPage + query := ctx.QueryParam("query") var mailboxes []*imap.MailboxInfo @@ -92,9 +101,9 @@ func handleGetMailbox(ctx *koushin.Context) error { return err } if query != "" { - msgs, total, err = searchMessages(c, mboxName, query, page) + msgs, total, err = searchMessages(c, mboxName, query, page, messagesPerPage) } else { - msgs, err = listMessages(c, mboxName, page) + msgs, err = listMessages(c, mboxName, page, messagesPerPage) } if err != nil { return err @@ -185,6 +194,12 @@ func handleGetPart(ctx *koushin.Context, raw bool) error { return echo.NewHTTPError(http.StatusBadRequest, err) } + settings, err := loadSettings(ctx.Session.Store()) + if err != nil { + return err + } + messagesPerPage := settings.MessagesPerPage + var mailboxes []*imap.MailboxInfo var msg *IMAPMessage var part *message.Entity @@ -685,3 +700,63 @@ func handleSetFlags(ctx *koushin.Context) error { return ctx.Redirect(http.StatusFound, fmt.Sprintf("/message/%v/%v", url.PathEscape(mboxName), uid)) } + +const settingsKey = "base.settings" +const maxMessagesPerPage = 100 + +type Settings struct { + MessagesPerPage int +} + +func loadSettings(s koushin.Store) (*Settings, error) { + settings := &Settings{ + MessagesPerPage: 50, + } + if err := s.Get(settingsKey, settings); err != nil && err != koushin.ErrNoStoreEntry { + return nil, err + } + if err := settings.check(); err != nil { + return nil, err + } + return settings, nil +} + +func (s *Settings) check() error { + if s.MessagesPerPage <= 0 || s.MessagesPerPage > maxMessagesPerPage { + return fmt.Errorf("messages per page out of bounds: %v", s.MessagesPerPage) + } + return nil +} + +type SettingsRenderData struct { + koushin.BaseRenderData + Settings *Settings +} + +func handleSettings(ctx *koushin.Context) error { + settings, err := loadSettings(ctx.Session.Store()) + if err != nil { + return fmt.Errorf("failed to load settings: %v", err) + } + + if ctx.Request().Method == http.MethodPost { + settings.MessagesPerPage, err = strconv.Atoi(ctx.FormValue("messages_per_page")) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, "invalid messages per page: %v", err) + } + + if err := settings.check(); err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err) + } + if err := ctx.Session.Store().Put(settingsKey, settings); err != nil { + return fmt.Errorf("failed to save settings: %v", err) + } + + return ctx.Redirect(http.StatusFound, "/mailbox/INBOX") + } + + return ctx.Render(http.StatusOK, "settings.html", &SettingsRenderData{ + BaseRenderData: *koushin.NewBaseRenderData(ctx), + Settings: settings, + }) +}