Support bridgy

This commit is contained in:
Jan-Lukas Else 2021-11-19 22:17:15 +01:00
parent 6e8aeef10d
commit 659d6dcea3
7 changed files with 131 additions and 9 deletions

1
dbmigrations/00024.sql Normal file
View File

@ -0,0 +1 @@
alter table webmentions add url text not null default "";

View File

@ -3,11 +3,11 @@
<ul> <ul>
{{ range $i, $mention := .Data }} {{ range $i, $mention := .Data }}
<li> <li>
<a href="{{$mention.Source}}" target="_blank" rel="nofollow noopener noreferrer ugc"> <a href="{{ $mention.Url }}" target="_blank" rel="nofollow noopener noreferrer ugc">
{{ if $mention.Author }} {{ if $mention.Author }}
{{ $mention.Author }} {{ $mention.Author }}
{{ else }} {{ else }}
{{ $mention.Source }} {{ $mention.Url }}
{{ end }} {{ end }}
</a> </a>
{{ with $mention.Title }} <b>{{.}}</b>{{ end }} {{ with $mention.Title }} <b>{{.}}</b>{{ end }}

View File

@ -11,6 +11,7 @@
<div id="mention-{{ $mention.ID }}" class="p"> <div id="mention-{{ $mention.ID }}" class="p">
<p> <p>
From: <a href="{{ $mention.Source }}" target="_blank" rel="noopener noreferrer">{{ $mention.Source }}</a><br/> From: <a href="{{ $mention.Source }}" target="_blank" rel="noopener noreferrer">{{ $mention.Source }}</a><br/>
{{ if not (eq $mention.Source $mention.Url ) }}u-url: <a href="{{ $mention.Url }}" target="_blank" rel="noopener noreferrer">{{ $mention.Url }}</a><br/>{{ end }}
To: <a href="{{ $mention.Target }}" target="_blank">{{ $mention.Target }}</a><br/> To: <a href="{{ $mention.Target }}" target="_blank">{{ $mention.Target }}</a><br/>
Created: {{ unixtodate $mention.Created }}<br/><br/> Created: {{ unixtodate $mention.Created }}<br/><br/>
{{ if $mention.Author }}{{ $mention.Author }}<br/>{{ end }} {{ if $mention.Author }}{{ $mention.Author }}<br/>{{ end }}

46
testdata/bridgy.html vendored Normal file
View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="0;url=https://example.net/notice/ADYb7HhxE6UzPpfFiK">
<title>comment test</title>
</head>
<article class="h-entry">
<span class="p-uid">tag:example.net,2013:ADYb7HhxE6UzPpfFiK</span>
<time class="dt-published" datetime="2021-11-19T11:16:10.000Z">2021-11-19T11:16:10.000Z</time>
<span class="p-author h-card">
<data class="p-uid" value="tag:example.net,2013:m4rk"></data>
<data class="p-numeric-id" value="ADK9CwrdBhAeIowb5c"></data>
<a class="p-name u-url" href="https://example.net/users/m4rk">m4rk</a>
<a class="u-url" href="https://example.org"></a>
<a class="u-url" href="https://example.net/@m4rk"></a>
<span class="p-nickname">m4rk</span>
<img class="u-photo" src="https://example.net/media/dfee423b-b56b-42bf-8c0b-795cfc2a4776/blob" alt="" />
</span>
<a class="u-url" href="https://example.net/notice/ADYb7HhxE6UzPpfFiK">https://example.net/notice/ADYb7HhxE6UzPpfFiK</a>
<div class="e-content p-name">
comment test
</div>
<span class="u-category h-card">
<data class="p-uid" value="tag:example.net,2013:ADK9CwrdBhAeIowb5c"></data>
<a class="p-name u-url" href="https://example.net/users/m4rk">m4rk</a>
</span>
<a class="u-in-reply-to" href="https://example.org/s/3"></a>
<a class="u-in-reply-to" href="https://example.org/walks/2021/11/9k-local-run"></a>
<a class="u-in-reply-to" href="https://example.net/web/statuses/ADYapxNFZfmlQbiYKm"></a>
</article>
</html>

View File

