From: {{ $mention.Source }}
+ {{ if not (eq $mention.Source $mention.Url ) }}u-url: {{ $mention.Url }}
{{ end }}
To: {{ $mention.Target }}
Created: {{ unixtodate $mention.Created }}
{{ if $mention.Author }}{{ $mention.Author }}
{{ end }}
diff --git a/testdata/bridgy.html b/testdata/bridgy.html
new file mode 100644
index 0000000..68c0569
--- /dev/null
+++ b/testdata/bridgy.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+
comment test
+
+
+ tag:example.net,2013:ADYb7HhxE6UzPpfFiK
+
+
+
+
+
+
+ m4rk
+
+
+ m4rk
+
+
+
+ https://example.net/notice/ADYb7HhxE6UzPpfFiK
+
+
+ comment test
+
+
+
+
+
+
+
+ m4rk
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/webmention.go b/webmention.go
index ffaafa1..7cf8de8 100644
--- a/webmention.go
+++ b/webmention.go
@@ -26,12 +26,14 @@ type mention struct {
NewSource string
Target string
NewTarget string
+ Url string
Created int64
Title string
Content string
Author string
Status webmentionStatus
Submentions []*mention
+ hasUrl bool
}
func (a *goBlog) initWebmention() {
@@ -127,11 +129,12 @@ func (a *goBlog) createWebmention(source, target string) (err error) {
func (db *database) insertWebmention(m *mention, status webmentionStatus) error {
_, err := db.exec(
`
- insert into webmentions (source, target, created, status, title, content, author)
- values (@source, @target, @created, @status, @title, @content, @author)
+ insert into webmentions (source, target, url, created, status, title, content, author)
+ values (@source, @target, @url, @created, @status, @title, @content, @author)
`,
sql.Named("source", m.Source),
sql.Named("target", m.Target),
+ sql.Named("url", m.Url),
sql.Named("created", m.Created),
sql.Named("status", status),
sql.Named("title", m.Title),
@@ -147,6 +150,7 @@ func (db *database) updateWebmention(m *mention, newStatus webmentionStatus) err
set
source = @newsource,
target = @newtarget,
+ url = @url,
status = @status,
title = @title,
content = @content,
@@ -157,6 +161,7 @@ func (db *database) updateWebmention(m *mention, newStatus webmentionStatus) err
`,
sql.Named("newsource", defaultIfEmpty(m.NewSource, m.Source)),
sql.Named("newtarget", defaultIfEmpty(m.NewTarget, m.Target)),
+ sql.Named("url", m.Url),
sql.Named("status", newStatus),
sql.Named("title", m.Title),
sql.Named("content", m.Content),
@@ -216,7 +221,7 @@ type webmentionsRequestConfig struct {
func buildWebmentionsQuery(config *webmentionsRequestConfig) (query string, args []interface{}) {
var queryBuilder strings.Builder
- queryBuilder.WriteString("select id, source, target, created, title, content, author, status from webmentions ")
+ queryBuilder.WriteString("select id, source, target, url, created, title, content, author, status from webmentions ")
if config != nil {
queryBuilder.WriteString("where 1")
if config.target != "" {
@@ -258,10 +263,13 @@ func (db *database) getWebmentions(config *webmentionsRequestConfig) ([]*mention
}
for rows.Next() {
m := &mention{}
- err = rows.Scan(&m.ID, &m.Source, &m.Target, &m.Created, &m.Title, &m.Content, &m.Author, &m.Status)
+ err = rows.Scan(&m.ID, &m.Source, &m.Target, &m.Url, &m.Created, &m.Title, &m.Content, &m.Author, &m.Status)
if err != nil {
return nil, err
}
+ if m.Url == "" {
+ m.Url = m.Source
+ }
if config.submentions {
m.Submentions, err = db.getWebmentions(&webmentionsRequestConfig{
target: m.Source,
diff --git a/webmentionVerification.go b/webmentionVerification.go
index 2228f45..6ea230c 100644
--- a/webmentionVerification.go
+++ b/webmentionVerification.go
@@ -201,7 +201,12 @@ func (a *goBlog) verifyReader(m *mention, body io.Reader) error {
m.Title = ""
m.Content = ""
m.Author = ""
+ m.Url = ""
+ m.hasUrl = false
m.fillFromData(microformats.Parse(&mfBuffer, sourceURL))
+ if m.Url == "" {
+ m.Url = m.Source
+ }
// Set title when content is empty as well
if m.Title == "" && m.Content == "" {
doc, err := goquery.NewDocumentFromReader(&gqBuffer)
@@ -216,8 +221,11 @@ func (a *goBlog) verifyReader(m *mention, body io.Reader) error {
}
func (m *mention) fillFromData(mf *microformats.Data) {
+ // Fill data
for _, i := range mf.Items {
- m.fill(i)
+ if m.fill(i) {
+ break
+ }
}
}
@@ -226,8 +234,22 @@ func (m *mention) fill(mf *microformats.Microformat) bool {
// Check URL
if url, ok := mf.Properties["url"]; ok && len(url) > 0 {
if url0, ok := url[0].(string); ok {
- if !strings.EqualFold(url0, defaultIfEmpty(m.NewSource, m.Source)) {
- // Not correct URL
+ if strings.EqualFold(url0, defaultIfEmpty(m.NewSource, m.Source)) {
+ // Is searched entry
+ m.hasUrl = true
+ m.Url = url0
+ // Reset attributes to refill
+ m.Author = ""
+ m.Title = ""
+ m.Content = ""
+ } else if m.hasUrl {
+ // Already found entry
+ return false
+ } else if m.Url == "" {
+ // Is the first entry
+ m.Url = url0
+ } else {
+ // Is not the first entry
return false
}
}
diff --git a/webmentionVerification_test.go b/webmentionVerification_test.go
index a142b3b..a5a8956 100644
--- a/webmentionVerification_test.go
+++ b/webmentionVerification_test.go
@@ -49,6 +49,7 @@ func Test_verifyMention(t *testing.T) {
require.Equal(t, "https://example.org/articles/micropub-syndication-targets-and-crossposting-to-mastodon", m.Target)
require.Equal(t, "https://example.net/articles/micropub-crossposting-to-twitter-and-enabling-tweetstorms", m.Source)
+ require.Equal(t, "https://example.net/articles/micropub-crossposting-to-twitter-and-enabling-tweetstorms", m.Url)
require.Equal(t, "Micropub, Crossposting to Twitter, and Enabling “Tweetsto…", m.Title)
require.Equal(t, "I’ve previously talked about how I crosspost from this blog to my Mastodon account without the need for a third-party service, and how I leverage WordPress’s hook system to even enable toot threading. In this post, I’m going to really quickly explain my (extremely similar) Twitter setup. (Note: I don’t actually syndicate this blog’s posts to Twitter, but I do use this very setup on another site of mine.) I liked the idea of a dead-simple Twitter plugin, so I forked my Mastodon plugin and twea…", m.Content)
require.Equal(t, "Test Blogger", m.Author)
@@ -57,3 +58,46 @@ func Test_verifyMention(t *testing.T) {
require.NoError(t, err)
}
+
+func Test_verifyMentionBidgy(t *testing.T) {
+
+ testHtmlBytes, err := os.ReadFile("testdata/bridgy.html")
+ require.NoError(t, err)
+ testHtml := string(testHtmlBytes)
+
+ mockClient := &fakeHttpClient{}
+ mockClient.setFakeResponse(http.StatusOK, testHtml)
+
+ app := &goBlog{
+ httpClient: mockClient,
+ cfg: &config{
+ Db: &configDb{
+ File: filepath.Join(t.TempDir(), "test.db"),
+ },
+ Server: &configServer{
+ PublicAddress: "https://example.org",
+ },
+ },
+ d: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // do nothing
+ }),
+ }
+
+ _ = app.initDatabase(false)
+ app.initComponents(false)
+
+ m := &mention{
+ Source: "https://example.com/abc",
+ Target: "https://example.org/walks/2021/11/9k-local-run",
+ }
+
+ err = app.verifyMention(m)
+ require.NoError(t, err)
+
+ require.Equal(t, "https://example.org/walks/2021/11/9k-local-run", m.Target)
+ require.Equal(t, "https://example.com/abc", m.Source)
+ require.Equal(t, "https://example.net/notice/ADYb7HhxE6UzPpfFiK", m.Url)
+ require.Equal(t, "comment test", m.Title)
+ require.Equal(t, "comment test", m.Content)
+ require.Equal(t, "m4rk", m.Author)
+}