Add RSS feed to the public mailing list archive.
This commit is contained in:
parent
438568eeb0
commit
f958f3d24b
8 changed files with 72 additions and 4 deletions
|
@ -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 (
|
||||||
|
|
|
@ -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
1
go.mod
|
@ -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
2
go.sum
|
@ -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=
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 }}
|
||||||
|
|
|
@ -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" .}}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue