also notify when received from whitelist

This commit is contained in:
Wouter Groeneveld 2022-04-28 09:28:16 +02:00
parent bf018eafe8
commit 45ff736001
8 changed files with 104 additions and 31 deletions

View File

@ -4,7 +4,7 @@ import (
"brainbaking.com/go-jamming/app/mf" "brainbaking.com/go-jamming/app/mf"
"brainbaking.com/go-jamming/common" "brainbaking.com/go-jamming/common"
"encoding/base64" "encoding/base64"
"github.com/rs/zerolog/log" "fmt"
"net/mail" "net/mail"
"net/smtp" "net/smtp"
) )
@ -53,15 +53,28 @@ func sendMail(from, subject, body, toName, toAddress string) error {
return c.Quit() return c.Quit()
} }
func (mn *MailNotifier) NotifyReceived(wm mf.Mention, indieweb *mf.IndiewebData) { func (mn *MailNotifier) NotifyReceived(wm mf.Mention, indieweb *mf.IndiewebData) error {
err := sendMail( if len(mn.Conf.AdminEmail) == 0 {
return fmt.Errorf("no adminEmail provided")
}
return sendMail(
mn.Conf.AdminEmail, mn.Conf.AdminEmail,
"Webmention in moderation from "+wm.SourceDomain(), "Webmention received from "+wm.SourceDomain(),
BuildNotification(wm, indieweb, mn.Conf), buildReceivedMsg(wm, indieweb, mn.Conf),
"Go-Jamming User",
mn.Conf.AdminEmail)
}
func (mn *MailNotifier) NotifyInModeration(wm mf.Mention, indieweb *mf.IndiewebData) error {
if len(mn.Conf.AdminEmail) == 0 {
return fmt.Errorf("no adminEmail provided")
}
return sendMail(
mn.Conf.AdminEmail,
"Webmention in moderation from "+wm.SourceDomain(),
buildInModerationMsg(wm, indieweb, mn.Conf),
"Go-Jamming User", "Go-Jamming User",
mn.Conf.AdminEmail) mn.Conf.AdminEmail)
if err != nil {
log.Err(err).Msg("Unable to send notification mail, check localhost postfix settings?")
}
} }

