Add basic pagination to message list

References: https://todo.sr.ht/~sircmpwn/koushin/22
This commit is contained in:
Simon Ser 2019-12-03 19:48:28 +01:00
parent 6344806755
commit 8de93c50d2
No known key found for this signature in database
GPG key ID: 0FDE7BE0E88F5E48
7 changed files with 61 additions and 21 deletions

View file

@ -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
}

22
imap.go
View file

@ -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 {
return nil, nil
} else if mbox.Messages > n {
from = mbox.Messages - n
to := int(mbox.Messages) - page*messagesPerPage
from := to - messagesPerPage
if from <= 0 {
from = 1
}
if to <= 0 {
return nil, nil
}
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})
}

View file

@ -20,10 +20,23 @@
<ul>
{{range .Messages}}
<li><a href="/message/{{$.Mailbox.Name | pathescape}}/{{.Uid}}?part={{.TextPartName}}">
{{.Envelope.Subject}}
{{if .Envelope.Subject}}
{{.Envelope.Subject}}
{{else}}
(No subject)
{{end}}
</a></li>
{{end}}
</ul>
<p>
{{if ge .PrevPage 0}}
<a href="?page={{.PrevPage}}">Prev</a>
{{end}}
{{if ge .NextPage 0}}
<a href="?page={{.NextPage}}">Next</a>
{{end}}
</p>
{{else}}
<p>Mailbox is empty.</p>
{{end}}

View file

@ -6,7 +6,13 @@
<a href="/mailbox/{{.Mailbox.Name | pathescape}}">Back</a>
</p>
<h2>{{.Message.Envelope.Subject}}</h2>
<h2>
{{if .Message.Envelope.Subject}}
{{.Message.Envelope.Subject}}
{{else}}
(No subject)
{{end}}
</h2>
{{define "message-part-tree"}}
{{/* nested templates can't access the parent's context */}}

View file

@ -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,
})
})

10
smtp.go
View file

@ -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 {

View file

@ -2,9 +2,9 @@ package koushin
import (
"fmt"
"net/url"
"strconv"
"strings"
"net/url"
)
func parseUid(s string) (uint32, error) {