Add RSS feed to the public mailing list archive.

This commit is contained in:
Kailash Nadh 2022-11-10 22:06:36 +05:30
parent 438568eeb0
commit f958f3d24b
8 changed files with 72 additions and 4 deletions

View file

@ -6,6 +6,7 @@ import (
"html/template" "html/template"
"net/http" "net/http"
"github.com/gorilla/feeds"
"github.com/knadh/listmonk/internal/manager" "github.com/knadh/listmonk/internal/manager"
"github.com/knadh/listmonk/models" "github.com/knadh/listmonk/models"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
@ -46,6 +47,42 @@ func handleGetCampaignArchives(c echo.Context) error {
return c.JSON(200, okResp{out}) return c.JSON(200, okResp{out})
} }
// handleGetCampaignArchivesFeed renders the public campaign archives RSS feed.
func handleGetCampaignArchivesFeed(c echo.Context) error {
var (
app = c.Get("app").(*App)
pg = app.paginator.NewFromURL(c.Request().URL.Query())
)
camps, _, err := getCampaignArchives(pg.Offset, pg.Limit, app)
if err != nil {
return err
}
out := make([]*feeds.Item, 0, len(camps))
for _, c := range camps {
out = append(out, &feeds.Item{
Title: c.Subject,
Link: &feeds.Link{Href: c.URL},
Created: c.CreatedAt.Time,
})
}
feed := &feeds.Feed{
Title: app.constants.SiteName,
Link: &feeds.Link{Href: app.constants.RootURL},
Description: app.i18n.T("public.archiveTitle"),
Items: out,
}
if err := feed.WriteRss(c.Response().Writer); err != nil {
app.log.Printf("error generating archive RSS feed: %v", err)
return echo.NewHTTPError(http.StatusBadRequest, app.i18n.T("public.errorProcessingRequest"))
}
return nil
}
// handleCampaignArchivesPage renders the public campaign archives page. // handleCampaignArchivesPage renders the public campaign archives page.
func handleCampaignArchivesPage(c echo.Context) error { func handleCampaignArchivesPage(c echo.Context) error {
var ( var (

View file

@ -194,7 +194,9 @@ func initHTTPHandlers(e *echo.Echo, app *App) {
"campUUID", "subUUID"))) "campUUID", "subUUID")))
e.GET("/campaign/:campUUID/:subUUID/px.png", noIndex(validateUUID(handleRegisterCampaignView, e.GET("/campaign/:campUUID/:subUUID/px.png", noIndex(validateUUID(handleRegisterCampaignView,
"campUUID", "subUUID"))) "campUUID", "subUUID")))
e.GET("/archive", handleCampaignArchivesPage) e.GET("/archive", handleCampaignArchivesPage)
e.GET("/archive.xml", handleGetCampaignArchivesFeed)
e.GET("/archive/:uuid", handleCampaignArchivePage) e.GET("/archive/:uuid", handleCampaignArchivePage)
e.GET("/public/custom.css", serveCustomApperance("public.custom_css")) e.GET("/public/custom.css", serveCustomApperance("public.custom_css"))

1
go.mod
View file

@ -9,6 +9,7 @@ require (
github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/gofrs/uuid v4.0.0+incompatible github.com/gofrs/uuid v4.0.0+incompatible
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/feeds v1.1.1 // indirect
github.com/huandu/xstrings v1.3.2 // indirect github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect github.com/imdario/mergo v0.3.12 // indirect
github.com/jmoiron/sqlx v1.3.4 github.com/jmoiron/sqlx v1.3.4

2
go.sum
View file

@ -42,6 +42,8 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/feeds v1.1.1 h1:HwKXxqzcRNg9to+BbvJog4+f3s/xzvtZXICcQGutYfY=
github.com/gorilla/feeds v1.1.1/go.mod h1:Nk0jZrvPFZX1OBe5NPiddPw7CfwF6Q9eqzaBbaightA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=

View file

@ -140,7 +140,7 @@ input[disabled] {
.archive { .archive {
list-style-type: none; list-style-type: none;
margin: 0; margin: 25px 0 0 0;
padding: 0; padding: 0;
} }
.archive .date { .archive .date {
@ -151,6 +151,16 @@ input[disabled] {
.archive li { .archive li {
margin-bottom: 15px; margin-bottom: 15px;
} }
.feed {
margin-right: 15px;
}
.home-options {
margin-top: 30px;
}
.home-options a {
margin: 0 7px;
}
.pagination { .pagination {
margin-top: 30px; margin-top: 30px;

View file

@ -17,9 +17,13 @@
{{ end }} {{ end }}
{{ if .EnablePublicSubPage }} {{ if .EnablePublicSubPage }}
<p class="right"> <div class="right">
<a href="{{ .RootURL }}/subscription/form">Subscribe</a> <a href="{{ .RootURL }}/archive.xml">
</p> <img src="{{ .RootURL }}/public/static/rss.svg" alt="RSS" class="feed"
width="16" height="16" />
</a>
<a href="{{ .RootURL }}/subscription/form">{{ L.T "public.sub" }}</a>
</div>
{{ end }} {{ end }}
{{ if gt .Data.TotalPages 1 }} {{ if gt .Data.TotalPages 1 }}

View file

@ -3,6 +3,15 @@
<section class="center"> <section class="center">
<a href="admin" class="button">{{ L.T "users.login" }}</a> <a href="admin" class="button">{{ L.T "users.login" }}</a>
<div class="home-options">
{{ if .EnablePublicSubPage }}
<a href="{{ .RootURL }}/subscription/form">{{ L.T "public.sub" }}</a>
{{ end }}
{{ if .EnablePublicSubPage }}
<a href="{{ .RootURL }}/archive">{{ L.T "public.archiveTitle" }}</a>
{{ end }}
</div>
</section> </section>
{{ template "footer" .}} {{ template "footer" .}}

View file

@ -6,6 +6,9 @@
<title>{{ .Data.Title }} - {{ .SiteName }}</title> <title>{{ .Data.Title }} - {{ .SiteName }}</title>
<meta name="description" content="{{ .Data.Description }}" /> <meta name="description" content="{{ .Data.Description }}" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<link rel="alternate" type="application/rss+xml" title="{{ L.T "public.archiveTitle" }} - {{ .SiteName }}" href="{{ .RootURL }}/archive.xml" />
<link href="/public/static/style.css" rel="stylesheet" type="text/css" /> <link href="/public/static/style.css" rel="stylesheet" type="text/css" />
<link href="/public/custom.css" rel="stylesheet" type="text/css"> <link href="/public/custom.css" rel="stylesheet" type="text/css">
<script src="/public/custom.js" async defer></script> <script src="/public/custom.js" async defer></script>