diff --git a/cmd/public.go b/cmd/public.go
index 0a871c26e..94c684fdf 100644
--- a/cmd/public.go
+++ b/cmd/public.go
@@ -47,9 +47,13 @@ type publicTpl struct {
Description string
}
-type unsubTpl struct {
+type updateTpl struct {
publicTpl
SubUUID string
+ Email string
+ AM bool
+ PM bool
+ Sponsored bool
AllowBlocklist bool
AllowExport bool
AllowWipe bool
@@ -156,39 +160,49 @@ func handleViewCampaignMessage(c echo.Context) error {
// campaigns link to.
func handleSubscriptionPage(c echo.Context) error {
var (
- app = c.Get("app").(*App)
- campUUID = c.Param("campUUID")
- subUUID = c.Param("subUUID")
- unsub = c.Request().Method == http.MethodPost
- blocklist, _ = strconv.ParseBool(c.FormValue("blocklist"))
- out = unsubTpl{}
+ app = c.Get("app").(*App)
+ subUUID = c.Param("subUUID")
+ update = c.Request().Method == http.MethodPost
+ out = updateTpl{}
)
out.SubUUID = subUUID
- out.Title = app.i18n.T("public.unsubscribeTitle")
+ out.Title = app.i18n.T("public.rtmSubscriptionTitle")
out.AllowBlocklist = app.constants.Privacy.AllowBlocklist
out.AllowExport = app.constants.Privacy.AllowExport
out.AllowWipe = app.constants.Privacy.AllowWipe
- // Unsubscribe.
- if unsub {
- // Is blocklisting allowed?
- if !app.constants.Privacy.AllowBlocklist {
- blocklist = false
- }
+ var sub models.RtmSubscriptions
+ if err := app.queries.GetRtmSubscriptions.Get(&sub, subUUID); err != nil {
+ app.log.Printf("GetRtmSubscriptions error: %v", err)
+ return c.Render(http.StatusInternalServerError, tplMessage,
+ makeMsgTpl(app.i18n.T("public.errorTitle"), "",
+ app.i18n.Ts("public.errorProcessingRequest")))
+ }
- if _, err := app.queries.Unsubscribe.Exec(campUUID, subUUID, blocklist); err != nil {
- app.log.Printf("error unsubscribing: %v", err)
+ out.Email = sub.Email
+ out.AM = sub.AM
+ out.PM = sub.PM
+ out.Sponsored = sub.Sponsored
+
+ // Update subscriptions.
+ if update {
+ am := c.FormValue("am") != ""
+ pm := c.FormValue("pm") != ""
+ sponsored := c.FormValue("sponsored") != ""
+
+ if _, err := app.queries.UpdateRtmSubscriptions.Exec(subUUID, am, pm, sponsored); err != nil {
+ app.log.Printf("UpdateRtmSubscriptions error: %v", err)
return c.Render(http.StatusInternalServerError, tplMessage,
makeMsgTpl(app.i18n.T("public.errorTitle"), "",
app.i18n.Ts("public.errorProcessingRequest")))
}
return c.Render(http.StatusOK, tplMessage,
- makeMsgTpl(app.i18n.T("public.unsubbedTitle"), "",
- app.i18n.T("public.unsubbedInfo")))
+ makeMsgTpl(app.i18n.T("public.rtmSubscriptionSuccess"), "",
+ app.i18n.T("public.rtmSubscriptionInfo")))
}
- return c.Render(http.StatusOK, "subscription", out)
+ return c.Render(http.StatusOK, "rtm-subscription", out)
}
// handleOptinPage renders the double opt-in confirmation page that subscribers
diff --git a/cmd/queries.go b/cmd/queries.go
index 90c6a9b2f..b5d40cb76 100644
--- a/cmd/queries.go
+++ b/cmd/queries.go
@@ -33,6 +33,10 @@ type Queries struct {
Unsubscribe *sqlx.Stmt `query:"unsubscribe"`
ExportSubscriberData *sqlx.Stmt `query:"export-subscriber-data"`
+ // RTM queries
+ GetRtmSubscriptions *sqlx.Stmt `query:"get-rtm-subscriptions"`
+ UpdateRtmSubscriptions *sqlx.Stmt `query:"update-rtm-subscriptions"`
+
// Non-prepared arbitrary subscriber queries.
QuerySubscribers string `query:"query-subscribers"`
QuerySubscribersCount string `query:"query-subscribers-count"`
diff --git a/i18n/en.json b/i18n/en.json
index 419a8c69f..252670ee3 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -302,6 +302,11 @@
"public.unsubHelp": "Do you want to unsubscribe from this mailing list?",
"public.unsubTitle": "Unsubscribe",
"public.unsubbedInfo": "You have unsubscribed successfully.",
+ "public.rtmSubscription": "Update",
+ "public.rtmSubscriptionSuccess": "Success",
+ "public.rtmSubscriptionTitle": "Update Subscriptions",
+ "public.rtmSubscriptionHelp": "Select which newsletters you'd like to be subscribed to.",
+ "public.rtmSubscriptionInfo": "The changes you made to your subscriptions have been succesfully applied.",
"public.unsubbedTitle": "Unsubscribed",
"public.unsubscribeTitle": "Unsubscribe from mailing list",
"settings.appearance.adminHelp": "Custom CSS to apply to the admin UI.",
diff --git a/models/models.go b/models/models.go
index 9388c08c8..9b0dfc3c2 100644
--- a/models/models.go
+++ b/models/models.go
@@ -270,6 +270,14 @@ type Bounce struct {
Total int `db:"total" json:"-"`
}
+// Data used for RTM subscription management
+type RtmSubscriptions struct {
+ Email string `db:"email" json:"email"`
+ AM bool `db:"am" json:"am"`
+ PM bool `db:"pm" json:"pm"`
+ Sponsored bool `db:"sponsored" json:"sponsored"`
+}
+
// markdown is a global instance of Markdown parser and renderer.
var markdown = goldmark.New(
goldmark.WithParserOptions(
diff --git a/queries.sql b/queries.sql
index a155c36bf..7d1fc9c73 100644
--- a/queries.sql
+++ b/queries.sql
@@ -196,6 +196,132 @@ UPDATE subscriber_lists SET status = 'unsubscribed' WHERE
-- If $3 is false, unsubscribe from the campaign's lists, otherwise all lists.
CASE WHEN $3 IS FALSE THEN list_id = ANY(SELECT list_id FROM lists) ELSE list_id != 0 END;
+-- name: get-rtm-subscriptions
+-- Get subscriptions by user and tag
+-- $1 = subscribers.uuid
+WITH
+ subscriber AS (
+ SELECT id, email
+ FROM subscribers
+ WHERE uuid = $1
+ ),
+ subscribed AS (
+ SELECT array_agg(list_id) AS lists
+ FROM subscriber_lists AS l, subscriber AS s
+ WHERE l.subscriber_id = s.id
+ AND l.status != 'unsubscribed'
+ ),
+ am AS (
+ SELECT array_agg(id) AS lists
+ FROM lists
+ WHERE 'am' = ANY (tags)
+ ),
+ pm AS (
+ SELECT array_agg(id) AS lists
+ FROM lists
+ WHERE 'pm' = ANY (tags)
+ ),
+ sponsored AS (
+ SELECT array_agg(id) AS lists
+ FROM lists
+ WHERE 'sponsored' = ANY (tags)
+ )
+SELECT
+ subscriber.email,
+ COALESCE(am.lists && subscribed.lists, false) AS am,
+ COALESCE(pm.lists && subscribed.lists, false) AS pm,
+ COALESCE(sponsored.lists && subscribed.lists, false) AS sponsored
+FROM subscriber, am, pm, sponsored, subscribed;
+
+-- name: update-rtm-subscriptions
+-- Subscribe AM, PM, Sponsored subscriptions by user and tag
+-- $1 = subscribers.uuid
+-- $2 = bool (am)
+-- $3 = bool (pm)
+-- $4 = bool (sponsored)
+WITH
+ subscriber AS (
+ SELECT id
+ FROM subscribers
+ WHERE uuid = $1
+ ),
+ amSubscribe AS (
+ INSERT INTO subscriber_lists (subscriber_id, list_id, status, updated_at)
+ SELECT subscriber.id, am.primary, 'unconfirmed', now()
+ FROM subscriber, (
+ SELECT id AS primary
+ FROM lists
+ WHERE 'am' = ANY (tags)
+ AND 'primary' = ANY (tags)
+ ) AS am
+ WHERE true = $2
+ ON CONFLICT (subscriber_id, list_id)
+ DO UPDATE SET status = 'unconfirmed', updated_at = now()
+ ),
+ pmSubscribe AS (
+ INSERT INTO subscriber_lists (subscriber_id, list_id, status, updated_at)
+ SELECT subscriber.id, pm.primary, 'unconfirmed', now()
+ FROM subscriber, (
+ SELECT id AS primary
+ FROM lists
+ WHERE 'pm' = ANY (tags)
+ AND 'primary' = ANY (tags)
+ ) AS pm
+ WHERE true = $3
+ ON CONFLICT (subscriber_id, list_id)
+ DO UPDATE SET status = 'unconfirmed', updated_at = now()
+ ),
+ sponsoredSubscribe AS (
+ INSERT INTO subscriber_lists (subscriber_id, list_id, status, updated_at)
+ SELECT subscriber.id, sponsored.primary, 'unconfirmed', now()
+ FROM subscriber, (
+ SELECT id AS primary
+ FROM lists
+ WHERE 'sponsored' = ANY (tags)
+ AND 'primary' = ANY (tags)
+ ) AS sponsored
+ WHERE true = $4
+ ON CONFLICT (subscriber_id, list_id)
+ DO UPDATE SET status = 'unconfirmed', updated_at = now()
+ ),
+ amUnsubscribe AS (
+ UPDATE subscriber_lists SET
+ status = 'unsubscribed', updated_at = now()
+ FROM subscriber, (
+ SELECT id
+ FROM lists
+ WHERE 'am' = ANY (tags)
+ ) AS am
+ WHERE false = $2
+ AND subscriber_id = subscriber.id
+ AND list_id = am.id
+ ),
+ pmUnsubscribe AS (
+ UPDATE subscriber_lists SET
+ status = 'unsubscribed', updated_at = now()
+ FROM subscriber, (
+ SELECT id
+ FROM lists
+ WHERE 'pm' = ANY (tags)
+ ) AS pm
+ WHERE false = $3
+ AND subscriber_id = subscriber.id
+ AND list_id = pm.id
+ ),
+ sponsoredUnsubscribe AS (
+ UPDATE subscriber_lists SET
+ status = 'unsubscribed', updated_at = now()
+ FROM subscriber, (
+ SELECT id
+ FROM lists
+ WHERE 'sponsored' = ANY (tags)
+ ) AS sponsored
+ WHERE false = $4
+ AND subscriber_id = subscriber.id
+ AND list_id = sponsored.id
+ )
+SELECT true;
+
-- privacy
-- name: export-subscriber-data
WITH prof AS (
diff --git a/static/public/templates/rtm-subscription.html b/static/public/templates/rtm-subscription.html
new file mode 100644
index 000000000..eb3b009fd
--- /dev/null
+++ b/static/public/templates/rtm-subscription.html
@@ -0,0 +1,70 @@
+{{ define "rtm-subscription" }}
+{{ template "header" .}}
+ {{ L.T "public.rtmSubscriptionHelp" }}{{ L.T "public.rtmSubscriptionTitle" }}
+