View File

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Webmention in moderation from {{ .SourceDomain }}</title> <title>Webmention {{ .Action }} from {{ .SourceDomain }}</title>
<style> <style>
body { body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
@ -12,7 +12,7 @@
</head> </head>
<body> <body>
<h1>🥞 Webmention in moderation from {{ .SourceDomain }}</h1> <h1>🥞 Webmention {{ .Action }} from {{ .SourceDomain }}</h1>
<p>Hi Admin, a webmention was received:</p> <p>Hi Admin, a webmention was received:</p>
@ -23,8 +23,8 @@
</p> </p>
<p> <p>
<a href="{{ .ApproveURL }}">✅ Accept!</a><br/> {{ with .ApproveURL}}<a href="{{ . }}">✅ Accept!</a><br/>{{ end }}
<a href="{{ .RejectURL }}">❌ Reject!</a> {{ with .RejectURL }}<a href="{{ . }}">❌ Reject!</a>{{ end }}
</p> </p>
<p> <p>

View File

@ -24,6 +24,7 @@ func init() {
} }
type notificationData struct { type notificationData struct {
Action string
SourceDomain string SourceDomain string
Source string Source string
Content string Content string
@ -34,17 +35,34 @@ type notificationData struct {
} }
type Notifier interface { type Notifier interface {
NotifyReceived(wm mf.Mention, data *mf.IndiewebData) NotifyInModeration(wm mf.Mention, data *mf.IndiewebData) error
NotifyReceived(wm mf.Mention, data *mf.IndiewebData) error
} }
// BuildNotification returns a HTML (string template) representation of the Mention to notify the admin. // buildReceivedMsg returns a HTML (string template) representation of the approved mention to notify the admin.
func BuildNotification(wm mf.Mention, data *mf.IndiewebData, cnf *common.Config) string { func buildReceivedMsg(wm mf.Mention, data *mf.IndiewebData, cnf *common.Config) string {
acceptUrl := fmt.Sprintf("%sadmin/approve/%s/%s", cnf.BaseURL, cnf.Token, wm.Key()) adminUrl := adminUrl(cnf)
rejectUrl := fmt.Sprintf("%sadmin/reject/%s/%s", cnf.BaseURL, cnf.Token, wm.Key()) var buff bytes.Buffer
adminUrl := fmt.Sprintf("%sadmin/%s", cnf.BaseURL, cnf.Token) notificationTmpl.Execute(&buff, notificationData{
Action: "approved",
Source: wm.Source,
Target: wm.Target,
Content: data.Content,
SourceDomain: wm.SourceDomain(),
AdminURL: adminUrl,
})
return buff.String()
}
// buildInModerationMsg returns a HTML (string template) representation of the in moderation mention to notify the admin.
func buildInModerationMsg(wm mf.Mention, data *mf.IndiewebData, cnf *common.Config) string {
acceptUrl := acceptUrl(wm, cnf)
rejectUrl := rejectUrl(wm, cnf)
adminUrl := adminUrl(cnf)
var buff bytes.Buffer var buff bytes.Buffer
notificationTmpl.Execute(&buff, notificationData{ notificationTmpl.Execute(&buff, notificationData{
Action: "in moderation",
Source: wm.Source, Source: wm.Source,
Target: wm.Target, Target: wm.Target,
Content: data.Content, Content: data.Content,
@ -55,3 +73,15 @@ func BuildNotification(wm mf.Mention, data *mf.IndiewebData, cnf *common.Config)
}) })
return buff.String() return buff.String()
} }
func rejectUrl(wm mf.Mention, cnf *common.Config) string {
return fmt.Sprintf("%sadmin/reject/%s/%s", cnf.BaseURL, cnf.Token, wm.Key())
}
func acceptUrl(wm mf.Mention, cnf *common.Config) string {
return fmt.Sprintf("%sadmin/approve/%s/%s", cnf.BaseURL, cnf.Token, wm.Key())
}
func adminUrl(cnf *common.Config) string {
return fmt.Sprintf("%sadmin/%s", cnf.BaseURL, cnf.Token)
}

View File

@ -7,7 +7,7 @@ import (
"testing" "testing"
) )
func TestBuildNotification(t *testing.T) { func TestBuildReceivedMsgDoesNotContainApproveLink(t *testing.T) {
wm := mf.Mention{ wm := mf.Mention{
Source: "https://brainbaking.com/valid-indieweb-source.html", Source: "https://brainbaking.com/valid-indieweb-source.html",
Target: "https://brainbaking.com/valid-indieweb-target.html", Target: "https://brainbaking.com/valid-indieweb-target.html",
@ -22,7 +22,30 @@ func TestBuildNotification(t *testing.T) {
Whitelist: []string{}, Whitelist: []string{},
} }
result := BuildNotification(wm, &mf.IndiewebData{Content: "somecontent"}, cnf) result := buildReceivedMsg(wm, &mf.IndiewebData{Content: "somecontent"}, cnf)
assert.Contains(t, result, `Webmention approved from`)
assert.Contains(t, result, `<em>Source:</em> <a href="https://brainbaking.com/valid-indieweb-source.html">https://brainbaking.com/valid-indieweb-source.html</a><br/>`)
assert.Contains(t, result, `<em>Target:</em> <a href="https://brainbaking.com/valid-indieweb-target.html">https://brainbaking.com/valid-indieweb-target.html</a><br/>`)
assert.NotContains(t, result, `<a href="https://jam.brainbaking.com/admin/approve/mytoken/19d462ddff3c3322c662dac3461324bb:brainbaking.com`)
}
func TestBuildInModerationMsgContainsApproveLink(t *testing.T) {
wm := mf.Mention{
Source: "https://brainbaking.com/valid-indieweb-source.html",
Target: "https://brainbaking.com/valid-indieweb-target.html",
}
cnf := &common.Config{
AllowedWebmentionSources: []string{
"brainbaking.com",
},
BaseURL: "https://jam.brainbaking.com/",
Token: "mytoken",
Blacklist: []string{},
Whitelist: []string{},
}
result := buildInModerationMsg(wm, &mf.IndiewebData{Content: "somecontent"}, cnf)
assert.Contains(t, result, `Webmention in moderation from`)
assert.Contains(t, result, `<em>Source:</em> <a href="https://brainbaking.com/valid-indieweb-source.html">https://brainbaking.com/valid-indieweb-source.html</a><br/>`) assert.Contains(t, result, `<em>Source:</em> <a href="https://brainbaking.com/valid-indieweb-source.html">https://brainbaking.com/valid-indieweb-source.html</a><br/>`)
assert.Contains(t, result, `<em>Target:</em> <a href="https://brainbaking.com/valid-indieweb-target.html">https://brainbaking.com/valid-indieweb-target.html</a><br/>`) assert.Contains(t, result, `<em>Target:</em> <a href="https://brainbaking.com/valid-indieweb-target.html">https://brainbaking.com/valid-indieweb-target.html</a><br/>`)
assert.Contains(t, result, `<a href="https://jam.brainbaking.com/admin/approve/mytoken/19d462ddff3c3322c662dac3461324bb:brainbaking.com`) assert.Contains(t, result, `<a href="https://jam.brainbaking.com/admin/approve/mytoken/19d462ddff3c3322c662dac3461324bb:brainbaking.com`)

View File

@ -89,11 +89,9 @@ func HandlePost(conf *common.Config, repo db.MentionRepo) http.HandlerFunc {
RestClient: httpClient, RestClient: httpClient,
Conf: conf, Conf: conf,
Repo: repo, Repo: repo,
} Notifier: &notifier.MailNotifier{
if len(conf.AdminEmail) > 0 {
recv.Notifier = &notifier.MailNotifier{
Conf: conf, Conf: conf,
} },
} }
go recv.Receive(wm) go recv.Receive(wm)

View File

@ -76,8 +76,9 @@ func (recv *Receiver) processMentionInModeration(wm mf.Mention, indieweb *mf.Ind
if err != nil { if err != nil {
log.Error().Err(err).Stringer("wm", wm).Msg("Failed to save new mention to in moderation db") log.Error().Err(err).Stringer("wm", wm).Msg("Failed to save new mention to in moderation db")
} }
if recv.Notifier != nil { err = recv.Notifier.NotifyInModeration(wm, indieweb)
recv.Notifier.NotifyReceived(wm, indieweb) if err != nil {
log.Error().Err(err).Msg("Failed to notify")
} }
log.Info().Str("key", key).Msg("OK: Webmention processed, in moderation.") log.Info().Str("key", key).Msg("OK: Webmention processed, in moderation.")
} }
@ -87,6 +88,10 @@ func (recv *Receiver) processWhitelistedMention(wm mf.Mention, indieweb *mf.Indi
if err != nil { if err != nil {
log.Error().Err(err).Stringer("wm", wm).Msg("Failed to save new mention to db") log.Error().Err(err).Stringer("wm", wm).Msg("Failed to save new mention to db")
} }
err = recv.Notifier.NotifyReceived(wm, indieweb)
if err != nil {
log.Error().Err(err).Msg("Failed to notify")
}
log.Info().Str("key", key).Msg("OK: Webmention processed, in whitelist.") log.Info().Str("key", key).Msg("OK: Webmention processed, in whitelist.")
} }

