forked from wgroeneveld/go-jamming
also notify when received from whitelist
This commit is contained in:
parent
bf018eafe8
commit
45ff736001
|
@ -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?")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -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`)
|
||||||
|
|
|
@ -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: ¬ifier.MailNotifier{
|
||||||
if len(conf.AdminEmail) > 0 {
|
|
||||||
recv.Notifier = ¬ifier.MailNotifier{
|
|
||||||
Conf: conf,
|
Conf: conf,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
go recv.Receive(wm)
|
go recv.Receive(wm)
|
||||||
|
|
|
@ -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.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue