mirror of https://github.com/jlelse/GoBlog
Custom webmention sending implementation and other improvements
This commit is contained in:
parent
6dd99289ad
commit
3a866fb3c0
|
@ -221,7 +221,7 @@ func apGetRemoteActor(iri string) (*asPerson, int, error) {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
req.Header.Set("Accept", contentTypeAS)
|
req.Header.Set("Accept", contentTypeAS)
|
||||||
req.Header.Set("User-Agent", "GoBlog")
|
req.Header.Set(userAgent, appUserAgent)
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
@ -273,7 +273,7 @@ func (p *post) apPost() {
|
||||||
createActivity := make(map[string]interface{})
|
createActivity := make(map[string]interface{})
|
||||||
createActivity["@context"] = asContext
|
createActivity["@context"] = asContext
|
||||||
createActivity["actor"] = appConfig.Blogs[p.Blog].apIri()
|
createActivity["actor"] = appConfig.Blogs[p.Blog].apIri()
|
||||||
createActivity["id"] = appConfig.Server.PublicAddress + p.Path
|
createActivity["id"] = p.fullURL()
|
||||||
createActivity["published"] = n.Published
|
createActivity["published"] = n.Published
|
||||||
createActivity["type"] = "Create"
|
createActivity["type"] = "Create"
|
||||||
createActivity["object"] = n
|
createActivity["object"] = n
|
||||||
|
@ -293,7 +293,7 @@ func (p *post) apUpdate() {
|
||||||
updateActivity := make(map[string]interface{})
|
updateActivity := make(map[string]interface{})
|
||||||
updateActivity["@context"] = asContext
|
updateActivity["@context"] = asContext
|
||||||
updateActivity["actor"] = appConfig.Blogs[p.Blog].apIri()
|
updateActivity["actor"] = appConfig.Blogs[p.Blog].apIri()
|
||||||
updateActivity["id"] = appConfig.Server.PublicAddress + p.Path
|
updateActivity["id"] = p.fullURL()
|
||||||
updateActivity["published"] = time.Now().Format("2006-01-02T15:04:05-07:00")
|
updateActivity["published"] = time.Now().Format("2006-01-02T15:04:05-07:00")
|
||||||
updateActivity["type"] = "Update"
|
updateActivity["type"] = "Update"
|
||||||
updateActivity["object"] = n
|
updateActivity["object"] = n
|
||||||
|
@ -307,10 +307,10 @@ func (p *post) apAnnounce() {
|
||||||
announceActivity := make(map[string]interface{})
|
announceActivity := make(map[string]interface{})
|
||||||
announceActivity["@context"] = asContext
|
announceActivity["@context"] = asContext
|
||||||
announceActivity["actor"] = appConfig.Blogs[p.Blog].apIri()
|
announceActivity["actor"] = appConfig.Blogs[p.Blog].apIri()
|
||||||
announceActivity["id"] = appConfig.Server.PublicAddress + p.Path + "#announce"
|
announceActivity["id"] = p.fullURL() + "#announce"
|
||||||
announceActivity["published"] = p.toASNote().Published
|
announceActivity["published"] = p.toASNote().Published
|
||||||
announceActivity["type"] = "Announce"
|
announceActivity["type"] = "Announce"
|
||||||
announceActivity["object"] = appConfig.Server.PublicAddress + p.Path
|
announceActivity["object"] = p.fullURL()
|
||||||
apSendToAllFollowers(p.Blog, announceActivity)
|
apSendToAllFollowers(p.Blog, announceActivity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,10 +321,10 @@ func (p *post) apDelete() {
|
||||||
deleteActivity := make(map[string]interface{})
|
deleteActivity := make(map[string]interface{})
|
||||||
deleteActivity["@context"] = asContext
|
deleteActivity["@context"] = asContext
|
||||||
deleteActivity["actor"] = appConfig.Blogs[p.Blog].apIri()
|
deleteActivity["actor"] = appConfig.Blogs[p.Blog].apIri()
|
||||||
deleteActivity["id"] = appConfig.Server.PublicAddress + p.Path + "#delete"
|
deleteActivity["id"] = p.fullURL() + "#delete"
|
||||||
deleteActivity["type"] = "Delete"
|
deleteActivity["type"] = "Delete"
|
||||||
deleteActivity["object"] = map[string]string{
|
deleteActivity["object"] = map[string]string{
|
||||||
"id": appConfig.Server.PublicAddress + p.Path,
|
"id": p.fullURL(),
|
||||||
"type": "Tombstone",
|
"type": "Tombstone",
|
||||||
}
|
}
|
||||||
apSendToAllFollowers(p.Blog, deleteActivity)
|
apSendToAllFollowers(p.Blog, deleteActivity)
|
||||||
|
@ -405,7 +405,7 @@ func apSendSigned(blog *configBlog, activity interface{}, to string) error {
|
||||||
}
|
}
|
||||||
r.Header.Set("Accept-Charset", "utf-8")
|
r.Header.Set("Accept-Charset", "utf-8")
|
||||||
r.Header.Set("Date", time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
|
r.Header.Set("Date", time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
|
||||||
r.Header.Set("User-Agent", "GoBlog")
|
r.Header.Set(userAgent, appUserAgent)
|
||||||
r.Header.Set("Accept", contentTypeASUTF8)
|
r.Header.Set("Accept", contentTypeASUTF8)
|
||||||
r.Header.Set(contentType, contentTypeASUTF8)
|
r.Header.Set(contentType, contentTypeASUTF8)
|
||||||
r.Header.Set("Host", iri.Host)
|
r.Header.Set("Host", iri.Host)
|
||||||
|
|
|
@ -74,8 +74,8 @@ func (p *post) toASNote() *asNote {
|
||||||
Context: asContext,
|
Context: asContext,
|
||||||
To: []string{"https://www.w3.org/ns/activitystreams#Public"},
|
To: []string{"https://www.w3.org/ns/activitystreams#Public"},
|
||||||
MediaType: contentTypeHTML,
|
MediaType: contentTypeHTML,
|
||||||
ID: appConfig.Server.PublicAddress + p.Path,
|
ID: p.fullURL(),
|
||||||
URL: appConfig.Server.PublicAddress + p.Path,
|
URL: p.fullURL(),
|
||||||
AttributedTo: appConfig.Blogs[p.Blog].apIri(),
|
AttributedTo: appConfig.Blogs[p.Blog].apIri(),
|
||||||
}
|
}
|
||||||
// Name and Type
|
// Name and Type
|
||||||
|
@ -133,8 +133,8 @@ func (b *configBlog) serveActivityStreams(blog string, w http.ResponseWriter) {
|
||||||
PreferredUsername: blog,
|
PreferredUsername: blog,
|
||||||
Inbox: appConfig.Server.PublicAddress + "/activitypub/inbox/" + blog,
|
Inbox: appConfig.Server.PublicAddress + "/activitypub/inbox/" + blog,
|
||||||
PublicKey: &asPublicKey{
|
PublicKey: &asPublicKey{
|
||||||
Owner: appConfig.Server.PublicAddress + b.Path,
|
Owner: b.apIri(),
|
||||||
ID: appConfig.Server.PublicAddress + b.Path + "#main-key",
|
ID: b.apIri() + "#main-key",
|
||||||
PublicKeyPem: string(pem.EncodeToMemory(&pem.Block{
|
PublicKeyPem: string(pem.EncodeToMemory(&pem.Block{
|
||||||
Type: "PUBLIC KEY",
|
Type: "PUBLIC KEY",
|
||||||
Headers: nil,
|
Headers: nil,
|
||||||
|
|
2
api.go
2
api.go
|
@ -55,6 +55,6 @@ func apiPostCreateHugo(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Header().Set("Location", appConfig.Server.PublicAddress+p.Path)
|
w.Header().Set("Location", p.fullURL())
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
2
feeds.go
2
feeds.go
|
@ -55,7 +55,7 @@ func generateFeed(blog string, f feedType, w http.ResponseWriter, r *http.Reques
|
||||||
}
|
}
|
||||||
feed.Add(&feeds.Item{
|
feed.Add(&feeds.Item{
|
||||||
Title: p.title(),
|
Title: p.title(),
|
||||||
Link: &feeds.Link{Href: appConfig.Server.PublicAddress + p.Path},
|
Link: &feeds.Link{Href: p.fullURL()},
|
||||||
Description: p.summary(),
|
Description: p.summary(),
|
||||||
Id: p.Path,
|
Id: p.Path,
|
||||||
Content: string(p.html()),
|
Content: string(p.html()),
|
||||||
|
|
10
go.mod
10
go.mod
|
@ -24,7 +24,7 @@ require (
|
||||||
github.com/kyokomi/emoji v2.2.4+incompatible
|
github.com/kyokomi/emoji v2.2.4+incompatible
|
||||||
github.com/lopezator/migrator v0.3.0
|
github.com/lopezator/migrator v0.3.0
|
||||||
github.com/magiconair/properties v1.8.4 // indirect
|
github.com/magiconair/properties v1.8.4 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.4
|
github.com/mattn/go-sqlite3 v1.14.5
|
||||||
github.com/miekg/dns v1.1.35 // indirect
|
github.com/miekg/dns v1.1.35 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.3.3 // indirect
|
github.com/mitchellh/mapstructure v1.3.3 // indirect
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
|
@ -37,23 +37,23 @@ require (
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.1
|
||||||
github.com/tdewolff/minify/v2 v2.9.10
|
github.com/tdewolff/minify/v2 v2.9.10
|
||||||
|
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
||||||
github.com/vcraescu/go-paginator v1.0.0
|
github.com/vcraescu/go-paginator v1.0.0
|
||||||
github.com/yuin/goldmark v1.2.1
|
github.com/yuin/goldmark v1.2.1
|
||||||
github.com/yuin/goldmark-emoji v1.0.1
|
github.com/yuin/goldmark-emoji v1.0.1
|
||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
go.uber.org/zap v1.16.0 // indirect
|
go.uber.org/zap v1.16.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9
|
golang.org/x/crypto v0.0.0-20201116153603-4be66e5b6582
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
||||||
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba // indirect
|
golang.org/x/sys v0.0.0-20201116161645-c061ba923fbb // indirect
|
||||||
golang.org/x/text v0.3.4 // indirect
|
golang.org/x/text v0.3.4 // indirect
|
||||||
golang.org/x/tools v0.0.0-20201116002733-ac45abd4c88c // indirect
|
golang.org/x/tools v0.0.0-20201116172350-d68bbb546781 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||||
honnef.co/go/tools v0.0.1-2020.1.6 // indirect
|
honnef.co/go/tools v0.0.1-2020.1.6 // indirect
|
||||||
willnorris.com/go/microformats v1.1.1
|
willnorris.com/go/microformats v1.1.1
|
||||||
willnorris.com/go/webmention v0.0.0-20200623235404-057ea514ab98
|
|
||||||
)
|
)
|
||||||
|
|
26
go.sum
26
go.sum
|
@ -208,8 +208,8 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
|
||||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||||
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||||
github.com/mattn/go-sqlite3 v1.14.4 h1:4rQjbDxdu9fSgI/r3KN72G3c2goxknAqHHgPWWs8UlI=
|
github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ=
|
||||||
github.com/mattn/go-sqlite3 v1.14.4/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mholt/acmez v0.1.1 h1:KQODCqk+hBn3O7qfCRPj6L96uG65T5BSS95FKNEqtdA=
|
github.com/mholt/acmez v0.1.1 h1:KQODCqk+hBn3O7qfCRPj6L96uG65T5BSS95FKNEqtdA=
|
||||||
|
@ -315,10 +315,10 @@ github.com/tdewolff/parse/v2 v2.5.5/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1I
|
||||||
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
||||||
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
|
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
|
||||||
|
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
|
||||||
github.com/vcraescu/go-paginator v1.0.0 h1:ilNmRhlgG8N44LuxfGoPI2u8guXMA6gUqaPGA5BmRFs=
|
github.com/vcraescu/go-paginator v1.0.0 h1:ilNmRhlgG8N44LuxfGoPI2u8guXMA6gUqaPGA5BmRFs=
|
||||||
github.com/vcraescu/go-paginator v1.0.0/go.mod h1:caZCjjt2qcA1O2aDzW7lwAcK4Rxw3LNvdEVF/ONxZWw=
|
github.com/vcraescu/go-paginator v1.0.0/go.mod h1:caZCjjt2qcA1O2aDzW7lwAcK4Rxw3LNvdEVF/ONxZWw=
|
||||||
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 h1:3UeQBvD0TFrlVjOeLOBz+CPAI8dnbqNSVwUwRrkp7vQ=
|
|
||||||
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM=
|
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
|
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
|
||||||
|
@ -357,8 +357,8 @@ golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPh
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 h1:umElSU9WZirRdgu2yFHY0ayQkEnKiOC1TtM3fWXFnoU=
|
golang.org/x/crypto v0.0.0-20201116153603-4be66e5b6582 h1:0WDrJ1E7UolDk1KhTXxxw3Fc8qtk5x7dHP431KHEJls=
|
||||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201116153603-4be66e5b6582/go.mod h1:tCqSYrHVcf3i63Co2FzBkTCo2gdF6Zak62921dSfraU=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
@ -387,7 +387,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
@ -438,12 +437,15 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
|
||||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba h1:xmhUJGQGbxlod18iJGqVEp9cHIPLl7QiX2aA3to708s=
|
golang.org/x/sys v0.0.0-20201116161645-c061ba923fbb h1:+EHGEcgeA7ESswi5i4ojbo7sRzlz7vWoxFGcMuEZtu8=
|
||||||
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201116161645-c061ba923fbb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/term v0.0.0-20201113234701-d7a72108b828 h1:htWEtQEuEVJ4tU/Ngx7Cd/4Q7e3A5Up1owgyBtVsTwk=
|
||||||
|
golang.org/x/term v0.0.0-20201113234701-d7a72108b828/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
@ -478,8 +480,8 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnf
|
||||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20201116002733-ac45abd4c88c h1:quJUizHRFn7XriXTIOCLKSr76x2cMbNGfvfy9ubOO0g=
|
golang.org/x/tools v0.0.0-20201116172350-d68bbb546781 h1:pupwog4teA+VTW6Kpi3Z6f0AR4+5MBi0+AN5ym9fzaQ=
|
||||||
golang.org/x/tools v0.0.0-20201116002733-ac45abd4c88c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201116172350-d68bbb546781/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
@ -544,5 +546,3 @@ honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzE
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
willnorris.com/go/microformats v1.1.1 h1:h5tk2luq6KBIRcwMGdksxdeea4GGuWrRFie5460OAbo=
|
willnorris.com/go/microformats v1.1.1 h1:h5tk2luq6KBIRcwMGdksxdeea4GGuWrRFie5460OAbo=
|
||||||
willnorris.com/go/microformats v1.1.1/go.mod h1:kvVnWrkkEscVAIITCEoiTX66Hcyg59C7q0E49mb9TJ0=
|
willnorris.com/go/microformats v1.1.1/go.mod h1:kvVnWrkkEscVAIITCEoiTX66Hcyg59C7q0E49mb9TJ0=
|
||||||
willnorris.com/go/webmention v0.0.0-20200623235404-057ea514ab98 h1:06Zf8bMVQ+OBHceFvlr/SYZyYnkyVlWIkvediXHyQQU=
|
|
||||||
willnorris.com/go/webmention v0.0.0-20200623235404-057ea514ab98/go.mod h1:p+ZRAsZS2pzZ6kX3GKWYurf3WZI2ygj7VbR8NM8qwfM=
|
|
||||||
|
|
6
hooks.go
6
hooks.go
|
@ -21,7 +21,7 @@ func (p *post) postPostHooks() {
|
||||||
for _, cmdTmplString := range appConfig.Hooks.PostPost {
|
for _, cmdTmplString := range appConfig.Hooks.PostPost {
|
||||||
go func(p *post, cmdTmplString string) {
|
go func(p *post, cmdTmplString string) {
|
||||||
executeTemplateCommand("post-post", cmdTmplString, map[string]interface{}{
|
executeTemplateCommand("post-post", cmdTmplString, map[string]interface{}{
|
||||||
"URL": appConfig.Server.PublicAddress + p.Path,
|
"URL": p.fullURL(),
|
||||||
"Post": p,
|
"Post": p,
|
||||||
})
|
})
|
||||||
}(p, cmdTmplString)
|
}(p, cmdTmplString)
|
||||||
|
@ -38,7 +38,7 @@ func (p *post) postUpdateHooks() {
|
||||||
for _, cmdTmplString := range appConfig.Hooks.PostUpdate {
|
for _, cmdTmplString := range appConfig.Hooks.PostUpdate {
|
||||||
go func(p *post, cmdTmplString string) {
|
go func(p *post, cmdTmplString string) {
|
||||||
executeTemplateCommand("post-update", cmdTmplString, map[string]interface{}{
|
executeTemplateCommand("post-update", cmdTmplString, map[string]interface{}{
|
||||||
"URL": appConfig.Server.PublicAddress + p.Path,
|
"URL": p.fullURL(),
|
||||||
"Post": p,
|
"Post": p,
|
||||||
})
|
})
|
||||||
}(p, cmdTmplString)
|
}(p, cmdTmplString)
|
||||||
|
@ -54,7 +54,7 @@ func (p *post) postDeleteHooks() {
|
||||||
for _, cmdTmplString := range appConfig.Hooks.PostDelete {
|
for _, cmdTmplString := range appConfig.Hooks.PostDelete {
|
||||||
go func(p *post, cmdTmplString string) {
|
go func(p *post, cmdTmplString string) {
|
||||||
executeTemplateCommand("post-delete", cmdTmplString, map[string]interface{}{
|
executeTemplateCommand("post-delete", cmdTmplString, map[string]interface{}{
|
||||||
"URL": appConfig.Server.PublicAddress + p.Path,
|
"URL": p.fullURL(),
|
||||||
"Post": p,
|
"Post": p,
|
||||||
})
|
})
|
||||||
}(p, cmdTmplString)
|
}(p, cmdTmplString)
|
||||||
|
|
3
http.go
3
http.go
|
@ -27,6 +27,9 @@ const (
|
||||||
contentTypeHTMLUTF8 = contentTypeHTML + charsetUtf8Suffix
|
contentTypeHTMLUTF8 = contentTypeHTML + charsetUtf8Suffix
|
||||||
contentTypeJSONUTF8 = contentTypeJSON + charsetUtf8Suffix
|
contentTypeJSONUTF8 = contentTypeJSON + charsetUtf8Suffix
|
||||||
contentTypeASUTF8 = contentTypeAS + charsetUtf8Suffix
|
contentTypeASUTF8 = contentTypeAS + charsetUtf8Suffix
|
||||||
|
|
||||||
|
userAgent = "User-Agent"
|
||||||
|
appUserAgent = "GoBlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -100,7 +100,7 @@ func (p *post) toMfItem() *microformatItem {
|
||||||
Updated: []string{p.Updated},
|
Updated: []string{p.Updated},
|
||||||
Category: p.Parameters[appConfig.Micropub.CategoryParam],
|
Category: p.Parameters[appConfig.Micropub.CategoryParam],
|
||||||
Content: []string{content},
|
Content: []string{content},
|
||||||
URL: []string{appConfig.Server.PublicAddress + p.Path},
|
URL: []string{p.fullURL()},
|
||||||
InReplyTo: p.Parameters[appConfig.Micropub.ReplyParam],
|
InReplyTo: p.Parameters[appConfig.Micropub.ReplyParam],
|
||||||
LikeOf: p.Parameters[appConfig.Micropub.LikeParam],
|
LikeOf: p.Parameters[appConfig.Micropub.LikeParam],
|
||||||
BookmarkOf: p.Parameters[appConfig.Micropub.BookmarkParam],
|
BookmarkOf: p.Parameters[appConfig.Micropub.BookmarkParam],
|
||||||
|
@ -181,7 +181,7 @@ func serveMicropubPost(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Add("Location", appConfig.Server.PublicAddress+p.Path)
|
w.Header().Add("Location", p.fullURL())
|
||||||
w.WriteHeader(http.StatusAccepted)
|
w.WriteHeader(http.StatusAccepted)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
75
posts.go
75
posts.go
|
@ -47,7 +47,7 @@ func servePost(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
canonical := p.firstParameter("original")
|
canonical := p.firstParameter("original")
|
||||||
if canonical == "" {
|
if canonical == "" {
|
||||||
canonical = appConfig.Server.PublicAddress + p.Path
|
canonical = p.fullURL()
|
||||||
}
|
}
|
||||||
render(w, templatePost, &renderData{
|
render(w, templatePost, &renderData{
|
||||||
blogString: p.Blog,
|
blogString: p.Blog,
|
||||||
|
@ -56,18 +56,6 @@ func servePost(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type indexTemplateData struct {
|
|
||||||
Blog string
|
|
||||||
Title string
|
|
||||||
Description string
|
|
||||||
Posts []*post
|
|
||||||
HasPrev bool
|
|
||||||
HasNext bool
|
|
||||||
First string
|
|
||||||
Prev string
|
|
||||||
Next string
|
|
||||||
}
|
|
||||||
|
|
||||||
type postPaginationAdapter struct {
|
type postPaginationAdapter struct {
|
||||||
config *postsRequestConfig
|
config *postsRequestConfig
|
||||||
nums int
|
nums int
|
||||||
|
@ -148,29 +136,32 @@ func serveTaxonomyValue(blog string, path string, tax *taxonomy, value string) f
|
||||||
|
|
||||||
func servePhotos(blog string, path string) func(w http.ResponseWriter, r *http.Request) {
|
func servePhotos(blog string, path string) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return serveIndex(&indexConfig{
|
return serveIndex(&indexConfig{
|
||||||
blog: blog,
|
blog: blog,
|
||||||
path: path,
|
path: path,
|
||||||
parameter: appConfig.Blogs[blog].Photos.Parameter,
|
parameter: appConfig.Blogs[blog].Photos.Parameter,
|
||||||
template: templatePhotos,
|
title: appConfig.Blogs[blog].Photos.Title,
|
||||||
|
description: appConfig.Blogs[blog].Photos.Description,
|
||||||
|
summaryTemplate: templatePhotosSummary,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveSearchResults(blog string, path string) func(w http.ResponseWriter, r *http.Request) {
|
func serveSearchResults(blog string, path string) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return serveIndex(&indexConfig{
|
return serveIndex(&indexConfig{
|
||||||
blog: blog,
|
blog: blog,
|
||||||
path: path,
|
path: path,
|
||||||
template: templateIndex,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type indexConfig struct {
|
type indexConfig struct {
|
||||||
blog string
|
blog string
|
||||||
path string
|
path string
|
||||||
section *section
|
section *section
|
||||||
tax *taxonomy
|
tax *taxonomy
|
||||||
taxValue string
|
taxValue string
|
||||||
parameter string
|
parameter string
|
||||||
template string
|
title string
|
||||||
|
description string
|
||||||
|
summaryTemplate string
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
|
func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -205,7 +196,8 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Meta
|
// Meta
|
||||||
var title, description string
|
title := ic.title
|
||||||
|
description := ic.description
|
||||||
if ic.tax != nil {
|
if ic.tax != nil {
|
||||||
title = fmt.Sprintf("%s: %s", ic.tax.Title, ic.taxValue)
|
title = fmt.Sprintf("%s: %s", ic.tax.Title, ic.taxValue)
|
||||||
} else if ic.section != nil {
|
} else if ic.section != nil {
|
||||||
|
@ -238,22 +230,23 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
|
||||||
nextPage = p.Page()
|
nextPage = p.Page()
|
||||||
}
|
}
|
||||||
nextPath := fmt.Sprintf("%s/page/%d", path, nextPage)
|
nextPath := fmt.Sprintf("%s/page/%d", path, nextPage)
|
||||||
template := ic.template
|
summaryTemplate := ic.summaryTemplate
|
||||||
if len(template) == 0 {
|
if summaryTemplate == "" {
|
||||||
template = templateIndex
|
summaryTemplate = templateSummary
|
||||||
}
|
}
|
||||||
render(w, template, &renderData{
|
render(w, templateIndex, &renderData{
|
||||||
blogString: ic.blog,
|
blogString: ic.blog,
|
||||||
Canonical: appConfig.Server.PublicAddress + getBlogRelativePath(ic.blog, path),
|
Canonical: appConfig.Server.PublicAddress + getBlogRelativePath(ic.blog, path),
|
||||||
Data: &indexTemplateData{
|
Data: map[string]interface{}{
|
||||||
Title: title,
|
"Title": title,
|
||||||
Description: description,
|
"Description": description,
|
||||||
Posts: posts,
|
"Posts": posts,
|
||||||
HasPrev: p.HasPrev(),
|
"HasPrev": p.HasPrev(),
|
||||||
HasNext: p.HasNext(),
|
"HasNext": p.HasNext(),
|
||||||
First: getBlogRelativePath(ic.blog, path),
|
"First": getBlogRelativePath(ic.blog, path),
|
||||||
Prev: getBlogRelativePath(ic.blog, prevPath),
|
"Prev": getBlogRelativePath(ic.blog, prevPath),
|
||||||
Next: getBlogRelativePath(ic.blog, nextPath),
|
"Next": getBlogRelativePath(ic.blog, nextPath),
|
||||||
|
"SummaryTemplate": summaryTemplate,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,10 @@ import (
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (p *post) fullURL() string {
|
||||||
|
return appConfig.Server.PublicAddress + p.Path
|
||||||
|
}
|
||||||
|
|
||||||
func (p *post) firstParameter(parameter string) (result string) {
|
func (p *post) firstParameter(parameter string) (result string) {
|
||||||
if pp := p.Parameters[parameter]; len(pp) > 0 {
|
if pp := p.Parameters[parameter]; len(pp) > 0 {
|
||||||
result = pp[0]
|
result = pp[0]
|
||||||
|
|
|
@ -27,8 +27,9 @@ const templatePost = "post"
|
||||||
const templateError = "error"
|
const templateError = "error"
|
||||||
const templateIndex = "index"
|
const templateIndex = "index"
|
||||||
const templateTaxonomy = "taxonomy"
|
const templateTaxonomy = "taxonomy"
|
||||||
const templatePhotos = "photos"
|
|
||||||
const templateSearch = "search"
|
const templateSearch = "search"
|
||||||
|
const templateSummary = "summary"
|
||||||
|
const templatePhotosSummary = "photosummary"
|
||||||
|
|
||||||
var templates map[string]*template.Template
|
var templates map[string]*template.Template
|
||||||
var templateFunctions template.FuncMap
|
var templateFunctions template.FuncMap
|
||||||
|
@ -76,7 +77,7 @@ func initRendering() error {
|
||||||
},
|
},
|
||||||
"postmentions": func(p *post) []*mention {
|
"postmentions": func(p *post) []*mention {
|
||||||
mentions, _ := getWebmentions(&webmentionsRequestConfig{
|
mentions, _ := getWebmentions(&webmentionsRequestConfig{
|
||||||
target: appConfig.Server.PublicAddress + p.Path,
|
target: p.fullURL(),
|
||||||
status: webmentionStatusApproved,
|
status: webmentionStatusApproved,
|
||||||
asc: true,
|
asc: true,
|
||||||
})
|
})
|
||||||
|
|
|
@ -19,7 +19,7 @@ func serveSitemap(w http.ResponseWriter, r *http.Request) {
|
||||||
sm.Minify = true
|
sm.Minify = true
|
||||||
for _, p := range posts {
|
for _, p := range posts {
|
||||||
item := &sitemap.URL{
|
item := &sitemap.URL{
|
||||||
Loc: appConfig.Server.PublicAddress + p.Path}
|
Loc: p.fullURL()}
|
||||||
var lastMod time.Time
|
var lastMod time.Time
|
||||||
if p.Updated != "" {
|
if p.Updated != "" {
|
||||||
lastMod, _ = dateparse.ParseIn(p.Updated, time.Local)
|
lastMod, _ = dateparse.ParseIn(p.Updated, time.Local)
|
||||||
|
|
|
@ -18,7 +18,7 @@ func (p *post) tgPost() {
|
||||||
message.WriteString(title)
|
message.WriteString(title)
|
||||||
message.WriteString("\n\n")
|
message.WriteString("\n\n")
|
||||||
}
|
}
|
||||||
message.WriteString(appConfig.Server.PublicAddress + p.Path)
|
message.WriteString(p.fullURL())
|
||||||
sendTelegramMessage(message.String(), appConfig.Blogs[p.Blog].Telegram.BotToken, appConfig.Blogs[p.Blog].Telegram.ChatID)
|
sendTelegramMessage(message.String(), appConfig.Blogs[p.Blog].Telegram.BotToken, appConfig.Blogs[p.Blog].Telegram.ChatID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,9 @@
|
||||||
<hr>
|
<hr>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ $blog := .Blog }}
|
{{ $blog := .Blog }}
|
||||||
|
{{ $summaryTemplate := .Data.SummaryTemplate }}
|
||||||
{{ range $i, $post := .Data.Posts }}
|
{{ range $i, $post := .Data.Posts }}
|
||||||
{{ include "summary" $blog $post }}
|
{{ include $summaryTemplate $blog $post }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ if .Data.HasPrev }}
|
{{ if .Data.HasPrev }}
|
||||||
<p><a href="{{ .Data.Prev }}">{{ string .Blog.Lang "prev" }}</a></p>
|
<p><a href="{{ .Data.Prev }}">{{ string .Blog.Lang "prev" }}</a></p>
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
{{ define "title" }}
|
|
||||||
<title>{{ with .Blog.Photos.Title }}{{ . }} - {{ end }}{{ .Blog.Title }}</title>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ define "main" }}
|
|
||||||
<main>
|
|
||||||
{{ with .Blog.Photos.Title }}<h1>{{ . }}</h1>{{ end }}
|
|
||||||
{{ with .Blog.Photos.Description }}{{ md . }}{{ end }}
|
|
||||||
{{ if (or .Blog.Photos.Title .Blog.Photos.Description) }}
|
|
||||||
<hr>
|
|
||||||
{{ end }}
|
|
||||||
{{ $blog := .Blog }}
|
|
||||||
{{ range $i, $post := .Data.Posts }}
|
|
||||||
{{ include "photosummary" $blog $post }}
|
|
||||||
{{ end }}
|
|
||||||
{{ if .Data.HasPrev }}
|
|
||||||
<p><a href="{{ .Data.Prev }}">{{ string .Blog.Lang "prev" }}</a></p>
|
|
||||||
{{ end }}
|
|
||||||
{{ if .Data.HasNext }}
|
|
||||||
<p><a href="{{ .Data.Next }}">{{ string .Blog.Lang "next" }}</a></p>
|
|
||||||
{{ end }}
|
|
||||||
</main>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ define "photos" }}
|
|
||||||
{{ template "base" . }}
|
|
||||||
{{ end }}
|
|
|
@ -1,23 +0,0 @@
|
||||||
{{ define "title" }}{{ end }}
|
|
||||||
|
|
||||||
{{ define "main" }}
|
|
||||||
<main class=h-entry>
|
|
||||||
<article>
|
|
||||||
<data class="u-url hide" value="{{ absolute .Data.Path }}"></data>
|
|
||||||
{{ with title .Data }}<h1 class=p-name>{{ . }}</h1>{{ end }}
|
|
||||||
{{ include "postmeta" . }}
|
|
||||||
{{ if .Data.Content }}
|
|
||||||
<div class=e-content>
|
|
||||||
{{ content .Data }}
|
|
||||||
{{ with p .Data "link" }}
|
|
||||||
<p><a class="u-bookmark-of" href="{{ . }}" target="_blank" rel="noopener">{{ . }}</a></p>
|
|
||||||
{{ end }}
|
|
||||||
</div>
|
|
||||||
{{ end }}
|
|
||||||
</article>
|
|
||||||
</main>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ define "postbasic" }}
|
|
||||||
{{ template "base" . }}
|
|
||||||
{{ end }}
|
|
|
@ -9,7 +9,11 @@
|
||||||
{{ $blog := .Blog }}
|
{{ $blog := .Blog }}
|
||||||
{{ range $i, $mention := .Data.Verified }}
|
{{ range $i, $mention := .Data.Verified }}
|
||||||
<div class="p">
|
<div class="p">
|
||||||
<p>From: {{ $mention.Source }}<br/>To: {{ $mention.Target }}<br/>Created: {{ unixtodate $mention.Created }}</p>
|
<p>
|
||||||
|
From: <a href="{{ $mention.Source }}" target="_blank" rel="noopener noreferrer">{{ $mention.Source }}</a><br/>
|
||||||
|
To: <a href="{{ $mention.Target }}" target="_blank">{{ $mention.Target }}</a><br/>
|
||||||
|
Created: {{ unixtodate $mention.Created }}
|
||||||
|
</p>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="submit" formaction="/webmention/admin/approve/{{ $mention.ID }}" value="{{ string $blog.Lang "approve" }}">
|
<input type="submit" formaction="/webmention/admin/approve/{{ $mention.ID }}" value="{{ string $blog.Lang "approve" }}">
|
||||||
<input type="submit" formaction="/webmention/admin/delete/{{ $mention.ID }}" value="{{ string $blog.Lang "delete" }}">
|
<input type="submit" formaction="/webmention/admin/delete/{{ $mention.ID }}" value="{{ string $blog.Lang "delete" }}">
|
||||||
|
|
27
utils.go
27
utils.go
|
@ -71,10 +71,6 @@ func isAbsoluteURL(s string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func allLinksFromHTML(r io.Reader, baseURL string) ([]string, error) {
|
func allLinksFromHTML(r io.Reader, baseURL string) ([]string, error) {
|
||||||
bu, err := url.Parse(baseURL)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
doc, err := goquery.NewDocumentFromReader(r)
|
doc, err := goquery.NewDocumentFromReader(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -82,10 +78,25 @@ func allLinksFromHTML(r io.Reader, baseURL string) ([]string, error) {
|
||||||
links := []string{}
|
links := []string{}
|
||||||
doc.Find("a[href]").Each(func(_ int, item *goquery.Selection) {
|
doc.Find("a[href]").Each(func(_ int, item *goquery.Selection) {
|
||||||
if href, exists := item.Attr("href"); exists {
|
if href, exists := item.Attr("href"); exists {
|
||||||
if ref, err := url.Parse(href); err == nil {
|
links = append(links, href)
|
||||||
links = append(links, bu.ResolveReference(ref).String())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return links, nil
|
links, err = resolveURLReferences(baseURL, links...)
|
||||||
|
return links, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveURLReferences(base string, refs ...string) ([]string, error) {
|
||||||
|
b, err := url.Parse(base)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var urls []string
|
||||||
|
for _, r := range refs {
|
||||||
|
u, err := url.Parse(r)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
urls = append(urls, b.ResolveReference(u).String())
|
||||||
|
}
|
||||||
|
return urls, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -12,7 +11,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
"willnorris.com/go/webmention"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type webmentionStatus string
|
type webmentionStatus string
|
||||||
|
@ -38,15 +36,6 @@ func initWebmention() {
|
||||||
startWebmentionVerifier()
|
startWebmentionVerifier()
|
||||||
}
|
}
|
||||||
|
|
||||||
func startWebmentionVerifier() {
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
time.Sleep(30 * time.Second)
|
|
||||||
verifyNextWebmention()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleWebmention(w http.ResponseWriter, r *http.Request) {
|
func handleWebmention(w http.ResponseWriter, r *http.Request) {
|
||||||
m, err := extractMention(r)
|
m, err := extractMention(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -149,37 +138,6 @@ func webmentionExists(source, target string) bool {
|
||||||
return result == 1
|
return result == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyNextWebmention() error {
|
|
||||||
m := &mention{}
|
|
||||||
oldStatus := ""
|
|
||||||
row, err := appDbQueryRow("select id, source, target, status from webmentions where (status = ? or status = ?) limit 1", webmentionStatusNew, webmentionStatusRenew)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := row.Scan(&m.ID, &m.Source, &m.Target, &oldStatus); err == sql.ErrNoRows {
|
|
||||||
return nil
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := wmVerify(m); err != nil {
|
|
||||||
// Invalid
|
|
||||||
return deleteWebmention(m.ID)
|
|
||||||
}
|
|
||||||
if len(m.Content) > 500 {
|
|
||||||
m.Content = m.Content[0:497] + "…"
|
|
||||||
}
|
|
||||||
newStatus := webmentionStatusVerified
|
|
||||||
if strings.HasPrefix(m.Source, appConfig.Server.PublicAddress) {
|
|
||||||
// Approve if it's server-intern
|
|
||||||
newStatus = webmentionStatusApproved
|
|
||||||
}
|
|
||||||
_, err = appDbExec("update webmentions set status = ?, title = ?, content = ?, author = ? where id = ?", newStatus, m.Title, m.Content, m.Author, m.ID)
|
|
||||||
if oldStatus == string(webmentionStatusNew) {
|
|
||||||
sendNotification(fmt.Sprintf("New webmention from %s to %s", m.Source, m.Target))
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func createWebmention(source, target string) (err error) {
|
func createWebmention(source, target string) (err error) {
|
||||||
if webmentionExists(source, target) {
|
if webmentionExists(source, target) {
|
||||||
_, err = appDbExec("update webmentions set status = ? where source = ? and target = ?", webmentionStatusRenew, source, target)
|
_, err = appDbExec("update webmentions set status = ? where source = ? and target = ?", webmentionStatusRenew, source, target)
|
||||||
|
@ -241,36 +199,3 @@ func getWebmentions(config *webmentionsRequestConfig) ([]*mention, error) {
|
||||||
}
|
}
|
||||||
return mentions, nil
|
return mentions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *post) sendWebmentions() error {
|
|
||||||
url := appConfig.Server.PublicAddress + p.Path
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
// Render basic post data
|
|
||||||
render(recorder, "postbasic", &renderData{
|
|
||||||
blogString: p.Blog,
|
|
||||||
Data: p,
|
|
||||||
})
|
|
||||||
discovered, err := webmention.DiscoverLinksFromReader(recorder.Result().Body, url, ".h-entry")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
client := webmention.New(nil)
|
|
||||||
for _, link := range discovered {
|
|
||||||
if strings.HasPrefix(link, appConfig.Server.PublicAddress) {
|
|
||||||
// Save mention directly
|
|
||||||
createWebmention(url, link)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
endpoint, err := client.DiscoverEndpoint(link)
|
|
||||||
if err != nil || len(endpoint) < 1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
_, err = client.SendWebmention(endpoint, url, link)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Sending webmention to " + link + " failed")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
log.Println("Sent webmention to " + link)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/PuerkitoBio/goquery"
|
||||||
|
"github.com/tomnomnom/linkheader"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *post) sendWebmentions() error {
|
||||||
|
links := []string{}
|
||||||
|
contentLinks, err := allLinksFromHTML(strings.NewReader(string(p.html())), p.fullURL())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
links = append(links, contentLinks...)
|
||||||
|
links = append(links, p.firstParameter(appConfig.Micropub.LikeParam), p.firstParameter(appConfig.Micropub.ReplyParam), p.firstParameter(appConfig.Micropub.BookmarkParam))
|
||||||
|
for _, link := range links {
|
||||||
|
if link == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(link, appConfig.Server.PublicAddress) {
|
||||||
|
// Save mention directly
|
||||||
|
createWebmention(p.fullURL(), link)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
endpoint := discoverEndpoint(link)
|
||||||
|
if endpoint == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err = sendWebmention(endpoint, p.fullURL(), link)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Sending webmention to " + link + " failed")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Println("Sent webmention to " + link)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendWebmention(endpoint, source, target string) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest(http.MethodPost, endpoint, strings.NewReader(url.Values{
|
||||||
|
"source": []string{source},
|
||||||
|
"target": []string{target},
|
||||||
|
}.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set(contentType, contentTypeWWWForm)
|
||||||
|
req.Header.Set(userAgent, appUserAgent)
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if code := res.StatusCode; code < 200 || 300 <= code {
|
||||||
|
return res, fmt.Errorf("response error: %v", res.StatusCode)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func discoverEndpoint(urlStr string) string {
|
||||||
|
doRequest := func(method, urlStr string) string {
|
||||||
|
req, err := http.NewRequest(method, urlStr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
req.Header.Set(userAgent, appUserAgent)
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if code := resp.StatusCode; code < 200 || 300 <= code {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
endpoint, err := extractEndpoint(resp)
|
||||||
|
if err != nil || endpoint == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if urls, err := resolveURLReferences(urlStr, endpoint); err == nil && len(urls) > 0 && urls[0] != "" {
|
||||||
|
return urls[0]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
headEndpoint := doRequest(http.MethodHead, urlStr)
|
||||||
|
if headEndpoint != "" {
|
||||||
|
return headEndpoint
|
||||||
|
}
|
||||||
|
getEndpoint := doRequest(http.MethodGet, urlStr)
|
||||||
|
if getEndpoint != "" {
|
||||||
|
return getEndpoint
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractEndpoint(resp *http.Response) (string, error) {
|
||||||
|
// first check http link headers
|
||||||
|
if endpoint := wmEndpointHTTPLink(resp.Header); endpoint != "" {
|
||||||
|
return endpoint, nil
|
||||||
|
}
|
||||||
|
// then look in the HTML body
|
||||||
|
endpoint, err := wmEndpointHTMLLink(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return endpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wmEndpointHTTPLink(headers http.Header) string {
|
||||||
|
links := linkheader.ParseMultiple(headers[http.CanonicalHeaderKey("Link")]).FilterByRel("webmention")
|
||||||
|
for _, link := range links {
|
||||||
|
if u := link.URL; u != "" {
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func wmEndpointHTMLLink(r io.Reader) (string, error) {
|
||||||
|
doc, err := goquery.NewDocumentFromReader(r)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
href, _ := doc.Find("a[href][rel=webmention],link[href][rel=webmention]").Attr("href")
|
||||||
|
return href, nil
|
||||||
|
}
|
|
@ -2,29 +2,66 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
"willnorris.com/go/microformats"
|
"willnorris.com/go/microformats"
|
||||||
)
|
)
|
||||||
|
|
||||||
func wmVerify(m *mention) error {
|
func startWebmentionVerifier() {
|
||||||
client := &http.Client{}
|
go func() {
|
||||||
client.CheckRedirect = func(r *http.Request, via []*http.Request) error {
|
for {
|
||||||
if len(via) > 15 {
|
time.Sleep(30 * time.Second)
|
||||||
return errors.New("too many redirects")
|
verifyNextWebmention()
|
||||||
}
|
}
|
||||||
return nil
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyNextWebmention() error {
|
||||||
|
m := &mention{}
|
||||||
|
oldStatus := ""
|
||||||
|
row, err := appDbQueryRow("select id, source, target, status from webmentions where (status = ? or status = ?) limit 1", webmentionStatusNew, webmentionStatusRenew)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
if err := row.Scan(&m.ID, &m.Source, &m.Target, &oldStatus); err == sql.ErrNoRows {
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := wmVerify(m); err != nil {
|
||||||
|
// Invalid
|
||||||
|
return deleteWebmention(m.ID)
|
||||||
|
}
|
||||||
|
if len(m.Content) > 500 {
|
||||||
|
m.Content = m.Content[0:497] + "…"
|
||||||
|
}
|
||||||
|
newStatus := webmentionStatusVerified
|
||||||
|
if strings.HasPrefix(m.Source, appConfig.Server.PublicAddress) {
|
||||||
|
// Approve if it's server-intern
|
||||||
|
newStatus = webmentionStatusApproved
|
||||||
|
}
|
||||||
|
_, err = appDbExec("update webmentions set status = ?, title = ?, content = ?, author = ? where id = ?", newStatus, m.Title, m.Content, m.Author, m.ID)
|
||||||
|
if oldStatus == string(webmentionStatusNew) {
|
||||||
|
sendNotification(fmt.Sprintf("New webmention from %s to %s", m.Source, m.Target))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func wmVerify(m *mention) error {
|
||||||
req, err := http.NewRequest(http.MethodGet, m.Source, nil)
|
req, err := http.NewRequest(http.MethodGet, m.Source, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
req.Header.Set("User-Agent", "GoBlog")
|
req.Header.Set(userAgent, appUserAgent)
|
||||||
resp, err := client.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
Loading…
Reference in New Issue