@ -26,12 +26,14 @@ type mention struct {
NewSource string NewSource string
Target string Target string
NewTarget string NewTarget string
Url string
Created int64 Created int64
Title string Title string
Content string Content string
Author string Author string
Status webmentionStatus Status webmentionStatus
Submentions []*mention Submentions []*mention
hasUrl bool
} }
func (a *goBlog) initWebmention() { 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 { func (db *database) insertWebmention(m *mention, status webmentionStatus) error {
_, err := db.exec( _, err := db.exec(
` `
insert into webmentions (source, target, created, status, title, content, author) insert into webmentions (source, target, url, created, status, title, content, author)
values (@source, @target, @created, @status, @title, @content, @author) values (@source, @target, @url, @created, @status, @title, @content, @author)
`, `,
sql.Named("source", m.Source), sql.Named("source", m.Source),
sql.Named("target", m.Target), sql.Named("target", m.Target),
sql.Named("url", m.Url),
sql.Named("created", m.Created), sql.Named("created", m.Created),
sql.Named("status", status), sql.Named("status", status),
sql.Named("title", m.Title), sql.Named("title", m.Title),
@ -147,6 +150,7 @@ func (db *database) updateWebmention(m *mention, newStatus webmentionStatus) err
set set
source = @newsource, source = @newsource,
target = @newtarget, target = @newtarget,
url = @url,
status = @status, status = @status,
title = @title, title = @title,
content = @content, 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("newsource", defaultIfEmpty(m.NewSource, m.Source)),
sql.Named("newtarget", defaultIfEmpty(m.NewTarget, m.Target)), sql.Named("newtarget", defaultIfEmpty(m.NewTarget, m.Target)),
sql.Named("url", m.Url),
sql.Named("status", newStatus), sql.Named("status", newStatus),
sql.Named("title", m.Title), sql.Named("title", m.Title),
sql.Named("content", m.Content), sql.Named("content", m.Content),
@ -216,7 +221,7 @@ type webmentionsRequestConfig struct {
func buildWebmentionsQuery(config *webmentionsRequestConfig) (query string, args []interface{}) { func buildWebmentionsQuery(config *webmentionsRequestConfig) (query string, args []interface{}) {
var queryBuilder strings.Builder 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 { if config != nil {
queryBuilder.WriteString("where 1") queryBuilder.WriteString("where 1")
if config.target != "" { if config.target != "" {
@ -258,10 +263,13 @@ func (db *database) getWebmentions(config *webmentionsRequestConfig) ([]*mention
} }
for rows.Next() { for rows.Next() {
m := &mention{} 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 { if err != nil {
return nil, err return nil, err
} }
if m.Url == "" {
m.Url = m.Source
}
if config.submentions { if config.submentions {
m.Submentions, err = db.getWebmentions(&webmentionsRequestConfig{ m.Submentions, err = db.getWebmentions(&webmentionsRequestConfig{
target: m.Source, target: m.Source,

View File

@ -201,7 +201,12 @@ func (a *goBlog) verifyReader(m *mention, body io.Reader) error {
m.Title = "" m.Title = ""
m.Content = "" m.Content = ""
m.Author = "" m.Author = ""
m.Url = ""
m.hasUrl = false
m.fillFromData(microformats.Parse(&mfBuffer, sourceURL)) m.fillFromData(microformats.Parse(&mfBuffer, sourceURL))
if m.Url == "" {
m.Url = m.Source
}
// Set title when content is empty as well // Set title when content is empty as well
if m.Title == "" && m.Content == "" { if m.Title == "" && m.Content == "" {
doc, err := goquery.NewDocumentFromReader(&gqBuffer) 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) { func (m *mention) fillFromData(mf *microformats.Data) {
// Fill data
for _, i := range mf.Items { 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 // Check URL
if url, ok := mf.Properties["url"]; ok && len(url) > 0 { if url, ok := mf.Properties["url"]; ok && len(url) > 0 {
if url0, ok := url[0].(string); ok { if url0, ok := url[0].(string); ok {
if !strings.EqualFold(url0, defaultIfEmpty(m.NewSource, m.Source)) { if strings.EqualFold(url0, defaultIfEmpty(m.NewSource, m.Source)) {
// Not correct URL // 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 return false
} }
} }

View File

@ -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.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.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, "Micropub, Crossposting to Twitter, and Enabling “Tweetsto…", m.Title)
require.Equal(t, "Ive 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 WordPresss hook system to even enable toot threading. In this post, Im going to really quickly explain my (extremely similar) Twitter setup. (Note: I dont actually syndicate this blogs 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, "Ive 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 WordPresss hook system to even enable toot threading. In this post, Im going to really quickly explain my (extremely similar) Twitter setup. (Note: I dont actually syndicate this blogs 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) require.Equal(t, "Test Blogger", m.Author)
@ -57,3 +58,46 @@ func Test_verifyMention(t *testing.T) {
require.NoError(t, err) 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)
}