implement self-hosted pictures, remove need for datapath

This commit is contained in:
Wouter Groeneveld 2021-04-19 20:22:38 +02:00
parent 47af4bb93f
commit 64c6065d74
25 changed files with 670 additions and 92 deletions

View File

@ -1,10 +1,10 @@
package mf
import (
"brainbaking.com/go-jamming/rest"
"crypto/md5"
"fmt"
"net/url"
"strings"
)
// this should be passed along as a value object, not as a pointer
@ -28,12 +28,7 @@ func (wm Mention) String() string {
// This is the same as conf.FetchDomain(wm.Target), only without config, and without error handling.
// Assumes http(s) protocol, which should have been validated by now.
func (wm Mention) Domain() string {
withPossibleSubdomain := strings.Split(wm.Target, "/")[2]
split := strings.Split(withPossibleSubdomain, ".")
if len(split) == 2 {
return withPossibleSubdomain // that was the extention, not the subdomain.
}
return fmt.Sprintf("%s.%s", split[1], split[2])
return rest.Domain(wm.Target)
}
func (wm Mention) Key() string {

View File

@ -6,41 +6,10 @@ import (
)
func TestDomainParseFromTarget(t *testing.T) {
cases := []struct {
label string
target string
expected string
}{
{
"parse from default http domain",
"http://patat.be/frietjes/zijn/lekker",
"patat.be",
},
{
"parse from default https domain",
"https://frit.be/patatjes/zijn/lekker",
"frit.be",
},
{
"parse from default https domain with www subdomain",
"https://www.frit.be/patatjes/zijn/lekker",
"frit.be",
},
{
"parse from default https domain with some random subdomain",
"https://mayonaise.frit.be/patatjes/zijn/lekker",
"frit.be",
},
wm := Mention{
Source: "source",
Target: "http://patat.be/frietjes/zijn/lekker",
}
for _, tc := range cases {
t.Run(tc.label, func(t *testing.T) {
wm := Mention{
Source: "source",
Target: tc.target,
}
assert.Equal(t, tc.expected, wm.Domain())
})
}
assert.Equal(t, "patat.be", wm.Domain())
}

View File

@ -2,8 +2,6 @@ package mf
import (
"brainbaking.com/go-jamming/common"
"encoding/json"
"io/ioutil"
"strings"
"time"
"willnorris.com/go/microformats"
@ -41,17 +39,15 @@ type IndiewebData struct {
Target string `json:"target"`
}
func (id *IndiewebData) IsEmpty() bool {
return id.Url == ""
func (id *IndiewebData) AsMention() Mention {
return Mention{
Source: id.Source,
Target: id.Target,
}
}
// RequireFromFile converts the file JSON contents into the indieweb struct.
// This ignores read and marshall errors and returns an emtpy struct instead.
func RequireFromFile(file string) *IndiewebData {
indiewebData := &IndiewebData{}
data, _ := ioutil.ReadFile(file)
json.Unmarshal(data, indiewebData)
return indiewebData
func (id *IndiewebData) IsEmpty() bool {
return id.Url == ""
}
func PublishedNow(utcOffset int) string {

23
app/pictures/handler.go Normal file
View File

@ -0,0 +1,23 @@
package pictures
import (
"brainbaking.com/go-jamming/db"
"github.com/gorilla/mux"
"net/http"
)
// Handle handles picture GET calls.
// It does not validate the picture query as it's part of a composite key anyway.
func Handle(repo db.MentionRepo) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
picDomain := mux.Vars(r)["picture"]
picData := repo.GetPicture(picDomain)
if picData == nil {
http.NotFound(w, r)
return
}
w.WriteHeader(http.StatusOK)
// TODO response headers? is this a jpeg, png, gif, webm? should we?
w.Write(picData)
}
}

View File

@ -2,6 +2,7 @@ package app
import (
"brainbaking.com/go-jamming/app/index"
"brainbaking.com/go-jamming/app/pictures"
"brainbaking.com/go-jamming/app/pingback"
"brainbaking.com/go-jamming/app/webmention"
)
@ -14,6 +15,7 @@ func (s *server) routes() {
db := s.repo
s.router.HandleFunc("/", index.Handle(c)).Methods("GET")
s.router.HandleFunc("/pictures/{picture}", pictures.Handle(db)).Methods("GET")
s.router.HandleFunc("/pingback", pingback.HandlePost(c, db)).Methods("POST")
s.router.HandleFunc("/webmention", webmention.HandlePost(c, db)).Methods("POST")
s.router.HandleFunc("/webmention/{domain}/{token}", s.authorizedOnly(webmention.HandleGet(db))).Methods("GET")

View File

@ -5,6 +5,7 @@ import (
"brainbaking.com/go-jamming/common"
"brainbaking.com/go-jamming/db"
"brainbaking.com/go-jamming/rest"
"fmt"
"regexp"
"strings"
@ -41,6 +42,9 @@ func (recv *Receiver) processSourceBody(body string, wm mf.Mention) {
data := microformats.Parse(strings.NewReader(body), wm.SourceUrl())
indieweb := recv.convertBodyToIndiewebData(body, wm, mf.HEntry(data))
if indieweb.Author.Picture != "" {
recv.saveAuthorPictureLocally(indieweb)
}
key, err := recv.Repo.Save(wm, indieweb)
if err != nil {
@ -93,6 +97,22 @@ func (recv *Receiver) parseBodyAsNonIndiewebSite(body string, wm mf.Mention) *mf
}
}
func (recv *Receiver) saveAuthorPictureLocally(indieweb *mf.IndiewebData) {
_, picData, err := recv.RestClient.GetBody(indieweb.Author.Picture)
if err != nil {
log.Warn().Err(err).Str("url", indieweb.Author.Picture).Msg("Unable to download author picture. Ignoring.")
return
}
srcDomain := rest.Domain(indieweb.Source)
_, dberr := recv.Repo.SavePicture(picData, srcDomain)
if dberr != nil {
log.Warn().Err(err).Str("url", indieweb.Author.Picture).Msg("Unable to save downloaded author picture. Ignoring.")
return
}
indieweb.Author.Picture = fmt.Sprintf("/pictures/%s", srcDomain)
}
func nonIndiewebTitle(body string, wm mf.Mention) string {
titleMatch := titleRegexp.FindStringSubmatch(body)
title := wm.Source

View File

@ -34,7 +34,7 @@ func TestReceive(t *testing.T) {
Source: "https://brainbaking.com/valid-bridgy-twitter-source.html",
Target: "https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag",
},
json: `{"author":{"name":"Jamie Tanna","picture":"https://www.jvt.me/img/profile.png"},"name":"","content":"Recommended read:\nThe IndieWeb Mixed Bag - Thoughts about the (d)evolution of blog interactions\nhttps://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/","published":"2021-03-15T12:42:00+0000","url":"https://brainbaking.com/mf2/2021/03/1bkre/","type":"bookmark","source":"https://brainbaking.com/valid-bridgy-twitter-source.html","target":"https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag"}`,
json: `{"author":{"name":"Jamie Tanna","picture":"/pictures/brainbaking.com"},"name":"","content":"Recommended read:\nThe IndieWeb Mixed Bag - Thoughts about the (d)evolution of blog interactions\nhttps://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/","published":"2021-03-15T12:42:00+0000","url":"https://brainbaking.com/mf2/2021/03/1bkre/","type":"bookmark","source":"https://brainbaking.com/valid-bridgy-twitter-source.html","target":"https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag"}`,
},
{
label: "receive a brid.gy Webmention like",
@ -44,7 +44,7 @@ func TestReceive(t *testing.T) {
Target: "https://brainbaking.com/valid-indieweb-target.html",
},
// no dates in bridgy-to-mastodon likes...
json: `{"author":{"name":"Stampeding Longhorn","picture":"https://cdn.social.linux.pizza/v1/AUTH_91eb37814936490c95da7b85993cc2ff/sociallinuxpizza/accounts/avatars/000/185/996/original/9e36da0c093cfc9b.png"},"name":"","content":"","published":"2020-01-01T12:30:00","url":"https://chat.brainbaking.com/notice/A4nx1rFwKUJYSe4TqK#favorited-by-A4nwg4LYyh4WgrJOXg","type":"like","source":"https://brainbaking.com/valid-bridgy-like.html","target":"https://brainbaking.com/valid-indieweb-target.html"}`,
json: `{"author":{"name":"Stampeding Longhorn","picture":"/pictures/brainbaking.com"},"name":"","content":"","published":"2020-01-01T12:30:00","url":"https://chat.brainbaking.com/notice/A4nx1rFwKUJYSe4TqK#favorited-by-A4nwg4LYyh4WgrJOXg","type":"like","source":"https://brainbaking.com/valid-bridgy-like.html","target":"https://brainbaking.com/valid-indieweb-target.html"}`,
},
{
label: "receive a brid.gy Webmention that has a url and photo without value",
@ -52,7 +52,7 @@ func TestReceive(t *testing.T) {
Source: "https://brainbaking.com/valid-bridgy-source.html",
Target: "https://brainbaking.com/valid-indieweb-target.html",
},
json: `{"author":{"name":"Stampeding Longhorn", "picture":"https://cdn.social.linux.pizza/v1/AUTH_91eb37814936490c95da7b85993cc2ff/sociallinuxpizza/accounts/avatars/000/185/996/original/9e36da0c093cfc9b.png"}, "content":"@wouter The cat pictures are awesome. for jest tests!", "name":"@wouter The cat pictures are awesome. for jest tests!", "published":"2021-03-02T16:17:18.000Z", "source":"https://brainbaking.com/valid-bridgy-source.html", "target":"https://brainbaking.com/valid-indieweb-target.html", "type":"mention", "url":"https://social.linux.pizza/@StampedingLonghorn/105821099684887793"}`,
json: `{"author":{"name":"Stampeding Longhorn", "picture":"/pictures/brainbaking.com"}, "content":"@wouter The cat pictures are awesome. for jest tests!", "name":"@wouter The cat pictures are awesome. for jest tests!", "published":"2021-03-02T16:17:18.000Z", "source":"https://brainbaking.com/valid-bridgy-source.html", "target":"https://brainbaking.com/valid-indieweb-target.html", "type":"mention", "url":"https://social.linux.pizza/@StampedingLonghorn/105821099684887793"}`,
},
{
label: "receive saves a JSON file of indieweb-metadata if all is valid",
@ -60,7 +60,7 @@ func TestReceive(t *testing.T) {
Source: "https://brainbaking.com/valid-indieweb-source.html",
Target: "https://jefklakscodex.com/articles",
},
json: `{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com//img/avatar.jpg"},"name":"I just learned about https://www.inklestudios.com/...","content":"This is cool, I just found out about valid indieweb target - so cool","published":"2021-03-06T12:41:00","url":"https://brainbaking.com/notes/2021/03/06h12m41s48/","type":"mention","source":"https://brainbaking.com/valid-indieweb-source.html","target":"https://jefklakscodex.com/articles"}`,
json: `{"author":{"name":"Wouter Groeneveld","picture":"/pictures/brainbaking.com"},"name":"I just learned about https://www.inklestudios.com/...","content":"This is cool, I just found out about valid indieweb target - so cool","published":"2021-03-06T12:41:00","url":"https://brainbaking.com/notes/2021/03/06h12m41s48/","type":"mention","source":"https://brainbaking.com/valid-indieweb-source.html","target":"https://jefklakscodex.com/articles"}`,
},
{
label: "receive saves a JSON file of indieweb-metadata with summary as content if present",
@ -68,7 +68,7 @@ func TestReceive(t *testing.T) {
Source: "https://brainbaking.com/valid-indieweb-source-with-summary.html",
Target: "https://brainbaking.com/valid-indieweb-target.html",
},
json: `{"author":{"name":"Wouter Groeneveld", "picture":"https://brainbaking.com//img/avatar.jpg"}, "content":"This is cool, this is a summary!", "name":"I just learned about https://www.inklestudios.com/...", "published":"2021-03-06T12:41:00", "source":"https://brainbaking.com/valid-indieweb-source-with-summary.html", "target":"https://brainbaking.com/valid-indieweb-target.html", "type":"mention", "url":"https://brainbaking.com/notes/2021/03/06h12m41s48/"}`,
json: `{"author":{"name":"Wouter Groeneveld", "picture":"/pictures/brainbaking.com"}, "content":"This is cool, this is a summary!", "name":"I just learned about https://www.inklestudios.com/...", "published":"2021-03-06T12:41:00", "source":"https://brainbaking.com/valid-indieweb-source-with-summary.html", "target":"https://brainbaking.com/valid-indieweb-target.html", "type":"mention", "url":"https://brainbaking.com/notes/2021/03/06h12m41s48/"}`,
},
{
label: "receive saves a JSON file of non-indieweb-data such as title if all is valid",

View File

@ -26,9 +26,6 @@ func (c *Config) missingKeys() []string {
if c.Token == "" {
keys = append(keys, "token")
}
if c.DataPath == "" {
keys = append(keys, "dataPath")
}
if c.ConString == "" {
keys = append(keys, "conString")
}
@ -66,11 +63,11 @@ func (c *Config) FetchDomain(url string) (string, error) {
}
func Configure() *Config {
conf := config()
for _, domain := range conf.AllowedWebmentionSources {
c := config()
for _, domain := range c.AllowedWebmentionSources {
log.Info().Str("allowedDomain", domain).Msg("Configured")
}
return conf
return c
}
func config() *Config {
@ -99,7 +96,6 @@ func defaultConfig() *Config {
Port: 1337,
Token: "miauwkes",
UtcOffset: 60,
DataPath: "data",
ConString: "data/mentions.db",
AllowedWebmentionSources: []string{"brainbaking.com", "jefklakscodex.com"},
DisallowedWebmentionDomains: []string{"youtube.com"},

View File

@ -1,9 +1,8 @@
package main
package db
import (
"brainbaking.com/go-jamming/app/mf"
"brainbaking.com/go-jamming/common"
"brainbaking.com/go-jamming/db"
"encoding/json"
"fmt"
"github.com/rs/zerolog/log"
@ -11,20 +10,19 @@ import (
"os"
)
// Migrate migrates from data/[domain]/md5hash.json files to the new key/value db.
// This is only needed if you've run go-jamming before the db migration.
func Migrate() {
cnf := common.Configure()
dataPath := "data" // decoupled from config, change if needed
os.Remove(cnf.ConString)
repo := db.NewMentionRepo(cnf)
const (
dataPath = "data" // decoupled from config, change if needed
)
log.Info().Str("dbconfig", cnf.ConString).Msg("Starting migration...")
// MigrateDataFiles migrates from data/[domain]/md5hash.json files to the new key/value db.
// This is only needed if you've run go-jamming before the db migration.
func MigrateDataFiles(cnf *common.Config, repo *MentionRepoBunt) {
for _, domain := range cnf.AllowedWebmentionSources {
fmt.Printf("Processing domain %s...\n", domain)
log.Info().Str("domain", domain).Msg("MigrateDataFiles: processing")
entries, err := os.ReadDir(fmt.Sprintf("%s/%s", dataPath, domain))
if err != nil {
log.Fatal().Err(err).Msg("Error while reading import path")
log.Warn().Err(err).Msg("Error while reading import path - migration could be already done...")
continue
}
for _, file := range entries {
@ -36,10 +34,7 @@ func Migrate() {
var indiewebData mf.IndiewebData
json.Unmarshal(data, &indiewebData)
mention := mf.Mention{
Source: indiewebData.Source,
Target: indiewebData.Target,
}
mention := indiewebData.AsMention()
log.Info().Stringer("wm", mention).Str("file", filename).Msg("Re-saving entry")
repo.Save(mention, &indiewebData)
@ -57,6 +52,4 @@ func Migrate() {
log.Info().Str("domain", domain).Str("since", string(since)).Msg("Saving since")
repo.UpdateSince(domain, common.IsoToTime(string(since)))
}
log.Info().Str("dbconfig", cnf.ConString).Msg("Done! Check db")
}

69
db/migrate-pictures.go Normal file
View File

@ -0,0 +1,69 @@
package db
import (
"brainbaking.com/go-jamming/app/mf"
"brainbaking.com/go-jamming/common"
"brainbaking.com/go-jamming/rest"
"fmt"
"github.com/rs/zerolog/log"
"strings"
)
// MigratePictures converts all indiewebdata already present in the database into local byte arrays (strings).
// This makes it possible to self-host author pictures. Run only after Migrate() in migrate-db.go.
func MigratePictures(cnf *common.Config, repo *MentionRepoBunt) {
for _, domain := range cnf.AllowedWebmentionSources {
all := repo.GetAll(domain)
log.Info().Str("domain", domain).Int("mentions", len(all.Data)).Msg("migrate pictures: processing")
for _, mention := range all.Data {
if mention.Author.Picture == "" {
log.Warn().Str("url", mention.Url).Msg("Mention without author picture, skipping")
continue
}
savePicture(mention, repo, cnf)
}
}
}
// ChangeBaseUrl changes all base urls of pictures in the database.
// e.g. "http://localhost:1337/" to "https://jam.brainbaking.com/"
func ChangeBaseUrl(old, new string) {
cnf := common.Configure()
repo := NewMentionRepo(cnf)
for _, domain := range cnf.AllowedWebmentionSources {
for _, mention := range repo.GetAll(domain).Data {
if mention.Author.Picture == "" {
log.Warn().Str("url", mention.Url).Msg("Mention without author picture, skipping")
continue
}
mention.Author.Picture = strings.ReplaceAll(mention.Author.Picture, old, new)
repo.Save(mention.AsMention(), mention)
}
}
}
func savePicture(indieweb *mf.IndiewebData, repo *MentionRepoBunt, cnf *common.Config) {
restClient := &rest.HttpClient{}
picUrl := indieweb.Author.Picture
log.Info().Str("oldurl", picUrl).Msg("About to cache picture")
_, picData, err := restClient.GetBody(picUrl)
if err != nil {
log.Warn().Err(err).Str("url", picUrl).Msg("Unable to download author picture. Ignoring.")
return
}
srcDomain := rest.Domain(indieweb.Source)
_, dberr := repo.SavePicture(picData, srcDomain)
if dberr != nil {
log.Warn().Err(err).Str("url", picUrl).Msg("Unable to save downloaded author picture. Ignoring.")
return
}
indieweb.Author.Picture = fmt.Sprintf("/pictures/%s", srcDomain)
_, serr := repo.Save(indieweb.AsMention(), indieweb)
if serr != nil {
log.Fatal().Err(serr).Msg("Unable to update wm?")
}
log.Info().Str("oldurl", picUrl).Str("newurl", indieweb.Author.Picture).Msg("Picture saved!")
}

13
db/migrate.go Normal file
View File

@ -0,0 +1,13 @@
package db
import "brainbaking.com/go-jamming/common"
// Migrate self-checks and executes necessary DB migrations, if any.
func Migrate() {
cnf := common.Configure()
repo := NewMentionRepo(cnf)
MigrateDataFiles(cnf, repo)
MigratePictures(cnf, repo)
repo.db.Shrink()
}

View File

@ -18,17 +18,19 @@ type MentionRepoBunt struct {
type MentionRepo interface {
Save(key mf.Mention, data *mf.IndiewebData) (string, error)
SavePicture(bytes string, domain string) (string, error)
Delete(key mf.Mention)
Since(domain string) (time.Time, error)
UpdateSince(domain string, since time.Time)
Get(key mf.Mention) *mf.IndiewebData
GetPicture(domain string) []byte
GetAll(domain string) mf.IndiewebDataResult
}
// UpdateSince updates the since timestamp to now. Logs but ignores errors.
func (r *MentionRepoBunt) UpdateSince(domain string, since time.Time) {
err := r.db.Update(func(tx *buntdb.Tx) error {
_, _, err := tx.Set(fmt.Sprintf("%s:since", domain), common.TimeToIso(since), nil)
_, _, err := tx.Set(sinceKey(domain), common.TimeToIso(since), nil)
return err
})
if err != nil {
@ -41,7 +43,7 @@ func (r *MentionRepoBunt) UpdateSince(domain string, since time.Time) {
func (r *MentionRepoBunt) Since(domain string) (time.Time, error) {
var since string
err := r.db.View(func(tx *buntdb.Tx) error {
val, err := tx.Get(fmt.Sprintf("%s:since", domain))
val, err := tx.Get(sinceKey(domain))
since = val
return err
})
@ -51,6 +53,10 @@ func (r *MentionRepoBunt) Since(domain string) (time.Time, error) {
return common.IsoToTime(since), nil
}
func sinceKey(domain string) string {
return fmt.Sprintf("%s:since", domain)
}
// Delete removes a possibly present mention by key. Ignores possible errors.
func (r *MentionRepoBunt) Delete(wm mf.Mention) {
key := r.mentionToKey(wm)
@ -60,6 +66,22 @@ func (r *MentionRepoBunt) Delete(wm mf.Mention) {
})
}
func (r *MentionRepoBunt) SavePicture(bytes string, domain string) (string, error) {
key := pictureKey(domain)
err := r.db.Update(func(tx *buntdb.Tx) error {
_, _, err := tx.Set(key, bytes, nil)
return err
})
if err != nil {
return "", err
}
return key, nil
}
func pictureKey(domain string) string {
return fmt.Sprintf("%s:picture", domain)
}
// Save saves the mention by marshalling data. Returns the key or a marshal/persist error.
func (r *MentionRepoBunt) Save(wm mf.Mention, data *mf.IndiewebData) (string, error) {
jsonData, err := json.Marshal(data)
@ -104,6 +126,24 @@ func (r *MentionRepoBunt) Get(wm mf.Mention) *mf.IndiewebData {
return &data
}
func (r *MentionRepoBunt) GetPicture(domain string) []byte {
var data []byte
key := pictureKey(domain)
err := r.db.View(func(tx *buntdb.Tx) error {
val, err := tx.Get(key)
if err != nil {
return err
}
data = []byte(val)
return nil
})
if err != nil {
log.Error().Err(err).Str("key", key).Msg("repo getpicture: unable to retrieve key")
return nil
}
return data
}
// GetAll returns a wrapped data result for all mentions for a particular domain.
// Intentionally ignores marshal errors, db should be consistent!
// Warning, this will potentially marshall 10k strings!
@ -117,6 +157,7 @@ func (r *MentionRepoBunt) GetAll(domain string) mf.IndiewebDataResult {
return true
})
})
if err != nil {
log.Error().Err(err).Msg("get all: failed to ascend from view")
return mf.IndiewebDataResult{}

View File

@ -6,6 +6,7 @@ import (
"fmt"
"github.com/stretchr/testify/assert"
"github.com/tidwall/buntdb"
"io/ioutil"
"os"
"testing"
"time"
@ -20,6 +21,19 @@ var (
}
)
func TestSaveAndGetPicture(t *testing.T) {
data, err := ioutil.ReadFile("../mocks/picture.jpg")
assert.NoError(t, err)
db := NewMentionRepo(conf)
key, dberr := db.SavePicture(string(data), "bloeberig.be")
assert.NoError(t, dberr)
assert.Equal(t, "bloeberig.be:picture", key)
picDataAfterSave := db.GetPicture("bloeberig.be")
assert.Equal(t, data, picDataAfterSave)
}
func TestDelete(t *testing.T) {
db := NewMentionRepo(conf)
wm := mf.Mention{

2
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/hashicorp/go-retryablehttp v0.6.8
github.com/rs/zerolog v1.21.0
github.com/stretchr/testify v1.7.0
github.com/tidwall/buntdb v1.2.3 // indirect
github.com/tidwall/buntdb v1.2.3
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
willnorris.com/go/microformats v1.1.1
)

1
go.sum
View File

@ -36,6 +36,7 @@ github.com/tidwall/gjson v1.7.4 h1:19cchw8FOxkG5mdLRkGf9jqIqEyqdZhPqW60XfyFxk8=
github.com/tidwall/gjson v1.7.4/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
github.com/tidwall/grect v0.1.1 h1:+kMEkxhoqB7rniVXzMEIA66XwU07STgINqxh+qVIndY=
github.com/tidwall/grect v0.1.1/go.mod h1:CzvbGiFbWUwiJ1JohXLb28McpyBsI00TK9Y6pDWLGRQ=
github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8=
github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8=
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=

15
main.go
View File

@ -1,6 +1,7 @@
package main
import (
"brainbaking.com/go-jamming/db"
"flag"
"os"
@ -14,15 +15,27 @@ func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
verboseFlag := flag.Bool("verbose", false, "Verbose mode (pretty print log, debug level)")
migrateFlag := flag.Bool("migrate", false, "Run migration scripts for the DB and exit.")
flag.Parse()
// logs by default to Stderr (/var/log/syslog). Rolling files possible via lumberjack.
zerolog.SetGlobalLevel(zerolog.InfoLevel)
if *verboseFlag == true {
if *verboseFlag == true || *migrateFlag == true {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
zerolog.SetGlobalLevel(zerolog.DebugLevel)
}
if *migrateFlag == true {
migrate()
os.Exit(0)
}
log.Debug().Msg("Let's a go!")
app.Start()
}
func migrate() {
log.Info().Msg("Starting db migration...")
db.Migrate()
log.Info().Msg("Migration ended, exiting.")
}

378
mentions.db Normal file
View File

@ -0,0 +1,378 @@
*3
$3
set
$48
18acebf759df6d79f8a109faa8d18fc7:brainbaking.com
$625
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"I changed my mind on my toot syndication to brainb...","content":"I changed my mind on my toot syndication to brainbaking.com policy. From now on, only non-replies (in-reply-to) get pushed to https://brainbaking.com/notes/ - it was cluttering up the RSS feed and most replies are useless to non-followers anyway. Sor...","published":"2021-03-20T13:27:00","url":"https://brainbaking.com/notes/2021/03/20h13m27s36/","type":"mention","source":"https://brainbaking.com/notes/2021/03/20h13m27s36/","target":"http://brainbaking.com"}
*3
$3
set
$48
1b2ba8c60768014afa147580d452ced5:brainbaking.com
$633
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"I changed my mind on my toot syndication to brainb...","content":"I changed my mind on my toot syndication to brainbaking.com policy. From now on, only non-replies (in-reply-to) get pushed to https://brainbaking.com/notes/ - it was cluttering up the RSS feed and most replies are useless to non-followers anyway. Sor...","published":"2021-03-20T13:27:00","url":"https://brainbaking.com/notes/2021/03/20h13m27s36/","type":"mention","source":"https://brainbaking.com/notes/2021/03/20h13m27s36/","target":"https://brainbaking.com/notes/"}
*3
$3
set
$48
421c001c7efa6e36e6f331c005d31c27:brainbaking.com
$597
{"author":{"name":"Henrique Dias","picture":"https://hacdias.com/me-256.jpg"},"name":"Site Ideas","content":"A bunch of ideas for my website that might never get implemented.Wanna know more about the website? Check out the meta page!Finish uses.https://cleanuptheweb.org/Create /meta/historical with pictures of old versions of my website.Remove .Params.socia...","published":"2021-04-17T06:46:33Z","url":"https://hacdias.com/notes/site-ideas/","type":"mention","source":"https://hacdias.com/notes/site-ideas","target":"https://brainbaking.com/post/2021/04/using-hugo-to-launch-a-gemini-capsule/"}
*3
$3
set
$48
4b0d1434331f1a382493b2838dc4b1a2:brainbaking.com
$421
{"author":{"name":"Jamie Tanna","picture":"https://www.jvt.me/img/profile.png"},"name":"","content":"Recommended read: The IndieWeb Mixed Bag - Thoughts about the (d)evolution of blog interactions","published":"2021-03-15T12:42:00+0000","url":"https://www.jvt.me/mf2/2021/03/1bkre/","type":"mention","source":"https://www.jvt.me/mf2/2021/03/1bkre/","target":"https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/"}
*3
$3
set
$48
5854ce85363d8c7513cd14e52870d46b:brainbaking.com
$708
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"@StampedingLonghorn @256 Don't forget the cleverly hidden Roland MT-32, a majestic piece of p...","content":"@StampedingLonghorn @256 Don't forget the cleverly hidden Roland MT-32, a majestic piece of pre-MIDI standardized era synthesizer. What else would you use to run Sierra Online games, and monkey1? I really need one for my 486… https://brainbaking.com/...","published":"2021-03-02T17:13:00","url":"https://brainbaking.com/notes/2021/03/02h17m13s27/","type":"mention","source":"https://brainbaking.com/notes/2021/03/02h17m13s27/","target":"https://brainbaking.com/post/2021/02/my-retro-desktop-setup/"}
*3
$3
set
$48
69c99dcf12c180b8acb3c1c218d1f388:brainbaking.com
$655
{"author":{"name":"Jefklak","picture":"https://jefklakscodex.com/img/avatar.jpg"},"name":"Reviews from 2001 revived!","content":"Good news everyone! Futurama might not be back, but old PC gaming previews and reviews from UnionVault.NET, one of Jefklaks Codex ancestors, have been revived. I happened to stumble upon a few readable HTML files wile looking for something else and ...","published":"2020-09-25","url":"https://jefklakscodex.com/articles/features/reviews-from-2001-revived/","type":"mention","source":"https://jefklakscodex.com/articles/features/reviews-from-2001-revived/","target":"https://brainbaking.com/post/2020/09/reviving-a-80486/"}
*3
$3
set
$48
78e327d69a3f5fa151f660b5a25c06a9:brainbaking.com
$682
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"Heads up RSS feed readers of brainbaking.com! Federated half-baked thoughts (https://brainbaking....","content":"Heads up RSS feed readers of brainbaking.com! Federated half-baked thoughts (https://brainbaking.com/notes/) are now integrated in /index.xml 🤓. Don't like that? Subscribe to /post/index.xml instead! Next up: webmentions, PESOS-ing of Goodreads revi...","published":"2021-03-03T16:00:00","url":"https://brainbaking.com/notes/2021/03/03h16m00s44/","type":"mention","source":"https://brainbaking.com/notes/2021/03/03h16m00s44/","target":"https://brainbaking.com/notes/"}
*3
$3
set
$48
792ed44939d1396d5156f1589e95b786:brainbaking.com
$707
{"author":{"name":"Jefklak","picture":"https://jefklakscodex.com/img/avatar.jpg"},"name":"Rainbow Six 3: Raven Shield - 17 Years Later","content":"Its amazing that the second disk is still readable by my Retro WinXP machine. It has been heavily abused in 2003 and the years after that. Rainbow Six' third installment, Raven Shield (or simply RvS), is quite a departure from the crude looking Rogu...","published":"2020-11-01","url":"https://jefklakscodex.com/articles/retrospectives/raven-shield-17-years-later/","type":"mention","source":"https://jefklakscodex.com/articles/retrospectives/raven-shield-17-years-later/","target":"https://brainbaking.com/post/2020/10/building-a-core2duo-winxp-retro-pc/"}
*3
$3
set
$48
83313bc67b0730459876ab7c3b9738f5:brainbaking.com
$674
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"Heads up RSS feed readers of brainbaking.com! Federated half-baked thoughts (https://brainbaking....","content":"Heads up RSS feed readers of brainbaking.com! Federated half-baked thoughts (https://brainbaking.com/notes/) are now integrated in /index.xml 🤓. Don't like that? Subscribe to /post/index.xml instead! Next up: webmentions, PESOS-ing of Goodreads revi...","published":"2021-03-03T16:00:00","url":"https://brainbaking.com/notes/2021/03/03h16m00s44/","type":"mention","source":"https://brainbaking.com/notes/2021/03/03h16m00s44/","target":"http://brainbaking.com"}
*3
$3
set
$48
9427d6a53258e670b0988bbd7f9a6ea8:brainbaking.com
$704
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"I've been fiddling with IndieWeb stuff the last week and all in all, I think it's a mixed...","content":"I've been fiddling with IndieWeb stuff the last week and all in all, I think it's a mixed bag: https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/@kev after I published it, I found out your \"removing support for indieweb\" post. Seems like we...","published":"2021-03-09T15:17:00","url":"https://brainbaking.com/notes/2021/03/09h15m17s30/","type":"mention","source":"https://brainbaking.com/notes/2021/03/09h15m17s30/","target":"https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/"}
*3
$3
set
$48
d6a0a260f50553c15cd4f7833694c841:brainbaking.com
$727
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"I pulled the Google plug and installed LineageOS: https://brainbaking.com/post/2021/03/getting-ri...","content":"I pulled the Google plug and installed LineageOS: https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/ Very impressed so far! Also rely on my own CalDAV server to replace GCalendar. Any others here running #lineageos for priv...","published":"2021-03-01T20:03:00","url":"https://brainbaking.com/notes/2021/03/01h20m03s35/","type":"mention","source":"https://brainbaking.com/notes/2021/03/01h20m03s35/","target":"https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/"}
*3
$3
set
$48
f101a8437084c39583a39acbcbd569c5:brainbaking.com
$581
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"@rsolva that's a lie indeed 😁 see https://brainba...","content":"@rsolva thats a lie indeed 😁 see https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/ I use davx5 and it works flawlessly","published":"2021-03-13T09:58:00","url":"https://brainbaking.com/notes/2021/03/13h09m58s25/","type":"mention","source":"https://brainbaking.com/notes/2021/03/13h09m58s25/","target":"https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/"}
*3
$3
set
$50
0f35e81e7376278498b425df5eaf956e:jefklakscodex.com
$610
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"I much prefer Sonic Mania's Lock On to Belgium's t...","content":"I much prefer Sonic Manias Lock On to Belgiums third Lock Down. Sigh. At least 16-bit 2D platformers make me smile: https://jefklakscodex.com/articles/reviews/sonic-mania/\n\n\n\n Enclosed Toot image","published":"2021-03-25T10:45:00","url":"https://brainbaking.com/notes/2021/03/25h10m45s09/","type":"mention","source":"https://brainbaking.com/notes/2021/03/25h10m45s09/","target":"https://jefklakscodex.com/articles/reviews/sonic-mania/"}
*3
$3
set
$50
169d68f8372aca44b39a3074a80429d8:jefklakscodex.com
$487
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"The insanity of collecting retro games","content":"Is a physical collection really worth it?","published":"2021-02-21","url":"https://brainbaking.com/post/2021/02/the-insanity-of-retro-game-collecting/","type":"mention","source":"https://brainbaking.com/post/2021/02/the-insanity-of-retro-game-collecting/","target":"https://jefklakscodex.com/articles/features/super-mario-64-aged-badly/"}
*3
$3
set
$50
3bee3dedf14a37425fc4d3ec2056b135:jefklakscodex.com
$447
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"Building an Athlon Windows 98 Retro PC","content":"Gaming from Quake to Quake III: Arena!","published":"2020-10-17","url":"https://brainbaking.com/post/2020/10/building-an-athlon-win98-retro-pc/","type":"mention","source":"https://brainbaking.com/post/2020/10/building-an-athlon-win98-retro-pc/","target":"https://jefklakscodex.com/tags/wizardry8/"}
*3
$3
set
$50
460e6c81d63550d9bfb79051bb86eb11:jefklakscodex.com
$489
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"The insanity of collecting retro games","content":"Is a physical collection really worth it?","published":"2021-02-21","url":"https://brainbaking.com/post/2021/02/the-insanity-of-retro-game-collecting/","type":"mention","source":"https://brainbaking.com/post/2021/02/the-insanity-of-retro-game-collecting/","target":"https://jefklakscodex.com/articles/features/gaming-setup-2007-flashback/"}
*3
$3
set
$50
509cf066810eadacb400e2397de5ed86:jefklakscodex.com
$473
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"Win98 Upgrade: GeForce 3 Ti200 vs Riva TNT2","content":"Get more out of that AGPx4 slot!","published":"2021-01-28","url":"https://brainbaking.com/post/2021/01/win98-upgrade-geforce3/","type":"mention","source":"https://brainbaking.com/post/2021/01/win98-upgrade-geforce3/","target":"https://jefklakscodex.com/articles/features/the-best-and-worst-retro-hack-and-slash-games/"}
*3
$3
set
$50
6880bf0f22930290ace839175db2ea34:jefklakscodex.com
$424
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"Win98 Upgrade: GeForce 3 Ti200 vs Riva TNT2","content":"Get more out of that AGPx4 slot!","published":"2021-01-28","url":"https://brainbaking.com/post/2021/01/win98-upgrade-geforce3/","type":"mention","source":"https://brainbaking.com/post/2021/01/win98-upgrade-geforce3/","target":"https://jefklakscodex.com/tags/wizardry8/"}
*3
$3
set
$50
6c97b9d5bf75e6601d3560dc3ef43771:jefklakscodex.com
$482
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"The Internet Killed Secrets in Games","content":"What's the 'secret' of the secret cow level in Diablo II?","published":"2020-11-19","url":"https://brainbaking.com/post/2020/11/the-internet-killed-secrets-in-games/","type":"mention","source":"https://brainbaking.com/post/2020/11/the-internet-killed-secrets-in-games/","target":"https://jefklakscodex.com/articles/reviews/gobliins2/"}
*3
$3
set
$50
7ea008404c0004e592dc84213253d942:jefklakscodex.com
$479
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"The Internet Killed Secrets in Games","content":"What's the 'secret' of the secret cow level in Diablo II?","published":"2020-11-19","url":"https://brainbaking.com/post/2020/11/the-internet-killed-secrets-in-games/","type":"mention","source":"https://brainbaking.com/post/2020/11/the-internet-killed-secrets-in-games/","target":"https://jefklakscodex.com/articles/reviews/sacred/"}
*3
$3
set
$50
8fc122b91788ceccb834ae721031ad98:jefklakscodex.com
$440
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"Win98 Upgrade: GeForce 3 Ti200 vs Riva TNT2","content":"Get more out of that AGPx4 slot!","published":"2021-01-28","url":"https://brainbaking.com/post/2021/01/win98-upgrade-geforce3/","type":"mention","source":"https://brainbaking.com/post/2021/01/win98-upgrade-geforce3/","target":"https://jefklakscodex.com/articles/reviews/dungeon-siege/"}
*3
$3
set
$50
e8cd7a857456a9de776e7a13c982516c:jefklakscodex.com
$502
{"author":{"name":"Wouter Groeneveld","picture":"https://brainbaking.com/img/avatar.jpg"},"name":"A journey through the history of webdesign","content":"Using personal websites and the Internet Archive","published":"2020-10-04","url":"https://brainbaking.com/post/2020/10/a-personal-journey-through-the-history-of-webdesign/","type":"mention","source":"https://brainbaking.com/post/2020/10/a-personal-journey-through-the-history-of-webdesign/","target":"https://jefklakscodex.com/tags/baldurs-gate-2/"}
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T12:54:38.452Z
*3
$3
set
$23
jefklakscodex.com:since
$24
2021-04-16T14:40:36.133Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T13:36:36.230Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T13:37:44.188Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T13:38:26.658Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T13:49:17.147Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T14:47:47.351Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T15:51:26.080Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T17:01:58.204Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T17:55:20.524Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T18:53:36.453Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T19:46:21.245Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T20:47:47.622Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T21:49:08.986Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T22:51:16.375Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-18T23:50:29.318Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T01:07:35.145Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T02:08:12.030Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T02:56:24.545Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T03:52:37.159Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T04:53:16.053Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T05:50:13.478Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T06:53:12.051Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T07:48:50.675Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T08:50:56.390Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T09:50:59.391Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T10:50:27.567Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T11:47:46.936Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T12:55:55.440Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T13:50:11.048Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T14:48:35.217Z
*3
$3
set
$21
brainbaking.com:since
$24
2021-04-19T15:51:50.183Z

BIN
mocks/picture.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -32,7 +32,7 @@ body {
<a class="p-name u-url" href="https://social.linux.pizza/@StampedingLonghorn">Stampeding Longhorn</a>
<a class="u-url" href="https://chat.brainbaking.com/@StampedingLonghorn"></a>
<span class="p-nickname">StampedingLonghorn</span>
<img class="u-photo" src="https://cdn.social.linux.pizza/v1/AUTH_91eb37814936490c95da7b85993cc2ff/sociallinuxpizza/accounts/avatars/000/185/996/original/9e36da0c093cfc9b.png" alt="" />
<img class="u-photo" src="https://brainbaking.com/picture.jpg" alt="" />
</span>
<a class="p-name u-url" href="https://chat.brainbaking.com/notice/A4nx1rFwKUJYSe4TqK#favorited-by-A4nwg4LYyh4WgrJOXg"></a>

View File

@ -32,7 +32,7 @@ body {
<a class="p-name u-url" href="https://social.linux.pizza/@StampedingLonghorn">Stampeding Longhorn</a>
<a class="u-url" href="https://chat.brainbaking.com/@StampedingLonghorn"></a>
<span class="p-nickname">StampedingLonghorn</span>
<img class="u-photo" src="https://cdn.social.linux.pizza/v1/AUTH_91eb37814936490c95da7b85993cc2ff/sociallinuxpizza/accounts/avatars/000/185/996/original/9e36da0c093cfc9b.png" alt="" />
<img class="u-photo" src="https://brainbaking.com/picture.jpg" alt="" />
</span>
<a class="u-url" href="https://social.linux.pizza/@StampedingLonghorn/105821099684887793">https://social.linux.pizza/@StampedingLonghorn/105821099684887793</a>

View File

@ -1,6 +1,6 @@
<!doctype html><html lang=en-gb><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta http-equiv=x-ua-compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="Hugo v0.81.0"><title>The IndieWeb Mixed Bag - Thoughts about the (d)evolution of blog interactions &#183; Jamie Tanna | Software Engineer</title><link rel=canonical href=https://www.jvt.me/mf2/2021/03/1bkre/><meta name=keywords content="indieweb,decentralisation,webmention,microformats"><link rel=stylesheet href=/css/style.css><link rel=stylesheet href=/css/font-awesome.min.css><link rel=stylesheet href=/css/asciinema-player.css><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Libre+Baskerville:400,400i,700"><link rel="shortcut icon" type=image/png href=/favicon.png><link rel=alternate type=text/calendar href=/mf2/2021/03/1bkre/index.ics title="Jamie Tanna | Software Engineer"><link rel=webmention href=https://webmention.io/www.jvt.me/webmention><link rel=pingback href=https://webmention.io/www.jvt.me/xmlrpc><link rel=authorization_endpoint href=https://indieauth.jvt.me/authorize><link rel=token_endpoint href=https://indieauth.jvt.me/token><link rel=micropub href=https://www-api.jvt.me/micropub><link rel=microsub href=https://aperture.p3k.io/microsub/262></head><body class="hack gruvbox-dark"><div class=container><nav class=nav><div class=nav-container><a href=/><h1 class=nav-title>Jamie Tanna | Software Engineer</h1></a><ul><li><a href=/now/><span>/now</span></a></li><li><a href=/kind/articles/><span>Blog</span></a></li><li><a href=/kind/bookmarks/><span>Links</span></a></li><li><a href=/rsvps/><span>RSVPs</span></a></li><li><a href=/kind/><span>Post by Kind</span></a></li><li><a href=/search/><span>Search</span></a></li><li><a href=/support-me/><span>Support Me</span></a></li></ul></div></nav><main><a name=top></a><div class="post mf2"><div class=h-entry><p><a class="u-bookmark-of url" href=https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/>The IndieWeb Mixed Bag - Thoughts about the (d)evolution of blog interactions</a></p><p class=p-bridgy-twitter-content>Recommended read:
The IndieWeb Mixed Bag - Thoughts about the (d)evolution of blog interactions
https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/</p><p class=post-meta><a class="u-uid u-url" href=/mf2/2021/03/1bkre/><time datetime=2021-03-15T12:42:00+0000 class=dt-published>Mon, 15 Mar 2021 12:42</time></a> by <span class="p-author h-card"><img class=u-photo src=https://www.jvt.me/img/profile.png alt="Jamie Tanna's profile image"> <a class="p-name u-url" href=https://www.jvt.me>Jamie Tanna</a></span>
https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/</p><p class=post-meta><a class="u-uid u-url" href=/mf2/2021/03/1bkre/><time datetime=2021-03-15T12:42:00+0000 class=dt-published>Mon, 15 Mar 2021 12:42</time></a> by <span class="p-author h-card"><img class=u-photo src=https://brainbaking.com/picture.jpg alt="Jamie Tanna's profile image"> <a class="p-name u-url" href=https://www.jvt.me>Jamie Tanna</a></span>
.
<i class="fa fa-tags"></i><a href=/tags/indieweb>#<span class=p-category>indieweb</span></a>
<a href=/tags/decentralisation>#<span class=p-category>decentralisation</span></a>

View File

@ -275,7 +275,7 @@
</header>
<div class="inmargin">
<a rel="author" class="p-author h-card u-url" href="https://brainbaking.com/">
<img class="u-photo" src="https://brainbaking.com//img/avatar.jpg" alt="Wouter Groeneveld" />
<img class="u-photo" src="https://brainbaking.com/picture.jpg" alt="Wouter Groeneveld" />
</a>
</div>
<p class="p-summary">

View File

@ -276,7 +276,7 @@
</header>
<div class="inmargin">
<a rel="author" class="p-author h-card u-url" href="https://brainbaking.com/">
<img class="u-photo" src="https://brainbaking.com//img/avatar.jpg" alt="Wouter Groeneveld" />
<img class="u-photo" src="https://brainbaking.com/picture.jpg" alt="Wouter Groeneveld" />
</a>
</div>
<div class="e-content content toot">

View File

@ -2,8 +2,10 @@ package rest
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
// mimicing NotFound: https://golang.org/src/net/http/server.go?s=64787:64830#L2076
@ -19,6 +21,18 @@ func Unauthorized(w http.ResponseWriter) {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
}
// Domain parses the target url to extract the domain as part of the allowed webmention targets.
// This is the same as conf.FetchDomain(wm.Target), only without config, and without error handling.
// Assumes http(s) protocol, which should have been validated by now.
func Domain(target string) string {
withPossibleSubdomain := strings.Split(target, "/")[2]
split := strings.Split(withPossibleSubdomain, ".")
if len(split) == 2 {
return withPossibleSubdomain // that was the extention, not the subdomain.
}
return fmt.Sprintf("%s.%s", split[1], split[2])
}
func Json(w http.ResponseWriter, data interface{}) {
w.WriteHeader(200)
bytes, _ := json.MarshalIndent(data, "", " ")

41
rest/utils_test.go Normal file
View File

@ -0,0 +1,41 @@
package rest
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestDomainParseFromTarget(t *testing.T) {
cases := []struct {
label string
target string
expected string
}{
{
"parse from default http domain",
"http://patat.be/frietjes/zijn/lekker",
"patat.be",
},
{
"parse from default https domain",
"https://frit.be/patatjes/zijn/lekker",
"frit.be",
},
{
"parse from default https domain with www subdomain",
"https://www.frit.be/patatjes/zijn/lekker",
"frit.be",
},
{
"parse from default https domain with some random subdomain",
"https://mayonaise.frit.be/patatjes/zijn/lekker",
"frit.be",
},
}
for _, tc := range cases {
t.Run(tc.label, func(t *testing.T) {
assert.Equal(t, tc.expected, Domain(tc.target))
})
}
}