Compare commits
No commits in common. "41c2286311c80ad8b48ffed6c5c047a2d756918e" and "a8998068ad97be549156e50862d78e9987cd417e" have entirely different histories.
41c2286311
...
a8998068ad
|
@ -2,7 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"h4kor/owl-blogs"
|
"h4kor/owl-blogs"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -57,20 +56,14 @@ var webmentionCmd = &cobra.Command{
|
||||||
|
|
||||||
webmentions := post.OutgoingWebmentions()
|
webmentions := post.OutgoingWebmentions()
|
||||||
println("Found ", len(webmentions), " links")
|
println("Found ", len(webmentions), " links")
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
wg.Add(len(webmentions))
|
|
||||||
for _, webmention := range webmentions {
|
for _, webmention := range webmentions {
|
||||||
go func(webmention owl.WebmentionOut) {
|
|
||||||
defer wg.Done()
|
|
||||||
err = post.SendWebmention(webmention)
|
err = post.SendWebmention(webmention)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("Error sending webmentions: ", err.Error())
|
println("Error sending webmentions: ", err.Error())
|
||||||
} else {
|
} else {
|
||||||
println("Webmention sent to ", webmention.Target)
|
println("Webmention sent to ", webmention.Target)
|
||||||
}
|
}
|
||||||
}(webmention)
|
|
||||||
}
|
}
|
||||||
wg.Wait()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,12 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
{{if .Post.ApprovedIncomingWebmentions}}
|
{{if .Post.ApprovedWebmentions}}
|
||||||
<h3>
|
<h3>
|
||||||
Webmentions
|
Webmentions
|
||||||
</h3>
|
</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{{range .Post.ApprovedIncomingWebmentions}}
|
{{range .Post.ApprovedWebmentions}}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{.Source}}">
|
<a href="{{.Source}}">
|
||||||
{{if .Title}}
|
{{if .Title}}
|
||||||
|
|
21
owl_test.go
21
owl_test.go
|
@ -28,27 +28,6 @@ func (*MockHtmlParser) GetWebmentionEndpoint(resp *http.Response) (string, error
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MockParseLinksHtmlParser struct {
|
|
||||||
Links []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*MockParseLinksHtmlParser) ParseHEntry(resp *http.Response) (owl.ParsedHEntry, error) {
|
|
||||||
return owl.ParsedHEntry{Title: "Mock Title"}, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
func (parser *MockParseLinksHtmlParser) ParseLinks(resp *http.Response) ([]string, error) {
|
|
||||||
return parser.Links, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
func (parser *MockParseLinksHtmlParser) ParseLinksFromString(string) ([]string, error) {
|
|
||||||
return parser.Links, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
func (*MockParseLinksHtmlParser) GetWebmentionEndpoint(resp *http.Response) (string, error) {
|
|
||||||
return "http://example.com/webmention", nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type MockHttpClient struct{}
|
type MockHttpClient struct{}
|
||||||
|
|
||||||
func (*MockHttpClient) Get(url string) (resp *http.Response, err error) {
|
func (*MockHttpClient) Get(url string) (resp *http.Response, err error) {
|
||||||
|
|
211
post.go
211
post.go
|
@ -2,12 +2,12 @@ package owl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/yuin/goldmark"
|
"github.com/yuin/goldmark"
|
||||||
|
@ -23,7 +23,6 @@ type Post struct {
|
||||||
title string
|
title string
|
||||||
metaLoaded bool
|
metaLoaded bool
|
||||||
meta PostMeta
|
meta PostMeta
|
||||||
wmLock sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PostMeta struct {
|
type PostMeta struct {
|
||||||
|
@ -38,39 +37,39 @@ type PostWebmetions struct {
|
||||||
Outgoing []WebmentionOut `ymal:"outgoing"`
|
Outgoing []WebmentionOut `ymal:"outgoing"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) Id() string {
|
func (post Post) Id() string {
|
||||||
return post.id
|
return post.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) Dir() string {
|
func (post Post) Dir() string {
|
||||||
return path.Join(post.user.Dir(), "public", post.id)
|
return path.Join(post.user.Dir(), "public", post.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) WebmentionsFile() string {
|
func (post Post) WebmentionsFile() string {
|
||||||
return path.Join(post.Dir(), "webmentions.yml")
|
return path.Join(post.Dir(), "webmentions.yml")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) MediaDir() string {
|
func (post Post) MediaDir() string {
|
||||||
return path.Join(post.Dir(), "media")
|
return path.Join(post.Dir(), "media")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) UrlPath() string {
|
func (post Post) UrlPath() string {
|
||||||
return post.user.UrlPath() + "posts/" + post.id + "/"
|
return post.user.UrlPath() + "posts/" + post.id + "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) FullUrl() string {
|
func (post Post) FullUrl() string {
|
||||||
return post.user.FullUrl() + "posts/" + post.id + "/"
|
return post.user.FullUrl() + "posts/" + post.id + "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) UrlMediaPath(filename string) string {
|
func (post Post) UrlMediaPath(filename string) string {
|
||||||
return post.UrlPath() + "media/" + filename
|
return post.UrlPath() + "media/" + filename
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) Title() string {
|
func (post Post) Title() string {
|
||||||
return post.title
|
return post.title
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) ContentFile() string {
|
func (post Post) ContentFile() string {
|
||||||
return path.Join(post.Dir(), "index.md")
|
return path.Join(post.Dir(), "index.md")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,13 +80,49 @@ func (post *Post) Meta() PostMeta {
|
||||||
return post.meta
|
return post.meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) Content() []byte {
|
func (post Post) Content() []byte {
|
||||||
// read file
|
// read file
|
||||||
data, _ := ioutil.ReadFile(post.ContentFile())
|
data, _ := ioutil.ReadFile(post.ContentFile())
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) RenderedContent() bytes.Buffer {
|
func (post Post) Webmentions() PostWebmetions {
|
||||||
|
// read status file
|
||||||
|
// return parsed webmentions
|
||||||
|
fileName := post.WebmentionsFile()
|
||||||
|
if !fileExists(fileName) {
|
||||||
|
return PostWebmetions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := os.ReadFile(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return PostWebmetions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
webmentions := PostWebmetions{}
|
||||||
|
err = yaml.Unmarshal(data, &webmentions)
|
||||||
|
if err != nil {
|
||||||
|
return PostWebmetions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return webmentions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (post Post) PersistWebmentions(webmentions PostWebmetions) error {
|
||||||
|
data, err := yaml.Marshal(webmentions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(post.WebmentionsFile(), data, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (post Post) RenderedContent() bytes.Buffer {
|
||||||
data := post.Content()
|
data := post.Content()
|
||||||
|
|
||||||
// trim yaml block
|
// trim yaml block
|
||||||
|
@ -127,7 +162,7 @@ func (post *Post) RenderedContent() bytes.Buffer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) Aliases() []string {
|
func (post Post) Aliases() []string {
|
||||||
return post.Meta().Aliases
|
return post.Meta().Aliases
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,63 +190,14 @@ func (post *Post) LoadMeta() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Webmentions returns list of incoming and outgoing webmentions
|
|
||||||
func (post *Post) Webmentions() PostWebmetions {
|
|
||||||
// read status file
|
|
||||||
// return parsed webmentions
|
|
||||||
fileName := post.WebmentionsFile()
|
|
||||||
if !fileExists(fileName) {
|
|
||||||
return PostWebmetions{}
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := os.ReadFile(fileName)
|
|
||||||
if err != nil {
|
|
||||||
return PostWebmetions{}
|
|
||||||
}
|
|
||||||
|
|
||||||
webmentions := PostWebmetions{}
|
|
||||||
err = yaml.Unmarshal(data, &webmentions)
|
|
||||||
if err != nil {
|
|
||||||
return PostWebmetions{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return webmentions
|
|
||||||
}
|
|
||||||
|
|
||||||
func (post *Post) IncomingWebmentions() []WebmentionIn {
|
|
||||||
return post.Webmentions().Incoming
|
|
||||||
}
|
|
||||||
|
|
||||||
func (post *Post) OutgoingWebmentions() []WebmentionOut {
|
|
||||||
return post.Webmentions().Outgoing
|
|
||||||
}
|
|
||||||
|
|
||||||
func (post *Post) persistWebmentions(webmentions PostWebmetions) error {
|
|
||||||
data, err := yaml.Marshal(webmentions)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.WriteFile(post.WebmentionsFile(), data, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PersistWebmentionOutgoing persists incoming webmention
|
|
||||||
func (post *Post) PersistIncomingWebmention(webmention WebmentionIn) error {
|
func (post *Post) PersistIncomingWebmention(webmention WebmentionIn) error {
|
||||||
post.wmLock.Lock()
|
|
||||||
defer post.wmLock.Unlock()
|
|
||||||
|
|
||||||
wms := post.Webmentions()
|
wms := post.Webmentions()
|
||||||
|
|
||||||
// if target is not in status, add it
|
// if target is not in status, add it
|
||||||
replaced := false
|
replaced := false
|
||||||
for i, t := range wms.Incoming {
|
for i, t := range wms.Incoming {
|
||||||
if t.Source == webmention.Source {
|
if t.Source == webmention.Source {
|
||||||
wms.Incoming[i].UpdateWith(webmention)
|
wms.Incoming[i] = webmention
|
||||||
replaced = true
|
replaced = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -221,21 +207,58 @@ func (post *Post) PersistIncomingWebmention(webmention WebmentionIn) error {
|
||||||
wms.Incoming = append(wms.Incoming, webmention)
|
wms.Incoming = append(wms.Incoming, webmention)
|
||||||
}
|
}
|
||||||
|
|
||||||
return post.persistWebmentions(wms)
|
return post.PersistWebmentions(wms)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PersistOutgoingWebmention persists a webmention to the webmention file.
|
func (post *Post) Webmention(source string) (WebmentionIn, error) {
|
||||||
func (post *Post) PersistOutgoingWebmention(webmention *WebmentionOut) error {
|
wms := post.Webmentions()
|
||||||
post.wmLock.Lock()
|
for _, wm := range wms.Incoming {
|
||||||
defer post.wmLock.Unlock()
|
if wm.Source == source {
|
||||||
|
return wm, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return WebmentionIn{}, errors.New("not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (post *Post) AddIncomingWebmention(source string) error {
|
||||||
|
// Check if file already exists
|
||||||
|
_, err := post.Webmention(source)
|
||||||
|
if err != nil {
|
||||||
|
wms := post.Webmentions()
|
||||||
|
wms.Incoming = append(wms.Incoming, WebmentionIn{
|
||||||
|
Source: source,
|
||||||
|
})
|
||||||
|
defer post.EnrichWebmention(source)
|
||||||
|
return post.PersistWebmentions(wms)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (post *Post) AddOutgoingWebmention(target string) error {
|
||||||
wms := post.Webmentions()
|
wms := post.Webmentions()
|
||||||
|
|
||||||
// if target is not in webmention, add it
|
// Check if file already exists
|
||||||
|
for _, wm := range wms.Outgoing {
|
||||||
|
if wm.Target == target {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
webmention := WebmentionOut{
|
||||||
|
Target: target,
|
||||||
|
}
|
||||||
|
wms.Outgoing = append(wms.Outgoing, webmention)
|
||||||
|
return post.PersistWebmentions(wms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (post *Post) UpdateOutgoingWebmention(webmention *WebmentionOut) error {
|
||||||
|
wms := post.Webmentions()
|
||||||
|
|
||||||
|
// if target is not in status, add it
|
||||||
replaced := false
|
replaced := false
|
||||||
for i, t := range wms.Outgoing {
|
for i, t := range wms.Outgoing {
|
||||||
if t.Target == webmention.Target {
|
if t.Target == webmention.Target {
|
||||||
wms.Outgoing[i].UpdateWith(*webmention)
|
wms.Outgoing[i] = *webmention
|
||||||
replaced = true
|
replaced = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -245,24 +268,16 @@ func (post *Post) PersistOutgoingWebmention(webmention *WebmentionOut) error {
|
||||||
wms.Outgoing = append(wms.Outgoing, *webmention)
|
wms.Outgoing = append(wms.Outgoing, *webmention)
|
||||||
}
|
}
|
||||||
|
|
||||||
return post.persistWebmentions(wms)
|
return post.PersistWebmentions(wms)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) AddIncomingWebmention(source string) error {
|
func (post *Post) EnrichWebmention(source string) error {
|
||||||
// Check if file already exists
|
resp, err := post.user.repo.HttpClient.Get(source)
|
||||||
wm := WebmentionIn{
|
|
||||||
Source: source,
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
go post.EnrichWebmention(wm)
|
|
||||||
}()
|
|
||||||
return post.PersistIncomingWebmention(wm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (post *Post) EnrichWebmention(webmention WebmentionIn) error {
|
|
||||||
resp, err := post.user.repo.HttpClient.Get(webmention.Source)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
webmention, err := post.Webmention(source)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
entry, err := post.user.repo.Parser.ParseHEntry(resp)
|
entry, err := post.user.repo.Parser.ParseHEntry(resp)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
webmention.Title = entry.Title
|
webmention.Title = entry.Title
|
||||||
|
@ -272,7 +287,11 @@ func (post *Post) EnrichWebmention(webmention WebmentionIn) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) ApprovedIncomingWebmentions() []WebmentionIn {
|
func (post *Post) IncomingWebmentions() []WebmentionIn {
|
||||||
|
return post.Webmentions().Incoming
|
||||||
|
}
|
||||||
|
|
||||||
|
func (post *Post) ApprovedWebmentions() []WebmentionIn {
|
||||||
webmentions := post.IncomingWebmentions()
|
webmentions := post.IncomingWebmentions()
|
||||||
approved := []WebmentionIn{}
|
approved := []WebmentionIn{}
|
||||||
for _, webmention := range webmentions {
|
for _, webmention := range webmentions {
|
||||||
|
@ -288,29 +307,25 @@ func (post *Post) ApprovedIncomingWebmentions() []WebmentionIn {
|
||||||
return approved
|
return approved
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (post *Post) OutgoingWebmentions() []WebmentionOut {
|
||||||
|
return post.Webmentions().Outgoing
|
||||||
|
}
|
||||||
|
|
||||||
// ScanForLinks scans the post content for links and adds them to the
|
// ScanForLinks scans the post content for links and adds them to the
|
||||||
// `status.yml` file for the post. The links are not scanned by this function.
|
// `status.yml` file for the post. The links are not scanned by this function.
|
||||||
func (post *Post) ScanForLinks() error {
|
func (post *Post) ScanForLinks() error {
|
||||||
// this could be done in markdown parsing, but I don't want to
|
// this could be done in markdown parsing, but I don't want to
|
||||||
// rely on goldmark for this (yet)
|
// rely on goldmark for this (yet)
|
||||||
postHtml := post.RenderedContent()
|
postHtml := post.RenderedContent()
|
||||||
links, _ := post.user.repo.Parser.ParseLinksFromString(postHtml.String())
|
links, _ := post.user.repo.Parser.ParseLinksFromString(string(postHtml.Bytes()))
|
||||||
for _, link := range links {
|
for _, link := range links {
|
||||||
post.PersistOutgoingWebmention(&WebmentionOut{
|
post.AddOutgoingWebmention(link)
|
||||||
Target: link,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) SendWebmention(webmention WebmentionOut) error {
|
func (post *Post) SendWebmention(webmention WebmentionOut) error {
|
||||||
defer post.PersistOutgoingWebmention(&webmention)
|
defer post.UpdateOutgoingWebmention(&webmention)
|
||||||
|
|
||||||
// if last scan is less than 7 days ago, don't send webmention
|
|
||||||
if webmention.ScannedAt.After(time.Now().Add(-7*24*time.Hour)) && !webmention.Supported {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
webmention.ScannedAt = time.Now()
|
webmention.ScannedAt = time.Now()
|
||||||
|
|
||||||
resp, err := post.user.repo.HttpClient.Get(webmention.Target)
|
resp, err := post.user.repo.HttpClient.Get(webmention.Target)
|
||||||
|
|
185
post_test.go
185
post_test.go
|
@ -4,9 +4,7 @@ import (
|
||||||
"h4kor/owl-blogs"
|
"h4kor/owl-blogs"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -232,7 +230,7 @@ func TestAddIncomingWebmentionNotOverwritingWebmention(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEnrichAddsTitle(t *testing.T) {
|
func TestAddIncomingWebmentionAddsParsedTitle(t *testing.T) {
|
||||||
repo := getTestRepo(owl.RepoConfig{})
|
repo := getTestRepo(owl.RepoConfig{})
|
||||||
repo.HttpClient = &MockHttpClient{}
|
repo.HttpClient = &MockHttpClient{}
|
||||||
repo.Parser = &MockHtmlParser{}
|
repo.Parser = &MockHtmlParser{}
|
||||||
|
@ -240,7 +238,6 @@ func TestEnrichAddsTitle(t *testing.T) {
|
||||||
post, _ := user.CreateNewPost("testpost")
|
post, _ := user.CreateNewPost("testpost")
|
||||||
|
|
||||||
post.AddIncomingWebmention("https://example.com")
|
post.AddIncomingWebmention("https://example.com")
|
||||||
post.EnrichWebmention(owl.WebmentionIn{Source: "https://example.com"})
|
|
||||||
|
|
||||||
mentions := post.IncomingWebmentions()
|
mentions := post.IncomingWebmentions()
|
||||||
if len(mentions) != 1 {
|
if len(mentions) != 1 {
|
||||||
|
@ -252,7 +249,7 @@ func TestEnrichAddsTitle(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApprovedIncomingWebmentions(t *testing.T) {
|
func TestApprovedWebmentions(t *testing.T) {
|
||||||
repo := getTestRepo(owl.RepoConfig{})
|
repo := getTestRepo(owl.RepoConfig{})
|
||||||
user, _ := repo.CreateUser("testuser")
|
user, _ := repo.CreateUser("testuser")
|
||||||
post, _ := user.CreateNewPost("testpost")
|
post, _ := user.CreateNewPost("testpost")
|
||||||
|
@ -281,7 +278,7 @@ func TestApprovedIncomingWebmentions(t *testing.T) {
|
||||||
}
|
}
|
||||||
post.PersistIncomingWebmention(webmention)
|
post.PersistIncomingWebmention(webmention)
|
||||||
|
|
||||||
webmentions := post.ApprovedIncomingWebmentions()
|
webmentions := post.ApprovedWebmentions()
|
||||||
if len(webmentions) != 2 {
|
if len(webmentions) != 2 {
|
||||||
t.Errorf("Expected 2 webmentions, got %d", len(webmentions))
|
t.Errorf("Expected 2 webmentions, got %d", len(webmentions))
|
||||||
}
|
}
|
||||||
|
@ -374,179 +371,3 @@ func TestCanSendWebmention(t *testing.T) {
|
||||||
t.Errorf("Expected LastSentAt to be set")
|
t.Errorf("Expected LastSentAt to be set")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWebmentionOnlyScansOncePerWeek(t *testing.T) {
|
|
||||||
repo := getTestRepo(owl.RepoConfig{})
|
|
||||||
repo.HttpClient = &MockHttpClient{}
|
|
||||||
repo.Parser = &MockHtmlParser{}
|
|
||||||
user, _ := repo.CreateUser("testuser")
|
|
||||||
post, _ := user.CreateNewPost("testpost")
|
|
||||||
|
|
||||||
webmention := owl.WebmentionOut{
|
|
||||||
Target: "http://example.com",
|
|
||||||
ScannedAt: time.Now().Add(time.Hour * -24 * 6),
|
|
||||||
}
|
|
||||||
|
|
||||||
post.PersistOutgoingWebmention(&webmention)
|
|
||||||
webmentions := post.OutgoingWebmentions()
|
|
||||||
webmention = webmentions[0]
|
|
||||||
|
|
||||||
err := post.SendWebmention(webmention)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error sending webmention: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
webmentions = post.OutgoingWebmentions()
|
|
||||||
|
|
||||||
if len(webmentions) != 1 {
|
|
||||||
t.Errorf("Expected 1 webmention, got %d", len(webmentions))
|
|
||||||
}
|
|
||||||
|
|
||||||
if webmentions[0].ScannedAt != webmention.ScannedAt {
|
|
||||||
t.Errorf("Expected ScannedAt to be unchanged. Expected: %v, got %v", webmention.ScannedAt, webmentions[0].ScannedAt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSendingMultipleWebmentions(t *testing.T) {
|
|
||||||
repo := getTestRepo(owl.RepoConfig{})
|
|
||||||
repo.HttpClient = &MockHttpClient{}
|
|
||||||
repo.Parser = &MockHtmlParser{}
|
|
||||||
user, _ := repo.CreateUser("testuser")
|
|
||||||
post, _ := user.CreateNewPost("testpost")
|
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
wg.Add(20)
|
|
||||||
|
|
||||||
for i := 0; i < 20; i++ {
|
|
||||||
go func(k int) {
|
|
||||||
webmention := owl.WebmentionOut{
|
|
||||||
Target: "http://example.com" + strconv.Itoa(k),
|
|
||||||
}
|
|
||||||
post.SendWebmention(webmention)
|
|
||||||
wg.Done()
|
|
||||||
}(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
webmentions := post.OutgoingWebmentions()
|
|
||||||
|
|
||||||
if len(webmentions) != 20 {
|
|
||||||
t.Errorf("Expected 20 webmentions, got %d", len(webmentions))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReceivingMultipleWebmentions(t *testing.T) {
|
|
||||||
repo := getTestRepo(owl.RepoConfig{})
|
|
||||||
repo.HttpClient = &MockHttpClient{}
|
|
||||||
repo.Parser = &MockHtmlParser{}
|
|
||||||
user, _ := repo.CreateUser("testuser")
|
|
||||||
post, _ := user.CreateNewPost("testpost")
|
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
wg.Add(20)
|
|
||||||
|
|
||||||
for i := 0; i < 20; i++ {
|
|
||||||
go func(k int) {
|
|
||||||
post.AddIncomingWebmention("http://example.com" + strconv.Itoa(k))
|
|
||||||
wg.Done()
|
|
||||||
}(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
webmentions := post.IncomingWebmentions()
|
|
||||||
|
|
||||||
if len(webmentions) != 20 {
|
|
||||||
t.Errorf("Expected 20 webmentions, got %d", len(webmentions))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSendingAndReceivingMultipleWebmentions(t *testing.T) {
|
|
||||||
repo := getTestRepo(owl.RepoConfig{})
|
|
||||||
repo.HttpClient = &MockHttpClient{}
|
|
||||||
repo.Parser = &MockHtmlParser{}
|
|
||||||
user, _ := repo.CreateUser("testuser")
|
|
||||||
post, _ := user.CreateNewPost("testpost")
|
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
wg.Add(40)
|
|
||||||
|
|
||||||
for i := 0; i < 20; i++ {
|
|
||||||
go func(k int) {
|
|
||||||
post.AddIncomingWebmention("http://example.com" + strconv.Itoa(k))
|
|
||||||
wg.Done()
|
|
||||||
}(i)
|
|
||||||
go func(k int) {
|
|
||||||
webmention := owl.WebmentionOut{
|
|
||||||
Target: "http://example.com" + strconv.Itoa(k),
|
|
||||||
}
|
|
||||||
post.SendWebmention(webmention)
|
|
||||||
wg.Done()
|
|
||||||
}(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
ins := post.IncomingWebmentions()
|
|
||||||
|
|
||||||
if len(ins) != 20 {
|
|
||||||
t.Errorf("Expected 20 webmentions, got %d", len(ins))
|
|
||||||
}
|
|
||||||
|
|
||||||
outs := post.OutgoingWebmentions()
|
|
||||||
|
|
||||||
if len(outs) != 20 {
|
|
||||||
t.Errorf("Expected 20 webmentions, got %d", len(outs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestComplexParallelWebmentions(t *testing.T) {
|
|
||||||
repo := getTestRepo(owl.RepoConfig{})
|
|
||||||
repo.HttpClient = &MockHttpClient{}
|
|
||||||
repo.Parser = &MockParseLinksHtmlParser{
|
|
||||||
Links: []string{
|
|
||||||
"http://example.com/1",
|
|
||||||
"http://example.com/2",
|
|
||||||
"http://example.com/3",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
user, _ := repo.CreateUser("testuser")
|
|
||||||
post, _ := user.CreateNewPost("testpost")
|
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
wg.Add(60)
|
|
||||||
|
|
||||||
for i := 0; i < 20; i++ {
|
|
||||||
go func(k int) {
|
|
||||||
post.AddIncomingWebmention("http://example.com/" + strconv.Itoa(k))
|
|
||||||
wg.Done()
|
|
||||||
}(i)
|
|
||||||
go func(k int) {
|
|
||||||
webmention := owl.WebmentionOut{
|
|
||||||
Target: "http://example.com/" + strconv.Itoa(k),
|
|
||||||
}
|
|
||||||
post.SendWebmention(webmention)
|
|
||||||
wg.Done()
|
|
||||||
}(i)
|
|
||||||
go func() {
|
|
||||||
post.ScanForLinks()
|
|
||||||
wg.Done()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
ins := post.IncomingWebmentions()
|
|
||||||
|
|
||||||
if len(ins) != 20 {
|
|
||||||
t.Errorf("Expected 20 webmentions, got %d", len(ins))
|
|
||||||
}
|
|
||||||
|
|
||||||
outs := post.OutgoingWebmentions()
|
|
||||||
|
|
||||||
if len(outs) != 20 {
|
|
||||||
t.Errorf("Expected 20 webmentions, got %d", len(outs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,18 +19,6 @@ type WebmentionIn struct {
|
||||||
RetrievedAt time.Time `yaml:"retrieved_at"`
|
RetrievedAt time.Time `yaml:"retrieved_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (webmention *WebmentionIn) UpdateWith(update WebmentionIn) {
|
|
||||||
if update.Title != "" {
|
|
||||||
webmention.Title = update.Title
|
|
||||||
}
|
|
||||||
if update.ApprovalStatus != "" {
|
|
||||||
webmention.ApprovalStatus = update.ApprovalStatus
|
|
||||||
}
|
|
||||||
if !update.RetrievedAt.IsZero() {
|
|
||||||
webmention.RetrievedAt = update.RetrievedAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type WebmentionOut struct {
|
type WebmentionOut struct {
|
||||||
Target string `yaml:"target"`
|
Target string `yaml:"target"`
|
||||||
Supported bool `yaml:"supported"`
|
Supported bool `yaml:"supported"`
|
||||||
|
@ -38,18 +26,6 @@ type WebmentionOut struct {
|
||||||
LastSentAt time.Time `yaml:"last_sent_at"`
|
LastSentAt time.Time `yaml:"last_sent_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (webmention *WebmentionOut) UpdateWith(update WebmentionOut) {
|
|
||||||
if update.Supported {
|
|
||||||
webmention.Supported = update.Supported
|
|
||||||
}
|
|
||||||
if !update.ScannedAt.IsZero() {
|
|
||||||
webmention.ScannedAt = update.ScannedAt
|
|
||||||
}
|
|
||||||
if !update.LastSentAt.IsZero() {
|
|
||||||
webmention.LastSentAt = update.LastSentAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type HttpClient interface {
|
type HttpClient interface {
|
||||||
Get(url string) (resp *http.Response, err error)
|
Get(url string) (resp *http.Response, err error)
|
||||||
Post(url, contentType string, body io.Reader) (resp *http.Response, err error)
|
Post(url, contentType string, body io.Reader) (resp *http.Response, err error)
|
||||||
|
|
|
@ -148,42 +148,42 @@ func TestGetWebmentionEndpointRelativeLinkInHeader(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// func TestRealWorldWebmention(t *testing.T) {
|
func TestRealWorldWebmention(t *testing.T) {
|
||||||
// links := []string{
|
links := []string{
|
||||||
// "https://webmention.rocks/test/1",
|
"https://webmention.rocks/test/1",
|
||||||
// "https://webmention.rocks/test/2",
|
"https://webmention.rocks/test/2",
|
||||||
// "https://webmention.rocks/test/3",
|
"https://webmention.rocks/test/3",
|
||||||
// "https://webmention.rocks/test/4",
|
"https://webmention.rocks/test/4",
|
||||||
// "https://webmention.rocks/test/5",
|
"https://webmention.rocks/test/5",
|
||||||
// "https://webmention.rocks/test/6",
|
"https://webmention.rocks/test/6",
|
||||||
// "https://webmention.rocks/test/7",
|
"https://webmention.rocks/test/7",
|
||||||
// "https://webmention.rocks/test/8",
|
"https://webmention.rocks/test/8",
|
||||||
// "https://webmention.rocks/test/9",
|
"https://webmention.rocks/test/9",
|
||||||
// // "https://webmention.rocks/test/10", // not supported
|
// "https://webmention.rocks/test/10", // not supported
|
||||||
// "https://webmention.rocks/test/11",
|
"https://webmention.rocks/test/11",
|
||||||
// "https://webmention.rocks/test/12",
|
"https://webmention.rocks/test/12",
|
||||||
// "https://webmention.rocks/test/13",
|
"https://webmention.rocks/test/13",
|
||||||
// "https://webmention.rocks/test/14",
|
"https://webmention.rocks/test/14",
|
||||||
// "https://webmention.rocks/test/15",
|
"https://webmention.rocks/test/15",
|
||||||
// "https://webmention.rocks/test/16",
|
"https://webmention.rocks/test/16",
|
||||||
// "https://webmention.rocks/test/17",
|
"https://webmention.rocks/test/17",
|
||||||
// "https://webmention.rocks/test/18",
|
"https://webmention.rocks/test/18",
|
||||||
// "https://webmention.rocks/test/19",
|
"https://webmention.rocks/test/19",
|
||||||
// "https://webmention.rocks/test/20",
|
"https://webmention.rocks/test/20",
|
||||||
// "https://webmention.rocks/test/21",
|
"https://webmention.rocks/test/21",
|
||||||
// "https://webmention.rocks/test/22",
|
"https://webmention.rocks/test/22",
|
||||||
// "https://webmention.rocks/test/23/page",
|
"https://webmention.rocks/test/23/page",
|
||||||
// }
|
}
|
||||||
|
|
||||||
// for _, link := range links {
|
for _, link := range links {
|
||||||
// parser := &owl.OwlHtmlParser{}
|
parser := &owl.OwlHtmlParser{}
|
||||||
// client := &owl.OwlHttpClient{}
|
client := &owl.OwlHttpClient{}
|
||||||
// html, _ := client.Get(link)
|
html, _ := client.Get(link)
|
||||||
// _, err := parser.GetWebmentionEndpoint(html)
|
_, err := parser.GetWebmentionEndpoint(html)
|
||||||
|
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// t.Errorf("Unable to find webmention: %v for link %v", err, link)
|
t.Errorf("Unable to find webmention: %v for link %v", err, link)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// }
|
}
|
||||||
|
|
Loading…
Reference in New Issue