implement finalize and unsubscribe endpoints
This commit is contained in:
parent
ec4aac24ab
commit
9c3ea8dd80
@ -32,18 +32,24 @@ func mailingListSubscribeHandler(ml mailinglist.MailingList) http.Handler {
|
||||
}
|
||||
|
||||
func mailingListFinalizeHandler(ml mailinglist.MailingList) http.Handler {
|
||||
var errInvalidSubToken = errors.New("invalid subToken")
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
subToken := r.PostFormValue("subToken")
|
||||
if l := len(subToken); l == 0 || l > 128 {
|
||||
badRequest(rw, r, errors.New("invalid subToken"))
|
||||
badRequest(rw, r, errInvalidSubToken)
|
||||
return
|
||||
}
|
||||
|
||||
err := ml.FinalizeSubscription(subToken)
|
||||
if errors.Is(err, mailinglist.ErrNotFound) ||
|
||||
errors.Is(err, mailinglist.ErrAlreadyVerified) {
|
||||
badRequest(rw, r, err)
|
||||
|
||||
if errors.Is(err, mailinglist.ErrNotFound) {
|
||||
badRequest(rw, r, errInvalidSubToken)
|
||||
return
|
||||
|
||||
} else if errors.Is(err, mailinglist.ErrAlreadyVerified) {
|
||||
// no problem
|
||||
|
||||
} else if err != nil {
|
||||
internalServerError(rw, r, err)
|
||||
return
|
||||
@ -54,17 +60,21 @@ func mailingListFinalizeHandler(ml mailinglist.MailingList) http.Handler {
|
||||
}
|
||||
|
||||
func mailingListUnsubscribeHandler(ml mailinglist.MailingList) http.Handler {
|
||||
var errInvalidUnsubToken = errors.New("invalid unsubToken")
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
unsubToken := r.PostFormValue("unsubToken")
|
||||
if l := len(unsubToken); l == 0 || l > 128 {
|
||||
badRequest(rw, r, errors.New("invalid unsubToken"))
|
||||
badRequest(rw, r, errInvalidUnsubToken)
|
||||
return
|
||||
}
|
||||
|
||||
err := ml.Unsubscribe(unsubToken)
|
||||
|
||||
if errors.Is(err, mailinglist.ErrNotFound) {
|
||||
badRequest(rw, r, err)
|
||||
badRequest(rw, r, errInvalidUnsubToken)
|
||||
return
|
||||
|
||||
} else if err != nil {
|
||||
internalServerError(rw, r, err)
|
||||
return
|
||||
|
@ -27,7 +27,7 @@ func main() {
|
||||
|
||||
logger := mlog.NewLogger(nil)
|
||||
|
||||
hostname := flag.String("hostname", "localhost:4000", "Hostname to advertise this server as")
|
||||
publicURLStr := flag.String("public-url", "http://localhost:4000", "URL this service is accessible at")
|
||||
listenAddr := flag.String("listen-addr", ":4000", "Address to listen for HTTP requests on")
|
||||
dataDir := flag.String("data-dir", ".", "Directory to use for long term storage")
|
||||
|
||||
@ -55,6 +55,11 @@ func main() {
|
||||
logger.Fatal(context.Background(), "-ml-smtp-auth is required")
|
||||
}
|
||||
|
||||
publicURL, err := url.Parse(*publicURLStr)
|
||||
if err != nil {
|
||||
loggerFatalErr(context.Background(), logger, "parsing -public-url", err)
|
||||
}
|
||||
|
||||
var staticProxyURL *url.URL
|
||||
if *staticProxyURLStr != "" {
|
||||
var err error
|
||||
@ -79,7 +84,7 @@ func main() {
|
||||
// initialization
|
||||
|
||||
ctx := mctx.Annotate(context.Background(),
|
||||
"hostname", *hostname,
|
||||
"publicURL", publicURL.String(),
|
||||
"listenAddr", *listenAddr,
|
||||
"dataDir", *dataDir,
|
||||
"powTarget", fmt.Sprintf("%x", powTarget),
|
||||
@ -124,8 +129,8 @@ func main() {
|
||||
Store: mlStore,
|
||||
Mailer: mailer,
|
||||
Clock: clock,
|
||||
FinalizeSubURL: *hostname + "/mailinglist/finalize.html",
|
||||
UnsubURL: *hostname + "/mailinglist/unsubscribe.html",
|
||||
FinalizeSubURL: path.Join(publicURL.String(), "/mailinglist/finalize.html"),
|
||||
UnsubURL: path.Join(publicURL.String(), "/mailinglist/unsubscribe.html"),
|
||||
})
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
var (
|
||||
// ErrNotFound is used to indicate an email could not be found in the
|
||||
// database.
|
||||
ErrNotFound = errors.New("no record for given email found")
|
||||
ErrNotFound = errors.New("no record found")
|
||||
)
|
||||
|
||||
// EmailIterator will iterate through a sequence of emails, returning the next
|
||||
|
53
static/src/mailinglist/finalize.md
Normal file
53
static/src/mailinglist/finalize.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
layout: page
|
||||
title: ""
|
||||
nofollow: true
|
||||
---
|
||||
|
||||
<style>
|
||||
#result.success { color: green; }
|
||||
#result.fail { color: red; }
|
||||
</style>
|
||||
|
||||
<span id="result"></span>
|
||||
|
||||
<script>
|
||||
|
||||
(async () => {
|
||||
const resultSpan = document.getElementById("result");
|
||||
|
||||
function setErr(errStr) {
|
||||
resultSpan.className = "fail";
|
||||
resultSpan.innerHTML = errStr;
|
||||
}
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const subToken = urlParams.get('subToken');
|
||||
|
||||
if (!subToken) {
|
||||
setErr("No subscription token provided");
|
||||
return;
|
||||
}
|
||||
|
||||
const finalizeForm = new FormData();
|
||||
finalizeForm.append('subToken', subToken);
|
||||
|
||||
const finalizeReq = new Request('/api/mailinglist/finalize', {
|
||||
method: 'POST',
|
||||
body: finalizeForm,
|
||||
});
|
||||
|
||||
const res = await fetch(finalizeReq)
|
||||
.then(response => response.json());
|
||||
|
||||
if (res.error) {
|
||||
setErr(res.error);
|
||||
return;
|
||||
}
|
||||
|
||||
resultSpan.className = "success";
|
||||
resultSpan.innerHTML = "Your email subscription has been finalized! Please go on about your day.";
|
||||
|
||||
})();
|
||||
|
||||
</script>
|
54
static/src/mailinglist/unsubscribe.md
Normal file
54
static/src/mailinglist/unsubscribe.md
Normal file
@ -0,0 +1,54 @@
|
||||
---
|
||||
layout: page
|
||||
title: ""
|
||||
nofollow: true
|
||||
---
|
||||
|
||||
<style>
|
||||
#result.success { color: green; }
|
||||
#result.fail { color: red; }
|
||||
</style>
|
||||
|
||||
<span id="result"></span>
|
||||
|
||||
<script>
|
||||
|
||||
(async () => {
|
||||
const resultSpan = document.getElementById("result");
|
||||
|
||||
function setErr(errStr) {
|
||||
resultSpan.className = "fail";
|
||||
resultSpan.innerHTML = errStr;
|
||||
}
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const unsubToken = urlParams.get('unsubToken');
|
||||
|
||||
if (!unsubToken) {
|
||||
setErr("No unsubscribe token provided");
|
||||
return;
|
||||
}
|
||||
|
||||
const unsubscribeForm = new FormData();
|
||||
unsubscribeForm.append('unsubToken', unsubToken);
|
||||
|
||||
const unsubscribeReq = new Request('/api/mailinglist/unsubscribe', {
|
||||
method: 'POST',
|
||||
body: unsubscribeForm,
|
||||
});
|
||||
|
||||
const res = await fetch(unsubscribeReq)
|
||||
.then(response => response.json());
|
||||
|
||||
if (res.error) {
|
||||
setErr(res.error);
|
||||
return;
|
||||
}
|
||||
|
||||
resultSpan.className = "success";
|
||||
resultSpan.innerHTML = "You have been unsubscribed! Please go on about your day.";
|
||||
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user