diff --git a/app/pingback/handler.go b/app/pingback/handler.go
index 7ef3272..794a80f 100644
--- a/app/pingback/handler.go
+++ b/app/pingback/handler.go
@@ -2,13 +2,102 @@
package pingback
import (
+ "encoding/xml"
+ "github.com/rs/zerolog/log"
+ "github.com/wgroeneveld/go-jamming/app/webmention"
+ "github.com/wgroeneveld/go-jamming/rest"
+ "io/ioutil"
"net/http"
+ "text/template"
"github.com/wgroeneveld/go-jamming/common"
)
-func Handle(conf *common.Config) http.HandlerFunc {
+func HandlePost(conf *common.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
- }
+ body, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ pingbackError(w, "Unable to read request body")
+ }
+ rpc := &XmlRPCMethodCall{}
+ err = xml.Unmarshal(body, rpc)
+ if err != nil {
+ pingbackError(w, "Unable to unmarshal XMLRPC request body")
+ }
+
+ if !validate(rpc, conf) {
+ pingbackError(w, "malformed pingback request")
+ return
+ }
+
+ wm := webmention.Mention{
+ Source: rpc.Source(),
+ Target: rpc.Target(),
+ }
+ receiver := webmention.Receiver{
+ RestClient: &rest.HttpClient{},
+ Conf: conf,
+ }
+ go receiver.Receive(wm)
+ pingbackSuccess(w, "Thanks, bro. Will process this soon, pinky swear!")
+ }
}
+var successXml = `
+
+
+
+
+
+ {{ . }}
+
+
+
+
+
+`
+// compile once, execute as many times as needed.
+var successTpl, _ = template.New("success").Parse(successXml)
+
+func pingbackSuccess(w http.ResponseWriter, msg string) {
+ w.WriteHeader(200)
+ successTpl.Execute(w, msg)
+}
+
+// according to the XML-RPC spec, always return a 200, but encode it into the XML.
+func pingbackError(w http.ResponseWriter, msg string) {
+ xml := `
+
+
+
+
+
+
+ faultCode
+
+
+
+ 0
+
+
+
+
+
+ faultString
+
+
+
+ Sorry pal. Malformed request? Or something else, who knows...
+
+
+
+
+
+
+`
+ log.Error().Str("msg", msg).Msg("Pingback receive went wrong")
+ w.WriteHeader(200)
+ w.Write([]byte(xml))
+}
+
+
diff --git a/app/pingback/validate.go b/app/pingback/validate.go
new file mode 100644
index 0000000..a1f3aa1
--- /dev/null
+++ b/app/pingback/validate.go
@@ -0,0 +1,34 @@
+package pingback
+
+import (
+ "github.com/wgroeneveld/go-jamming/common"
+ "strings"
+)
+
+func validate(rpc *XmlRPCMethodCall, conf *common.Config) bool {
+ if rpc.MethodName != "pingback.ping" {
+ return false
+ }
+ if len(rpc.Params.Parameters) != 2 {
+ return false
+ }
+
+ target := rpc.Target()
+ if !strings.HasPrefix(target, "http") {
+ return false
+ }
+ _, err := conf.FetchDomain(target)
+ if err != nil {
+ return false
+ }
+
+ source := rpc.Source()
+ if !strings.HasPrefix(source, "http") {
+ return false
+ }
+
+ if source == target {
+ return false
+ }
+ return true
+}
diff --git a/app/pingback/validate_test.go b/app/pingback/validate_test.go
new file mode 100644
index 0000000..945b0e4
--- /dev/null
+++ b/app/pingback/validate_test.go
@@ -0,0 +1,178 @@
+package pingback
+
+import (
+ "encoding/xml"
+ "github.com/stretchr/testify/assert"
+ "github.com/wgroeneveld/go-jamming/common"
+ "testing"
+)
+
+var conf *common.Config = &common.Config{
+ AllowedWebmentionSources: []string{
+ "brainbaking.com",
+ "jefklakscodex.com",
+ },
+}
+
+func TestValidate(t *testing.T) {
+ cases := []struct {
+ label string
+ xml string
+ expected bool
+ }{
+ {
+ "not valid if methodName is not pingback.ping",
+ `
+
+
+ ka.tsjing
+
+
+ https://cool.site
+
+
+ https://brainbaking.com/post/2021/03/cool-ness
+
+
+
+ `,
+ false,
+ },
+ {
+ "not valid if less than two parameters",
+ `
+
+
+ pingback.ping
+
+
+ https://brainbaking.com/post/2021/03/cool-ness
+
+
+
+ `,
+ false,
+ },
+ {
+ "not valid if more than two parameters",
+ `
+
+ pingback.ping
+
+
+ https://cool.site
+
+
+ https://brainbaking.com/post/2021/03/cool-ness
+
+
+ https://brainbaking.com/post/2021/03/cool-ness
+
+
+
+ `,
+ false,
+ },
+ {
+ "not valid if target is not in trusted domains from config",
+ `
+
+
+ pingback.ping
+
+
+ https://cool.site
+
+
+ https://flashballz.com/post/2021/03/cool-ness
+
+
+
+ `,
+ false,
+ },
+ {
+ "not valid if target is not http(s)",
+ `
+
+
+ pingback.ping
+
+
+ https://cool.site
+
+
+ gemini://brainbaking.com/post/2021/03/cool-ness
+
+
+
+ `,
+ false,
+ },
+ {
+ "not valid if source is not http(s)",
+ `
+
+
+ pingback.ping
+
+
+ gemini://cool.site
+
+
+ https://brainbaking.com/post/2021/03/cool-ness
+
+
+
+ `,
+ false,
+ },
+ {
+ "is valid if pingback.ping and two http(s) parameters of which target is trusted",
+ `
+
+
+ pingback.ping
+
+
+ https://cool.site
+
+
+ https://brainbaking.com/post/2021/03/cool-ness
+
+
+
+ `,
+ true,
+ },
+ {
+ "is not valid if source and target are the same urls",
+ `
+
+
+ pingback.ping
+
+
+ https://brainbaking.com/post/2021/03/cool-ness
+
+
+ https://brainbaking.com/post/2021/03/cool-ness
+
+
+
+ `,
+ false,
+ },
+ }
+
+ for _, tc := range cases {
+ t.Run(tc.label, func(t *testing.T) {
+ var xmlObj XmlRPCMethodCall
+ err := xml.Unmarshal([]byte(tc.xml), &xmlObj)
+ assert.NoError(t, err, "XML invalid in test case")
+
+ result := validate(&xmlObj, conf)
+ assert.Equal(t, tc.expected, result)
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/pingback/xmlrpc.go b/app/pingback/xmlrpc.go
new file mode 100644
index 0000000..86be6e0
--- /dev/null
+++ b/app/pingback/xmlrpc.go
@@ -0,0 +1,45 @@
+package pingback
+
+import "encoding/xml"
+
+/* e.g. (see tests)
+
+
+ pingback.ping
+
+
+ https://brainbaking.com/kristien.html
+
+
+ https://kristienthoelen.be/2021/03/22/de-stadia-van-een-burn-out-in-welk-stadium-zit-jij/
+
+
+
+ */
+type XmlRPCMethodCall struct {
+ XMLName xml.Name `xml:"methodCall"`
+ MethodName string `xml:"methodName"`
+ Params XmlRPCParams `xml:"params"`
+}
+
+func (rpc *XmlRPCMethodCall) Source() string {
+ return rpc.Params.Parameters[0].Value.String
+}
+
+func (rpc *XmlRPCMethodCall) Target() string {
+ return rpc.Params.Parameters[1].Value.String
+}
+
+type XmlRPCParams struct {
+ XMLName xml.Name `xml:"params"`
+ Parameters []XmlRPCParam `xml:"param"`
+}
+
+type XmlRPCParam struct {
+ XMLName xml.Name `xml:"param"`
+ Value XmlRPCValue `xml:"value"`
+}
+
+type XmlRPCValue struct {
+ String string `xml:"string"`
+}
\ No newline at end of file
diff --git a/app/pingback/xmlrpc_test.go b/app/pingback/xmlrpc_test.go
new file mode 100644
index 0000000..f46b987
--- /dev/null
+++ b/app/pingback/xmlrpc_test.go
@@ -0,0 +1,30 @@
+package pingback
+
+import (
+ "encoding/xml"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+// See https://www.hixie.ch/specs/pingback/pingback#refsXMLRPC
+func TestMarshallValidXMLRPC(t *testing.T) {
+ xmlString := `
+
+ pingback.ping
+
+
+ https://brainbaking.com/kristien.html
+
+
+ https://kristienthoelen.be/2021/03/22/de-stadia-van-een-burn-out-in-welk-stadium-zit-jij/
+
+
+`
+ var rpc XmlRPCMethodCall
+ err := xml.Unmarshal([]byte(xmlString), &rpc)
+
+ assert.NoError(t, err)
+ assert.Equal(t, "pingback.ping", rpc.MethodName)
+ assert.Equal(t, "https://brainbaking.com/kristien.html", rpc.Params.Parameters[0].Value.String)
+ assert.Equal(t, "https://kristienthoelen.be/2021/03/22/de-stadia-van-een-burn-out-in-welk-stadium-zit-jij/", rpc.Params.Parameters[1].Value.String)
+}
\ No newline at end of file
diff --git a/app/routes.go b/app/routes.go
index 3084d5f..1e4118f 100644
--- a/app/routes.go
+++ b/app/routes.go
@@ -12,7 +12,7 @@ import (
// https://blog.questionable.services/article/http-handler-error-handling-revisited/ is the better idea, but more work
func (s *server) routes() {
s.router.HandleFunc("/", index.Handle(s.conf)).Methods("GET")
- s.router.HandleFunc("/pingback", pingback.Handle(s.conf)).Methods("POST")
+ s.router.HandleFunc("/pingback", pingback.HandlePost(s.conf)).Methods("POST")
s.router.HandleFunc("/webmention", webmention.HandlePost(s.conf)).Methods("POST")
s.router.HandleFunc("/webmention/{domain}/{token}", s.authorizedOnly(webmention.HandleGet(s.conf))).Methods("GET")
s.router.HandleFunc("/webmention/{domain}/{token}", s.authorizedOnly(webmention.HandlePut(s.conf))).Methods("PUT")
diff --git a/app/webmention/handler.go b/app/webmention/handler.go
index a078ee3..532ad70 100644
--- a/app/webmention/handler.go
+++ b/app/webmention/handler.go
@@ -37,16 +37,16 @@ func HandlePost(conf *common.Config) http.HandlerFunc {
return
}
- wm := webmention{
- source: r.FormValue("source"),
- target: target,
+ wm := Mention{
+ Source: r.FormValue("source"),
+ Target: target,
}
- recv := &receiver{
- restClient: httpClient,
- conf: conf,
+ recv := &Receiver{
+ RestClient: httpClient,
+ Conf: conf,
}
- go recv.receive(wm)
+ go recv.Receive(wm)
rest.Accept(w)
}
}
diff --git a/app/webmention/microformats.go b/app/webmention/microformats.go
index 176ae9b..bc2d7fe 100644
--- a/app/webmention/microformats.go
+++ b/app/webmention/microformats.go
@@ -1,6 +1,7 @@
package webmention
import (
+ "strings"
"time"
"willnorris.com/go/microformats"
)
@@ -80,3 +81,57 @@ func mfProp(mf *microformats.Microformat, key string) *microformats.Microformat
}
return val[0].(*microformats.Microformat)
}
+
+func determinePublishedDate(hEntry *microformats.Microformat, utcOffset int) string {
+ publishedDate := mfStr(hEntry, "published")
+ if publishedDate == "" {
+ return publishedNow(utcOffset)
+ }
+ return publishedDate
+}
+
+func determineAuthorName(hEntry *microformats.Microformat) string {
+ authorName := mfStr(mfProp(hEntry, "author"), "name")
+ if authorName == "" {
+ return mfProp(hEntry, "author").Value
+ }
+ return authorName
+}
+
+func determineMfType(hEntry *microformats.Microformat) string {
+ likeOf := mfStr(hEntry, "like-of")
+ if likeOf != "" {
+ return "like"
+ }
+ bookmarkOf := mfStr(hEntry, "bookmark-of")
+ if bookmarkOf != "" {
+ return "bookmark"
+ }
+ return "mention"
+}
+
+// Mastodon uids start with "tag:server", but we do want indieweb uids from other sources
+func determineUrl(hEntry *microformats.Microformat, source string) string {
+ uid := mfStr(hEntry, "uid")
+ if uid != "" && strings.HasPrefix(uid, "http") {
+ return uid
+ }
+ url := mfStr(hEntry, "url")
+ if url != "" {
+ return url
+ }
+ return source
+}
+
+func determineContent(hEntry *microformats.Microformat) string {
+ bridgyTwitterContent := mfStr(hEntry, "bridgy-twitter-content")
+ if bridgyTwitterContent != "" {
+ return shorten(bridgyTwitterContent)
+ }
+ summary := mfStr(hEntry, "summary")
+ if summary != "" {
+ return shorten(summary)
+ }
+ contentEntry := mfMap(hEntry, "content")["value"]
+ return shorten(contentEntry)
+}
\ No newline at end of file
diff --git a/app/webmention/receive.go b/app/webmention/receive.go
index 8d75a73..93e2433 100644
--- a/app/webmention/receive.go
+++ b/app/webmention/receive.go
@@ -18,39 +18,39 @@ import (
"willnorris.com/go/microformats"
)
-type webmention struct {
- source string
- target string
+type Mention struct {
+ Source string
+ Target string
}
-func (wm *webmention) String() string {
- return fmt.Sprintf("source: %s, target: %s", wm.source, wm.target)
+func (wm *Mention) String() string {
+ return fmt.Sprintf("source: %s, target: %s", wm.Source, wm.Target)
}
-func (wm *webmention) asPath(conf *common.Config) string {
- filename := fmt.Sprintf("%x", md5.Sum([]byte("source=" + wm.source + ",target=" + wm.target)))
- domain, _ := conf.FetchDomain(wm.target)
+func (wm *Mention) asPath(conf *common.Config) string {
+ filename := fmt.Sprintf("%x", md5.Sum([]byte("source=" + wm.Source+ ",target=" + wm.Target)))
+ domain, _ := conf.FetchDomain(wm.Target)
return conf.DataPath + "/" + domain + "/" + filename + ".json"
}
-func (wm *webmention) sourceUrl() *url.URL {
- url, _ := url.Parse(wm.source)
+func (wm *Mention) sourceUrl() *url.URL {
+ url, _ := url.Parse(wm.Source)
return url
}
// used as a "class" to iject dependencies, just to be able to test. Do NOT like htis.
// Is there a better way? e.g. in validate, I just pass rest.Client as an arg. Not great either.
-type receiver struct {
- restClient rest.Client
- conf *common.Config
+type Receiver struct {
+ RestClient rest.Client
+ Conf *common.Config
}
-func (recv *receiver) receive(wm webmention) {
- log.Info().Str("webmention", wm.String()).Msg("OK: looks valid")
- body, geterr := recv.restClient.GetBody(wm.source)
+func (recv *Receiver) Receive(wm Mention) {
+ log.Info().Str("Webmention", wm.String()).Msg("OK: looks valid")
+ body, geterr := recv.RestClient.GetBody(wm.Source)
if geterr != nil {
- log.Warn().Str("source", wm.source).Msg(" ABORT: invalid url")
+ log.Warn().Str("source", wm.Source).Msg(" ABORT: invalid url")
recv.deletePossibleOlderWebmention(wm)
return
}
@@ -58,8 +58,8 @@ func (recv *receiver) receive(wm webmention) {
recv.processSourceBody(body, wm)
}
-func (recv *receiver) deletePossibleOlderWebmention(wm webmention) {
- os.Remove(wm.asPath(recv.conf))
+func (recv *Receiver) deletePossibleOlderWebmention(wm Mention) {
+ os.Remove(wm.asPath(recv.Conf))
}
func getHEntry(data *microformats.Data) *microformats.Microformat {
@@ -72,40 +72,40 @@ func getHEntry(data *microformats.Data) *microformats.Microformat {
}
-func (recv *receiver) processSourceBody(body string, wm webmention) {
- if !strings.Contains(body, wm.target) {
- log.Warn().Str("target", wm.target).Msg("ABORT: no mention of target found in html src of source!")
+func (recv *Receiver) processSourceBody(body string, wm Mention) {
+ if !strings.Contains(body, wm.Target) {
+ log.Warn().Str("target", wm.Target).Msg("ABORT: no mention of target found in html src of source!")
return
}
- r := strings.NewReader(body)
- data := microformats.Parse(r, wm.sourceUrl())
- hEntry := getHEntry(data)
- var indieweb *indiewebData
- if hEntry == nil {
- indieweb = recv.parseBodyAsNonIndiewebSite(body, wm)
- } else {
- indieweb = recv.parseBodyAsIndiewebSite(hEntry, wm)
- }
-
+ data := microformats.Parse(strings.NewReader(body), wm.sourceUrl())
+ indieweb := recv.convertBodyToIndiewebData(body, wm, getHEntry(data))
+
recv.saveWebmentionToDisk(wm, indieweb)
- log.Info().Str("file", wm.asPath(recv.conf)).Msg("OK: webmention processed.")
+ log.Info().Str("file", wm.asPath(recv.Conf)).Msg("OK: Webmention processed.")
}
-func (recv *receiver) saveWebmentionToDisk(wm webmention, indieweb *indiewebData) {
+func (recv *Receiver) convertBodyToIndiewebData(body string, wm Mention, hEntry *microformats.Microformat) *indiewebData {
+ if hEntry == nil {
+ return recv.parseBodyAsNonIndiewebSite(body, wm)
+ }
+ return recv.parseBodyAsIndiewebSite(hEntry, wm)
+}
+
+func (recv *Receiver) saveWebmentionToDisk(wm Mention, indieweb *indiewebData) {
jsonData, jsonErr := json.Marshal(indieweb)
if jsonErr != nil {
- log.Err(jsonErr).Msg("Unable to serialize webmention into JSON")
+ log.Err(jsonErr).Msg("Unable to serialize Webmention into JSON")
}
- err := ioutil.WriteFile(wm.asPath(recv.conf), jsonData, fs.ModePerm)
+ err := ioutil.WriteFile(wm.asPath(recv.Conf), jsonData, fs.ModePerm)
if err != nil {
- log.Err(err).Msg("Unable to save webmention to disk")
+ log.Err(err).Msg("Unable to save Webmention to disk")
}
}
// TODO I'm smelling very unstable code, apply https://golang.org/doc/effective_go#recover here?
// see https://github.com/willnorris/microformats/blob/main/microformats.go
-func (recv *receiver) parseBodyAsIndiewebSite(hEntry *microformats.Microformat, wm webmention) *indiewebData {
+func (recv *Receiver) parseBodyAsIndiewebSite(hEntry *microformats.Microformat, wm Mention) *indiewebData {
name := mfStr(hEntry, "name")
pic := mfStr(mfProp(hEntry, "author"), "photo")
mfType := determineMfType(hEntry)
@@ -117,85 +117,31 @@ func (recv *receiver) parseBodyAsIndiewebSite(hEntry *microformats.Microformat,
Picture: pic,
},
Content: determineContent(hEntry),
- Url: determineUrl(hEntry, wm.source),
- Published: determinePublishedDate(hEntry, recv.conf.UtcOffset),
- Source: wm.source,
- Target: wm.target,
+ Url: determineUrl(hEntry, wm.Source),
+ Published: determinePublishedDate(hEntry, recv.Conf.UtcOffset),
+ Source: wm.Source,
+ Target: wm.Target,
IndiewebType: mfType,
}
}
-func determinePublishedDate(hEntry *microformats.Microformat, utcOffset int) string {
- publishedDate := mfStr(hEntry, "published")
- if publishedDate == "" {
- return publishedNow(utcOffset)
- }
- return publishedDate
-}
-
-func determineAuthorName(hEntry *microformats.Microformat) string {
- authorName := mfStr(mfProp(hEntry, "author"), "name")
- if authorName == "" {
- return mfProp(hEntry, "author").Value
- }
- return authorName
-}
-
-func determineMfType(hEntry *microformats.Microformat) string {
- likeOf := mfStr(hEntry, "like-of")
- if likeOf != "" {
- return "like"
- }
- bookmarkOf := mfStr(hEntry, "bookmark-of")
- if bookmarkOf != "" {
- return "bookmark"
- }
- return "mention"
-}
-
-// Mastodon uids start with "tag:server", but we do want indieweb uids from other sources
-func determineUrl(hEntry *microformats.Microformat, source string) string {
- uid := mfStr(hEntry, "uid")
- if uid != "" && strings.HasPrefix(uid, "http") {
- return uid
- }
- url := mfStr(hEntry, "url")
- if url != "" {
- return url
- }
- return source
-}
-
-func determineContent(hEntry *microformats.Microformat) string {
- bridgyTwitterContent := mfStr(hEntry, "bridgy-twitter-content")
- if bridgyTwitterContent != "" {
- return shorten(bridgyTwitterContent)
- }
- summary := mfStr(hEntry, "summary")
- if summary != "" {
- return shorten(summary)
- }
- contentEntry := mfMap(hEntry, "content")["value"]
- return shorten(contentEntry)
-}
-
-func (recv *receiver) parseBodyAsNonIndiewebSite(body string, wm webmention) *indiewebData {
+func (recv *Receiver) parseBodyAsNonIndiewebSite(body string, wm Mention) *indiewebData {
r := regexp.MustCompile(`
(.*?)<\/title>`)
titleMatch := r.FindStringSubmatch(body)
- title := wm.source
+ title := wm.Source
if titleMatch != nil {
title = titleMatch[1]
}
return &indiewebData{
Author: indiewebAuthor{
- Name: wm.source,
+ Name: wm.Source,
},
Name: title,
Content: title,
- Published: publishedNow(recv.conf.UtcOffset),
- Url: wm.source,
+ Published: publishedNow(recv.Conf.UtcOffset),
+ Url: wm.Source,
IndiewebType: "mention",
- Source: wm.source,
- Target: wm.target,
+ Source: wm.Source,
+ Target: wm.Target,
}
}
diff --git a/app/webmention/receive_test.go b/app/webmention/receive_test.go
index 4a61092..e9ea5a7 100644
--- a/app/webmention/receive_test.go
+++ b/app/webmention/receive_test.go
@@ -22,9 +22,9 @@ var conf = &common.Config{
func TestConvertWebmentionToPath(t *testing.T) {
- wm := webmention{
- source: "https://brainbaking.com",
- target: "https://jefklakscodex.com/articles",
+ wm := Mention{
+ Source: "https://brainbaking.com",
+ Target: "https://jefklakscodex.com/articles",
}
result := wm.asPath(conf)
@@ -42,56 +42,56 @@ func writeSomethingTo(filename string) {
func TestReceive(t *testing.T) {
cases := []struct {
label string
- wm webmention
- json string
+ wm Mention
+ json string
} {
{
- label: "receive a webmention bookmark via twitter",
- wm: webmention{
- source: "https://brainbaking.com/valid-bridgy-twitter-source.html",
- target: "https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag",
+ label: "receive a Webmention bookmark via twitter",
+ wm: Mention{
+ Source: "https://brainbaking.com/valid-bridgy-twitter-source.html",
+ Target: "https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag",
},
json: `{"author":{"name":"Jamie Tanna","picture":"https://www.jvt.me/img/profile.png"},"name":"","content":"Recommended read:\nThe IndieWeb Mixed Bag - Thoughts about the (d)evolution of blog interactions\nhttps://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/","published":"2021-03-15T12:42:00+0000","url":"https://brainbaking.com/mf2/2021/03/1bkre/","type":"bookmark","source":"https://brainbaking.com/valid-bridgy-twitter-source.html","target":"https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag"}`,
},
{
- label: "receive a brid.gy webmention like",
- wm: webmention{
- source: "https://brainbaking.com/valid-bridgy-like.html",
+ label: "receive a brid.gy Webmention like",
+ wm: Mention{
+ Source: "https://brainbaking.com/valid-bridgy-like.html",
// wrapped in a a class="u-like-of" tag
- target: "https://brainbaking.com/valid-indieweb-target.html",
+ Target: "https://brainbaking.com/valid-indieweb-target.html",
},
// no dates in bridgy-to-mastodon likes...
json: `{"author":{"name":"Stampeding Longhorn","picture":"https://cdn.social.linux.pizza/v1/AUTH_91eb37814936490c95da7b85993cc2ff/sociallinuxpizza/accounts/avatars/000/185/996/original/9e36da0c093cfc9b.png"},"name":"","content":"","published":"2020-01-01T12:30:00","url":"https://chat.brainbaking.com/notice/A4nx1rFwKUJYSe4TqK#favorited-by-A4nwg4LYyh4WgrJOXg","type":"like","source":"https://brainbaking.com/valid-bridgy-like.html","target":"https://brainbaking.com/valid-indieweb-target.html"}`,
},
{
- label: "receive a brid.gy webmention that has a url and photo without value",
- wm: webmention{
- source: "https://brainbaking.com/valid-bridgy-source.html",
- target: "https://brainbaking.com/valid-indieweb-target.html",
+ label: "receive a brid.gy Webmention that has a url and photo without value",
+ wm: Mention{
+ Source: "https://brainbaking.com/valid-bridgy-source.html",
+ Target: "https://brainbaking.com/valid-indieweb-target.html",
},
json: `{"author":{"name":"Stampeding Longhorn", "picture":"https://cdn.social.linux.pizza/v1/AUTH_91eb37814936490c95da7b85993cc2ff/sociallinuxpizza/accounts/avatars/000/185/996/original/9e36da0c093cfc9b.png"}, "content":"@wouter The cat pictures are awesome. for jest tests!", "name":"@wouter The cat pictures are awesome. for jest tests!", "published":"2021-03-02T16:17:18.000Z", "source":"https://brainbaking.com/valid-bridgy-source.html", "target":"https://brainbaking.com/valid-indieweb-target.html", "type":"mention", "url":"https://social.linux.pizza/@StampedingLonghorn/105821099684887793"}`,
},
{
label: "receive saves a JSON file of indieweb-metadata if all is valid",
- wm: webmention{
- source: "https://brainbaking.com/valid-indieweb-source.html",
- target: "https://jefklakscodex.com/articles",
+ wm: Mention{
+ Source: "https://brainbaking.com/valid-indieweb-source.html",
+ Target: "https://jefklakscodex.com/articles",
},
json: `{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com//img/avatar.jpg"},"name":"I just learned about https://www.inklestudios.com/...","content":"This is cool, I just found out about valid indieweb target - so cool","published":"2021-03-06T12:41:00","url":"https://brainbaking.com/notes/2021/03/06h12m41s48/","type":"mention","source":"https://brainbaking.com/valid-indieweb-source.html","target":"https://jefklakscodex.com/articles"}`,
},
{
label: "receive saves a JSON file of indieweb-metadata with summary as content if present",
- wm: webmention{
- source: "https://brainbaking.com/valid-indieweb-source-with-summary.html",
- target: "https://brainbaking.com/valid-indieweb-target.html",
+ wm: Mention{
+ Source: "https://brainbaking.com/valid-indieweb-source-with-summary.html",
+ Target: "https://brainbaking.com/valid-indieweb-target.html",
},
json: `{"author":{"name":"Wouter Groeneveld", "picture":"https://brainbaking.com//img/avatar.jpg"}, "content":"This is cool, this is a summary!", "name":"I just learned about https://www.inklestudios.com/...", "published":"2021-03-06T12:41:00", "source":"https://brainbaking.com/valid-indieweb-source-with-summary.html", "target":"https://brainbaking.com/valid-indieweb-target.html", "type":"mention", "url":"https://brainbaking.com/notes/2021/03/06h12m41s48/"}`,
},
{
label: "receive saves a JSON file of non-indieweb-data such as title if all is valid",
- wm: webmention{
- source: "https://brainbaking.com/valid-nonindieweb-source.html",
- target: "https://brainbaking.com/valid-indieweb-target.html",
+ wm: Mention{
+ Source: "https://brainbaking.com/valid-nonindieweb-source.html",
+ Target: "https://brainbaking.com/valid-indieweb-target.html",
},
json: `{"author":{"name":"https://brainbaking.com/valid-nonindieweb-source.html", "picture":""}, "content":"Diablo 2 Twenty Years Later: A Retrospective | Jefklaks Codex", "name":"Diablo 2 Twenty Years Later: A Retrospective | Jefklaks Codex", "published":"2020-01-01T12:30:00", "source":"https://brainbaking.com/valid-nonindieweb-source.html", "target":"https://brainbaking.com/valid-indieweb-target.html", "type":"mention", "url":"https://brainbaking.com/valid-nonindieweb-source.html"}`,
},
@@ -106,14 +106,14 @@ func TestReceive(t *testing.T) {
return time.Date(2020, time.January, 1, 12, 30, 0, 0, time.UTC)
}
- receiver := &receiver {
- conf: conf,
- restClient: &mocks.RestClientMock{
+ receiver := &Receiver{
+ Conf: conf,
+ RestClient: &mocks.RestClientMock{
GetBodyFunc: mocks.RelPathGetBodyFunc(t),
},
}
- receiver.receive(tc.wm)
+ receiver.Receive(tc.wm)
actualJson, _ := ioutil.ReadFile(tc.wm.asPath(conf))
assert.JSONEq(t, tc.json, string(actualJson))
@@ -125,9 +125,9 @@ func TestReceiveTargetDoesNotExistAnymoreDeletesPossiblyOlderWebmention(t *testi
os.MkdirAll("testdata/jefklakscodex.com", os.ModePerm)
defer os.RemoveAll("testdata")
- wm := webmention{
- source: "https://brainbaking.com",
- target: "https://jefklakscodex.com/articles",
+ wm := Mention{
+ Source: "https://brainbaking.com",
+ Target: "https://jefklakscodex.com/articles",
}
filename := wm.asPath(conf)
writeSomethingTo(filename)
@@ -137,31 +137,31 @@ func TestReceiveTargetDoesNotExistAnymoreDeletesPossiblyOlderWebmention(t *testi
return "", errors.New("whoops")
},
}
- receiver := &receiver {
- conf: conf,
- restClient: client,
+ receiver := &Receiver{
+ Conf: conf,
+ RestClient: client,
}
- receiver.receive(wm)
+ receiver.Receive(wm)
assert.NoFileExists(t, filename)
}
func TestReceiveTargetThatDoesNotPointToTheSourceDoesNothing(t *testing.T) {
- wm := webmention{
- source: "https://brainbaking.com/valid-indieweb-source.html",
- target: "https://brainbaking.com/valid-indieweb-source.html",
+ wm := Mention{
+ Source: "https://brainbaking.com/valid-indieweb-source.html",
+ Target: "https://brainbaking.com/valid-indieweb-source.html",
}
filename := wm.asPath(conf)
writeSomethingTo(filename)
- receiver := &receiver {
- conf: conf,
- restClient: &mocks.RestClientMock{
+ receiver := &Receiver{
+ Conf: conf,
+ RestClient: &mocks.RestClientMock{
GetBodyFunc: mocks.RelPathGetBodyFunc(t),
},
}
- receiver.receive(wm)
+ receiver.Receive(wm)
assert.NoFileExists(t, filename)
}
@@ -169,12 +169,12 @@ func TestProcessSourceBodyAbortsIfNoMentionOfTargetFoundInSourceHtml(t *testing.
os.MkdirAll("testdata/jefklakscodex.com", os.ModePerm)
defer os.RemoveAll("testdata")
- wm := webmention{
- source: "https://brainbaking.com",
- target: "https://jefklakscodex.com/articles",
+ wm := Mention{
+ Source: "https://brainbaking.com",
+ Target: "https://jefklakscodex.com/articles",
}
- receiver := &receiver {
- conf: conf,
+ receiver := &Receiver{
+ Conf: conf,
}
receiver.processSourceBody("my nice body", wm)
diff --git a/rest/utils.go b/rest/utils.go
index 3ca5212..065ce44 100644
--- a/rest/utils.go
+++ b/rest/utils.go
@@ -11,5 +11,5 @@ func BadRequest(w http.ResponseWriter) {
func Accept(w http.ResponseWriter) {
w.WriteHeader(202)
- w.Write([]byte("Thanks, bro. Will send these webmentions soon, pinky swear!"))
+ w.Write([]byte("Thanks, bro. Will process this soon, pinky swear!"))
}