View File

@ -269,7 +269,7 @@ func TestReceiveFromNotInWhitelistSavesInModerationAndNotifies(t *testing.T) {
receiver.Receive(wm) receiver.Receive(wm)
assert.Empty(t, repo.GetAll("brainbaking.com").Data) assert.Empty(t, repo.GetAll("brainbaking.com").Data)
assert.Equal(t, 1, len(repo.GetAllToModerate("brainbaking.com").Data)) assert.Equal(t, 1, len(repo.GetAllToModerate("brainbaking.com").Data))
assert.Contains(t, notifierMock.Output, "✅ Accept!") assert.Contains(t, notifierMock.Output, "in moderation!")
} }
func TestReceiveFromBlacklistedDomainDoesNothing(t *testing.T) { func TestReceiveFromBlacklistedDomainDoesNothing(t *testing.T) {

View File

@ -2,7 +2,6 @@ package mocks
import ( import (
"brainbaking.com/go-jamming/app/mf" "brainbaking.com/go-jamming/app/mf"
"brainbaking.com/go-jamming/app/notifier"
"brainbaking.com/go-jamming/common" "brainbaking.com/go-jamming/common"
) )
@ -11,6 +10,11 @@ type StringNotifier struct {
Conf *common.Config Conf *common.Config
} }
func (sn *StringNotifier) NotifyReceived(wm mf.Mention, indieweb *mf.IndiewebData) { func (sn *StringNotifier) NotifyInModeration(wm mf.Mention, data *mf.IndiewebData) error {
sn.Output = notifier.BuildNotification(wm, indieweb, sn.Conf) sn.Output = "in moderation!"
return nil
}
func (sn *StringNotifier) NotifyReceived(wm mf.Mention, data *mf.IndiewebData) error {
sn.Output = "received!"
return nil
} }