Add basic pagination to message list
References: https://todo.sr.ht/~sircmpwn/koushin/22
This commit is contained in:
parent
6344806755
commit
8de93c50d2
7 changed files with 61 additions and 21 deletions
|
@ -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
22
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 {
|
||||
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})
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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 */}}
|
||||
|
|
23
server.go
23
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,
|
||||
})
|
||||
})
|
||||
|
||||
|
|
10
smtp.go
10
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 {
|
||||
|
|
|
@ -2,9 +2,9 @@ package koushin
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func parseUid(s string) (uint32, error) {
|
||||
|
|
Loading…
Reference in a new issue