mirror of https://github.com/jlelse/GoBlog
Simplify activitypub followers listing, parse and save activitypub usernames in @user@example.org format
This commit is contained in:
parent
4407f0aae1
commit
fc8e8e9a9d
|
@ -247,7 +247,7 @@ func (a *goBlog) apOnCreateUpdate(blog *configBlog, requestActor *ap.Actor, acti
|
|||
// It's a reply
|
||||
original := object.GetID().String()
|
||||
name := requestActor.Name.First().Value.String()
|
||||
if username := requestActor.PreferredUsername.First().String(); name == "" && username != "" {
|
||||
if username := apUsername(requestActor); name == "" && username != "" {
|
||||
name = username
|
||||
}
|
||||
website := requestActor.GetLink().String()
|
||||
|
@ -388,27 +388,30 @@ func (db *database) apGetAllInboxes(blog string) (inboxes []string, err error) {
|
|||
}
|
||||
|
||||
type apFollower struct {
|
||||
follower, inbox string
|
||||
follower, inbox, username string
|
||||
}
|
||||
|
||||
func (db *database) apGetAllFollowers(blog string) (followers []*apFollower, err error) {
|
||||
rows, err := db.Query("select follower, inbox from activitypub_followers where blog = @blog", sql.Named("blog", blog))
|
||||
rows, err := db.Query("select follower, inbox, username from activitypub_followers where blog = @blog", sql.Named("blog", blog))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var follower, inbox string
|
||||
var follower, inbox, username string
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&follower, &inbox)
|
||||
err = rows.Scan(&follower, &inbox, &username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
followers = append(followers, &apFollower{follower: follower, inbox: inbox})
|
||||
followers = append(followers, &apFollower{follower: follower, inbox: inbox, username: username})
|
||||
}
|
||||
return followers, nil
|
||||
}
|
||||
|
||||
func (db *database) apAddFollower(blog, follower, inbox string) error {
|
||||
_, err := db.Exec("insert or replace into activitypub_followers (blog, follower, inbox) values (@blog, @follower, @inbox)", sql.Named("blog", blog), sql.Named("follower", follower), sql.Named("inbox", inbox))
|
||||
func (db *database) apAddFollower(blog, follower, inbox, username string) error {
|
||||
_, err := db.Exec(
|
||||
"insert or replace into activitypub_followers (blog, follower, inbox, username) values (@blog, @follower, @inbox, @username)",
|
||||
sql.Named("blog", blog), sql.Named("follower", follower), sql.Named("inbox", inbox), sql.Named("username", username),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -463,7 +466,7 @@ func (a *goBlog) apUndelete(p *post) {
|
|||
|
||||
func (a *goBlog) apAccept(blogName, blogIri string, blog *configBlog, follow *ap.Activity) {
|
||||
newFollower := follow.Actor.GetID()
|
||||
log.Println("New follow request:", newFollower.String())
|
||||
log.Println("New follow request from follower id:", newFollower.String())
|
||||
// Get remote actor
|
||||
follower, status, err := a.apGetRemoteActor(newFollower.String(), blogIri)
|
||||
if err != nil || status != 0 {
|
||||
|
@ -479,7 +482,8 @@ func (a *goBlog) apAccept(blogName, blogIri string, blog *configBlog, follow *ap
|
|||
if inbox == "" {
|
||||
return
|
||||
}
|
||||
if err = a.db.apAddFollower(blogName, follower.GetID().String(), inbox.String()); err != nil {
|
||||
username := apUsername(follower)
|
||||
if err = a.db.apAddFollower(blogName, follower.GetID().String(), inbox.String(), username); err != nil {
|
||||
return
|
||||
}
|
||||
// Send accept response to the new follower
|
||||
|
@ -488,7 +492,7 @@ func (a *goBlog) apAccept(blogName, blogIri string, blog *configBlog, follow *ap
|
|||
accept.Actor = a.apAPIri(blog)
|
||||
_ = a.apQueueSendSigned(a.apIri(blog), inbox.String(), accept)
|
||||
// Notification
|
||||
a.sendNotification(fmt.Sprintf("%s started following %s", newFollower.String(), a.apIri(blog)))
|
||||
a.sendNotification(fmt.Sprintf("%s (%s) started following %s", username, follower.GetID().String(), a.apIri(blog)))
|
||||
}
|
||||
|
||||
func (a *goBlog) apSendProfileUpdates() {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/pem"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/araddon/dateparse"
|
||||
ct "github.com/elnormous/contenttype"
|
||||
|
@ -151,3 +152,12 @@ func (a *goBlog) serveAPItem(item any, w http.ResponseWriter, r *http.Request) {
|
|||
w.Header().Set(contentType, contenttype.ASUTF8)
|
||||
_ = a.min.Get().Minify(contenttype.AS, w, bytes.NewReader(binary))
|
||||
}
|
||||
|
||||
func apUsername(person *ap.Person) string {
|
||||
preferredUsername := person.PreferredUsername.First().Value.String()
|
||||
u, err := url.Parse(person.GetLink().String())
|
||||
if err != nil || u == nil || u.Host == "" || preferredUsername == "" {
|
||||
return person.GetLink().String()
|
||||
}
|
||||
return fmt.Sprintf("@%s@%s", preferredUsername, u.Host)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ap "github.com/go-ap/activitypub"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_apUsername(t *testing.T) {
|
||||
item, err := ap.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1"
|
||||
],
|
||||
"id": "https://example.org/users/user",
|
||||
"type": "Person",
|
||||
"preferredUsername": "user",
|
||||
"name": "Example user",
|
||||
"url": "https://example.org/@user"
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
|
||||
actor, err := ap.ToActor(item)
|
||||
require.NoError(t, err)
|
||||
|
||||
username := apUsername(actor)
|
||||
assert.Equal(t, "@user@example.org", username)
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
alter table activitypub_followers add username text not null default "";
|
||||
update activitypub_followers set username = follower;
|
8
go.mod
8
go.mod
|
@ -21,9 +21,9 @@ require (
|
|||
github.com/elnormous/contenttype v1.0.3
|
||||
github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead
|
||||
github.com/emersion/go-smtp v0.15.0
|
||||
github.com/go-ap/activitypub v0.0.0-20221206062958-cae46e718d79
|
||||
github.com/go-ap/activitypub v0.0.0-20221207073405-5d6d22cbc42e
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
||||
github.com/go-chi/chi/v5 v5.0.7
|
||||
github.com/go-chi/chi/v5 v5.0.8
|
||||
github.com/go-fed/httpsig v1.1.0
|
||||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
|
||||
github.com/google/uuid v1.3.0
|
||||
|
@ -61,8 +61,8 @@ require (
|
|||
github.com/yuin/goldmark v1.5.3
|
||||
// master
|
||||
github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38
|
||||
golang.org/x/crypto v0.3.0
|
||||
golang.org/x/net v0.3.0
|
||||
golang.org/x/crypto v0.4.0
|
||||
golang.org/x/net v0.4.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/text v0.5.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
|
|
16
go.sum
16
go.sum
|
@ -124,14 +124,14 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
|||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/go-ap/activitypub v0.0.0-20221206062958-cae46e718d79 h1:iZ2ITdeyrEpQL0nOIWpdje6qtk3cBBuylB5fI7TI3Rc=
|
||||
github.com/go-ap/activitypub v0.0.0-20221206062958-cae46e718d79/go.mod h1:1oVD0h0aPT3OEE1ZoSUoym/UGKzxe+e0y8K2AkQ1Hqs=
|
||||
github.com/go-ap/activitypub v0.0.0-20221207073405-5d6d22cbc42e h1:Qb0THMsDaDvRqvAwUFzJmN6WRbweiHUOoy9nY6GCw2M=
|
||||
github.com/go-ap/activitypub v0.0.0-20221207073405-5d6d22cbc42e/go.mod h1:1oVD0h0aPT3OEE1ZoSUoym/UGKzxe+e0y8K2AkQ1Hqs=
|
||||
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea h1:ywGtLGVjJjMrq4mu35Qmu+NtlhlTk/gTayE6Bb4tQZk=
|
||||
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea/go.mod h1:SaTNjEEkp0q+w3pUS1ccyEL/lUrHteORlDq/e21mCc8=
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw=
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA=
|
||||
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
|
||||
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
|
||||
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
|
||||
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
|
@ -418,8 +418,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -494,8 +494,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
|
25
ui.go
25
ui.go
|
@ -1627,30 +1627,15 @@ func (a *goBlog) renderActivityPubFollowers(hb *htmlbuilder.HtmlBuilder, rd *ren
|
|||
hb.WriteElementClose("h1")
|
||||
|
||||
// List followers
|
||||
hb.WriteElementOpen("table")
|
||||
hb.WriteElementOpen("thead")
|
||||
hb.WriteElementOpen("th", "class", "tal")
|
||||
hb.WriteEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "apfollower"))
|
||||
hb.WriteElementClose("th")
|
||||
hb.WriteElementOpen("th", "class", "tar")
|
||||
hb.WriteEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "apinbox"))
|
||||
hb.WriteElementClose("th")
|
||||
hb.WriteElementClose("thead")
|
||||
hb.WriteElementOpen("tbody")
|
||||
hb.WriteElementOpen("ul")
|
||||
for _, follower := range aprd.followers {
|
||||
hb.WriteElementOpen("tr")
|
||||
hb.WriteElementOpen("td", "class", "tal")
|
||||
hb.WriteElementOpen("li")
|
||||
hb.WriteElementOpen("a", "href", follower.follower, "target", "_blank")
|
||||
hb.WriteEscaped(follower.follower)
|
||||
hb.WriteEscaped(follower.username)
|
||||
hb.WriteElementClose("a")
|
||||
hb.WriteElementClose("td")
|
||||
hb.WriteElementOpen("td", "class", "tar")
|
||||
hb.WriteEscaped(follower.inbox)
|
||||
hb.WriteElementClose("td")
|
||||
hb.WriteElementClose("tr")
|
||||
hb.WriteElementClose("li")
|
||||
}
|
||||
hb.WriteElementClose("tbody")
|
||||
hb.WriteElementClose("table")
|
||||
hb.WriteElementClose("ul")
|
||||
|
||||
hb.WriteElementClose("main")
|
||||
},
|
||||
|
|
19
utils.go
19
utils.go
|
@ -6,7 +6,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
|
@ -404,21 +403,3 @@ func stringToInt(s string) int {
|
|||
func loStringNotEmpty(s string, _ int) bool {
|
||||
return s != ""
|
||||
}
|
||||
|
||||
func mimeTypeFromUrl(urlString string) string {
|
||||
parsedUrl, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
ext := path.Ext(parsedUrl.Path)
|
||||
mimeType := mime.TypeByExtension(ext)
|
||||
if mimeType == "" {
|
||||
switch ext {
|
||||
case ".jpg":
|
||||
mimeType = "image/jpeg"
|
||||
default:
|
||||
mimeType = "image/" + strings.TrimPrefix(ext, ".")
|
||||
}
|
||||
}
|
||||
return mimeType
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -168,24 +167,3 @@ func Test_groupStrings(t *testing.T) {
|
|||
assert.Equal(t, "H", groups[3].Identifier)
|
||||
assert.Equal(t, "🚴", groups[4].Identifier)
|
||||
}
|
||||
|
||||
func Test_mimeTypeFromUrl(t *testing.T) {
|
||||
type test struct {
|
||||
url string
|
||||
want string
|
||||
}
|
||||
tests := []*test{
|
||||
{url: "https://example.com/profile.jpg", want: "image/jpeg"},
|
||||
{url: "https://example.com/profile.jpeg", want: "image/jpeg"},
|
||||
{url: "https://example.com/profile.png", want: "image/png"},
|
||||
{url: "https://example.com/profile.png?v=3", want: "image/png"},
|
||||
{url: "/profile.png?v=3", want: "image/png"},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
if got := mimeTypeFromUrl(tt.url); got != tt.want {
|
||||
t.Errorf("mimeTypeFromUrl() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue