From 8de93c50d2cf2144cfd3050cf7970a4ee9860bf4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 3 Dec 2019 19:48:28 +0100 Subject: [PATCH] Add basic pagination to message list References: https://todo.sr.ht/~sircmpwn/koushin/22 --- conn_pool.go | 2 +- imap.go | 20 ++++++++++---------- public/mailbox.html | 15 ++++++++++++++- public/message.html | 8 +++++++- server.go | 23 ++++++++++++++++++++++- smtp.go | 10 +++++----- strconv.go | 2 +- 7 files changed, 60 insertions(+), 20 deletions(-) diff --git a/conn_pool.go b/conn_pool.go index 69281af..34c51bb 100644 --- a/conn_pool.go +++ b/conn_pool.go @@ -21,7 +21,7 @@ func generateToken() (string, error) { var ErrSessionExpired = errors.New("session expired") type Session struct { - locker sync.Mutex + locker sync.Mutex imapConn *imapclient.Client username, password string } diff --git a/imap.go b/imap.go index 748d5cb..9c83fc7 100644 --- a/imap.go +++ b/imap.go @@ -206,23 +206,23 @@ func (msg *imapMessage) PartTree() *IMAPPartNode { return imapPartTree(msg.BodyStructure, nil) } -func listMessages(conn *imapclient.Client, mboxName string) ([]imapMessage, error) { +func listMessages(conn *imapclient.Client, mboxName string, page int) ([]imapMessage, error) { if err := ensureMailboxSelected(conn, mboxName); err != nil { return nil, err } - n := uint32(50) - mbox := conn.Mailbox() - from := uint32(1) - to := mbox.Messages - if mbox.Messages == 0 { + to := int(mbox.Messages) - page*messagesPerPage + from := to - messagesPerPage + if from <= 0 { + from = 1 + } + if to <= 0 { return nil, nil - } else if mbox.Messages > n { - from = mbox.Messages - n } + seqSet := new(imap.SeqSet) - seqSet.AddRange(from, to) + seqSet.AddRange(uint32(from), uint32(to)) fetch := []imap.FetchItem{imap.FetchEnvelope, imap.FetchUid, imap.FetchBodyStructure} @@ -232,7 +232,7 @@ func listMessages(conn *imapclient.Client, mboxName string) ([]imapMessage, erro done <- conn.Fetch(seqSet, fetch, ch) }() - msgs := make([]imapMessage, 0, n) + msgs := make([]imapMessage, 0, to-from) for msg := range ch { msgs = append(msgs, imapMessage{msg}) } diff --git a/public/mailbox.html b/public/mailbox.html index e56efcb..435998c 100644 --- a/public/mailbox.html +++ b/public/mailbox.html @@ -20,10 +20,23 @@ + +

+ {{if ge .PrevPage 0}} + Prev + {{end}} + {{if ge .NextPage 0}} + Next + {{end}} +

{{else}}

Mailbox is empty.

{{end}} diff --git a/public/message.html b/public/message.html index 2e1a308..5c18bd0 100644 --- a/public/message.html +++ b/public/message.html @@ -6,7 +6,13 @@ Back

-

{{.Message.Envelope.Subject}}

+

+ {{if .Message.Envelope.Subject}} + {{.Message.Envelope.Subject}} + {{else}} + (No subject) + {{end}} +

{{define "message-part-tree"}} {{/* nested templates can't access the parent's context */}} diff --git a/server.go b/server.go index bcdcfcc..93da487 100644 --- a/server.go +++ b/server.go @@ -6,6 +6,7 @@ import ( "mime" "net/http" "net/url" + "strconv" "strings" "time" @@ -18,6 +19,8 @@ import ( const cookieName = "koushin_session" +const messagesPerPage = 50 + type Server struct { imap struct { host string @@ -366,6 +369,14 @@ func New(imapURL, smtpURL string) *echo.Echo { return echo.NewHTTPError(http.StatusBadRequest, err) } + page := 0 + if pageStr := ctx.QueryParam("page"); pageStr != "" { + var err error + if page, err = strconv.Atoi(pageStr); err != nil || page < 0 { + return echo.NewHTTPError(http.StatusBadRequest, "invalid page index") + } + } + var mailboxes []*imap.MailboxInfo var msgs []imapMessage var mbox *imap.MailboxStatus @@ -374,7 +385,7 @@ func New(imapURL, smtpURL string) *echo.Echo { if mailboxes, err = listMailboxes(c); err != nil { return err } - if msgs, err = listMessages(c, mboxName); err != nil { + if msgs, err = listMessages(c, mboxName, page); err != nil { return err } mbox = c.Mailbox() @@ -384,10 +395,20 @@ func New(imapURL, smtpURL string) *echo.Echo { return err } + prevPage, nextPage := -1, -1 + if page > 0 { + prevPage = page - 1 + } + if (page+1)*messagesPerPage < int(mbox.Messages) { + nextPage = page + 1 + } + return ctx.Render(http.StatusOK, "mailbox.html", map[string]interface{}{ "Mailbox": mbox, "Mailboxes": mailboxes, "Messages": msgs, + "PrevPage": prevPage, + "NextPage": nextPage, }) }) diff --git a/smtp.go b/smtp.go index 288f332..b9d77b2 100644 --- a/smtp.go +++ b/smtp.go @@ -3,9 +3,9 @@ package koushin import ( "bufio" "fmt" - "time" "io" "strings" + "time" "github.com/emersion/go-message/mail" "github.com/emersion/go-smtp" @@ -50,11 +50,11 @@ func (s *Server) connectSMTP() (*smtp.Client, error) { } type OutgoingMessage struct { - From string - To []string - Subject string + From string + To []string + Subject string InReplyTo string - Text string + Text string } func (msg *OutgoingMessage) ToString() string { diff --git a/strconv.go b/strconv.go index 14c0c27..63cbffc 100644 --- a/strconv.go +++ b/strconv.go @@ -2,9 +2,9 @@ package koushin import ( "fmt" + "net/url" "strconv" "strings" - "net/url" ) func parseUid(s string) (uint32, error) {