Integrate paginator library in place of custom pagination function.

This commit is contained in:
Kailash Nadh 2022-11-08 23:35:31 +05:30
parent 9add728b08
commit 56a9836e86
11 changed files with 55 additions and 45 deletions

View file

@ -3,6 +3,7 @@ package main
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"html/template"
"net/http" "net/http"
"github.com/knadh/listmonk/internal/manager" "github.com/knadh/listmonk/internal/manager"
@ -22,7 +23,7 @@ type campArchive struct {
func handleGetCampaignArchives(c echo.Context) error { func handleGetCampaignArchives(c echo.Context) error {
var ( var (
app = c.Get("app").(*App) app = c.Get("app").(*App)
pg = getPagination(c.QueryParams(), 50) pg = app.paginator.NewFromURL(c.Request().URL.Query())
) )
camps, total, err := getCampaignArchives(pg.Offset, pg.Limit, app) camps, total, err := getCampaignArchives(pg.Offset, pg.Limit, app)
@ -49,23 +50,23 @@ func handleGetCampaignArchives(c echo.Context) error {
func handleCampaignArchivesPage(c echo.Context) error { func handleCampaignArchivesPage(c echo.Context) error {
var ( var (
app = c.Get("app").(*App) app = c.Get("app").(*App)
pg = getPagination(c.QueryParams(), 50) pg = app.paginator.NewFromURL(c.Request().URL.Query())
) )
out, total, err := getCampaignArchives(pg.Offset, pg.Limit, app) out, total, err := getCampaignArchives(pg.Offset, pg.Limit, app)
if err != nil { if err != nil {
return err return err
} }
pg.SetTotal(total)
title := app.i18n.T("public.archiveTitle") title := app.i18n.T("public.archiveTitle")
return c.Render(http.StatusOK, "archive", struct { return c.Render(http.StatusOK, "archive", struct {
Title string Title string
Description string Description string
Campaigns []campArchive Campaigns []campArchive
Total int TotalPages int
Page int Pagination template.HTML
PerPage int }{title, title, out, pg.TotalPages, template.HTML(pg.HTML("?page=%d"))})
}{title, title, out, total, pg.Page, pg.PerPage})
} }
// handleCampaignArchivePage renders the public campaign archives page. // handleCampaignArchivePage renders the public campaign archives page.
@ -137,7 +138,8 @@ func compileArchiveCampaigns(camps []models.Campaign, app *App) ([]manager.Campa
) )
out := make([]manager.CampaignMessage, 0, len(camps)) out := make([]manager.CampaignMessage, 0, len(camps))
for _, camp := range camps { for _, c := range camps {
camp := c
if err := camp.CompileTemplate(app.manager.TemplateFuncs(&camp)); err != nil { if err := camp.CompileTemplate(app.manager.TemplateFuncs(&camp)); err != nil {
app.log.Printf("error compiling template: %v", err) app.log.Printf("error compiling template: %v", err)
return nil, echo.NewHTTPError(http.StatusInternalServerError, app.i18n.T("public.errorFetchingCampaign")) return nil, echo.NewHTTPError(http.StatusInternalServerError, app.i18n.T("public.errorFetchingCampaign"))

View file

@ -15,7 +15,7 @@ import (
func handleGetBounces(c echo.Context) error { func handleGetBounces(c echo.Context) error {
var ( var (
app = c.Get("app").(*App) app = c.Get("app").(*App)
pg = getPagination(c.QueryParams(), 50) pg = app.paginator.NewFromURL(c.Request().URL.Query())
id, _ = strconv.Atoi(c.Param("id")) id, _ = strconv.Atoi(c.Param("id"))
campID, _ = strconv.Atoi(c.QueryParam("campaign_id")) campID, _ = strconv.Atoi(c.QueryParam("campaign_id"))

View file

@ -52,7 +52,7 @@ var (
func handleGetCampaigns(c echo.Context) error { func handleGetCampaigns(c echo.Context) error {
var ( var (
app = c.Get("app").(*App) app = c.Get("app").(*App)
pg = getPagination(c.QueryParams(), 20) pg = app.paginator.NewFromURL(c.Request().URL.Query())
status = c.QueryParams()["status"] status = c.QueryParams()["status"]
query = strings.TrimSpace(c.FormValue("query")) query = strings.TrimSpace(c.FormValue("query"))

View file

@ -3,11 +3,10 @@ package main
import ( import (
"crypto/subtle" "crypto/subtle"
"net/http" "net/http"
"net/url"
"path" "path"
"regexp" "regexp"
"strconv"
"github.com/knadh/paginator"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v4/middleware"
) )
@ -35,6 +34,14 @@ type pagination struct {
var ( var (
reUUID = regexp.MustCompile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$") reUUID = regexp.MustCompile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")
reLangCode = regexp.MustCompile("[^a-zA-Z_0-9\\-]") reLangCode = regexp.MustCompile("[^a-zA-Z_0-9\\-]")
paginate = paginator.New(paginator.Opt{
DefaultPerPage: 20,
MaxPerPage: 50,
NumPageNums: 10,
PageParam: "page",
PerPageParam: "per_page",
})
) )
// registerHandlers registers HTTP handlers. // registerHandlers registers HTTP handlers.
@ -311,34 +318,3 @@ func noIndex(next echo.HandlerFunc, params ...string) echo.HandlerFunc {
return next(c) return next(c)
} }
} }
// getPagination takes form values and extracts pagination values from it.
func getPagination(q url.Values, perPage int) pagination {
var (
page, _ = strconv.Atoi(q.Get("page"))
pp = q.Get("per_page")
)
if pp == "all" {
// No limit.
perPage = 0
} else {
ppi, _ := strconv.Atoi(pp)
if ppi > 0 {
perPage = ppi
}
}
if page < 1 {
page = 0
} else {
page--
}
return pagination{
Page: page + 1,
PerPage: perPage,
Offset: page * perPage,
Limit: perPage,
}
}

View file

@ -13,14 +13,15 @@ import (
func handleGetLists(c echo.Context) error { func handleGetLists(c echo.Context) error {
var ( var (
app = c.Get("app").(*App) app = c.Get("app").(*App)
out models.PageResults pg = app.paginator.NewFromURL(c.Request().URL.Query())
pg = getPagination(c.QueryParams(), 20)
query = strings.TrimSpace(c.FormValue("query")) query = strings.TrimSpace(c.FormValue("query"))
orderBy = c.FormValue("order_by") orderBy = c.FormValue("order_by")
order = c.FormValue("order") order = c.FormValue("order")
minimal, _ = strconv.ParseBool(c.FormValue("minimal")) minimal, _ = strconv.ParseBool(c.FormValue("minimal"))
listID, _ = strconv.Atoi(c.Param("id")) listID, _ = strconv.Atoi(c.Param("id"))
out models.PageResults
) )
// Fetch one list. // Fetch one list.

View file

@ -24,6 +24,7 @@ import (
"github.com/knadh/listmonk/internal/messenger" "github.com/knadh/listmonk/internal/messenger"
"github.com/knadh/listmonk/internal/subimporter" "github.com/knadh/listmonk/internal/subimporter"
"github.com/knadh/listmonk/models" "github.com/knadh/listmonk/models"
"github.com/knadh/paginator"
"github.com/knadh/stuffbin" "github.com/knadh/stuffbin"
) )
@ -45,6 +46,7 @@ type App struct {
media media.Store media media.Store
i18n *i18n.I18n i18n *i18n.I18n
bounce *bounce.Manager bounce *bounce.Manager
paginator *paginator.Paginator
notifTpls *notifTpls notifTpls *notifTpls
log *log.Logger log *log.Logger
bufLog *buflog.BufLog bufLog *buflog.BufLog
@ -166,6 +168,14 @@ func main() {
messengers: make(map[string]messenger.Messenger), messengers: make(map[string]messenger.Messenger),
log: lo, log: lo,
bufLog: bufLog, bufLog: bufLog,
paginator: paginator.New(paginator.Opt{
DefaultPerPage: 20,
MaxPerPage: 50,
NumPageNums: 10,
PageParam: "page",
PerPageParam: "per_page",
}),
} }
// Load i18n language map. // Load i18n language map.

View file

@ -84,7 +84,7 @@ func handleGetSubscriber(c echo.Context) error {
func handleQuerySubscribers(c echo.Context) error { func handleQuerySubscribers(c echo.Context) error {
var ( var (
app = c.Get("app").(*App) app = c.Get("app").(*App)
pg = getPagination(c.QueryParams(), 30) pg = app.paginator.NewFromURL(c.Request().URL.Query())
// The "WHERE ?" bit. // The "WHERE ?" bit.
query = sanitizeSQLExp(c.FormValue("query")) query = sanitizeSQLExp(c.FormValue("query"))

1
go.mod
View file

@ -16,6 +16,7 @@ require (
github.com/knadh/goyesql/v2 v2.1.2 github.com/knadh/goyesql/v2 v2.1.2
github.com/knadh/koanf v1.2.3 github.com/knadh/koanf v1.2.3
github.com/knadh/smtppool v1.0.1 github.com/knadh/smtppool v1.0.1
github.com/knadh/paginator v0.0.0-20210310070812-ae09d514e148 // indirect
github.com/knadh/stuffbin v1.1.0 github.com/knadh/stuffbin v1.1.0
github.com/labstack/echo/v4 v4.9.0 github.com/labstack/echo/v4 v4.9.0
github.com/lib/pq v1.10.3 github.com/lib/pq v1.10.3

2
go.sum
View file

@ -82,6 +82,8 @@ github.com/knadh/goyesql/v2 v2.1.2 h1:XQrGiXSyeaRchdJE7odfzmodn3eAyhD5D6SxAkU2+4
github.com/knadh/goyesql/v2 v2.1.2/go.mod h1:is+wK/XQBukYK3DdKfpJRyDH9U/ZTMyX2u6DFijjRnI= github.com/knadh/goyesql/v2 v2.1.2/go.mod h1:is+wK/XQBukYK3DdKfpJRyDH9U/ZTMyX2u6DFijjRnI=
github.com/knadh/koanf v1.2.3 h1:2Rkr0YhhYk+4QEOm800Q3Pu0Wi87svTxM6uuEb4WhYw= github.com/knadh/koanf v1.2.3 h1:2Rkr0YhhYk+4QEOm800Q3Pu0Wi87svTxM6uuEb4WhYw=
github.com/knadh/koanf v1.2.3/go.mod h1:xpPTwMhsA/aaQLAilyCCqfpEiY1gpa160AiCuWHJUjY= github.com/knadh/koanf v1.2.3/go.mod h1:xpPTwMhsA/aaQLAilyCCqfpEiY1gpa160AiCuWHJUjY=
github.com/knadh/paginator v0.0.0-20210310070812-ae09d514e148 h1:5KojMX5qCcq89QLyhjZPRh8zoFfmUiPaEzaxMCzSPLA=
github.com/knadh/paginator v0.0.0-20210310070812-ae09d514e148/go.mod h1:80FK5OPRRQQKEK75ahG+92/MdX/lu4dE8loTzJRVcCQ=
github.com/knadh/smtppool v1.0.0 h1:1c8A7+nD8WdMMzvd3yY5aoY9QBgyGTA+Iq1IdlgKGJw= github.com/knadh/smtppool v1.0.0 h1:1c8A7+nD8WdMMzvd3yY5aoY9QBgyGTA+Iq1IdlgKGJw=
github.com/knadh/smtppool v1.0.0/go.mod h1:3DJHouXAgPDBz0kC50HukOsdapYSwIEfJGwuip46oCA= github.com/knadh/smtppool v1.0.0/go.mod h1:3DJHouXAgPDBz0kC50HukOsdapYSwIEfJGwuip46oCA=
github.com/knadh/smtppool v1.0.1 h1:gNASLB4x4W5jhVHRApwr9d2xSpsuannAFJVt/bVR8pA= github.com/knadh/smtppool v1.0.1 h1:gNASLB4x4W5jhVHRApwr9d2xSpsuannAFJVt/bVR8pA=

View file

@ -148,6 +148,20 @@ input[disabled] {
margin-bottom: 10px; margin-bottom: 10px;
} }
.pagination {
margin-top: 30px;
text-align: center;
}
.pg-page {
display: inline-block;
padding: 0 10px;
text-decoration: none;
}
.pg-page.pg-selected {
text-decoration: underline;
font-weight: bold;
}
#btn-back { #btn-back {
display: none; display: none;
} }

View file

@ -15,6 +15,10 @@
{{ if not .Data.Campaigns }} {{ if not .Data.Campaigns }}
{{ L.T "public.archiveEmpty" }} {{ L.T "public.archiveEmpty" }}
{{ end }} {{ end }}
{{ if gt .Data.TotalPages 1 }}
<div class="pagination">{{ .Data.Pagination }}</div>
{{ end }}
</section> </section>
{{ template "footer" .}} {{ template "footer" .}}