fix: harden ActivityPub federation and fix N+1 follower fanout (#1056)
* initial commit * improve activitypub recipient query * small fixes --------- Co-authored-by: Christian Beutel <> Co-authored-by: slothful-vassal <89943360+slothful-vassal@users.noreply.github.com>
This commit is contained in:
@@ -18,11 +18,40 @@ import (
|
|||||||
|
|
||||||
"github.com/go-ap/jsonld"
|
"github.com/go-ap/jsonld"
|
||||||
"github.com/go-fed/httpsig"
|
"github.com/go-fed/httpsig"
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/tools/security"
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
"golang.org/x/sync/semaphore"
|
"golang.org/x/sync/semaphore"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var httpClient = &http.Client{Timeout: 10 * time.Second}
|
||||||
|
|
||||||
|
// followerInboxes returns inbox URLs for all accepted followers of actorId
|
||||||
|
// in a single JOIN query instead of one query per follower.
|
||||||
|
func followerInboxes(app core.App, actorId string) ([]string, error) {
|
||||||
|
rows, err := app.DB().
|
||||||
|
Select("aa.inbox").
|
||||||
|
From("follows f").
|
||||||
|
InnerJoin("activitypub_actors aa", dbx.NewExp("f.follower = aa.id")).
|
||||||
|
Where(dbx.NewExp("f.followee = {:followee} AND f.status = 'accepted' AND aa.inbox != ''",
|
||||||
|
dbx.Params{"followee": actorId})).
|
||||||
|
Rows()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var inboxes []string
|
||||||
|
for rows.Next() {
|
||||||
|
var inbox string
|
||||||
|
if err := rows.Scan(&inbox); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
inboxes = append(inboxes, inbox)
|
||||||
|
}
|
||||||
|
return inboxes, rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
func PostActivity(app core.App, actor *core.Record, activity *pub.Activity, recipients []string) error {
|
func PostActivity(app core.App, actor *core.Record, activity *pub.Activity, recipients []string) error {
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -67,7 +96,6 @@ func PostActivity(app core.App, actor *core.Record, activity *pub.Activity, reci
|
|||||||
}
|
}
|
||||||
pubID := actor.GetString("iri") + "#main-key"
|
pubID := actor.GetString("iri") + "#main-key"
|
||||||
|
|
||||||
client := &http.Client{}
|
|
||||||
sem := semaphore.NewWeighted(5)
|
sem := semaphore.NewWeighted(5)
|
||||||
|
|
||||||
slices.Sort(recipients)
|
slices.Sort(recipients)
|
||||||
@@ -105,7 +133,7 @@ func PostActivity(app core.App, actor *core.Record, activity *pub.Activity, reci
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.Logger().Error(fmt.Sprintf("Error sending to inbox %s: %s", inbox, err))
|
app.Logger().Error(fmt.Sprintf("Error sending to inbox %s: %s", inbox, err))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -194,12 +194,21 @@ func assembleActor(app core.App, ctx context.Context, dbActor *core.Record, incl
|
|||||||
|
|
||||||
dbActor.Set("last_fetched", time.Now())
|
dbActor.Set("last_fetched", time.Now())
|
||||||
|
|
||||||
|
// an empty privacy field is the default for users who never touched
|
||||||
|
// their privacy settings and is treated as public. A non-empty but
|
||||||
|
// corrupt value fails closed (private) so a broken setting can't
|
||||||
|
// silently expose a profile.
|
||||||
privacy := settings.GetString("privacy")
|
privacy := settings.GetString("privacy")
|
||||||
|
if privacy != "" {
|
||||||
result := make(map[string]interface{})
|
result := make(map[string]interface{})
|
||||||
json.Unmarshal([]byte(privacy), &result)
|
if err := json.Unmarshal([]byte(privacy), &result); err != nil {
|
||||||
|
private = true
|
||||||
|
} else {
|
||||||
// check that it's not our own profile
|
// check that it's not our own profile
|
||||||
private = result["account"] == "private" && dbActor.Id != strings.TrimPrefix(ctx.Value("actor").(string), "actor:")
|
actorVal, _ := ctx.Value("actor").(string)
|
||||||
|
private = result["account"] == "private" && dbActor.Id != strings.TrimPrefix(actorVal, "actor:")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -279,6 +288,9 @@ func fetchRemoteActor(app core.App, ctx context.Context, iri string, includeFoll
|
|||||||
client := util.SafeHTTPClient()
|
client := util.SafeHTTPClient()
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", iri, nil)
|
req, err := http.NewRequestWithContext(ctx, "GET", iri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
headers := map[string]string{
|
headers := map[string]string{
|
||||||
"Accept": "application/ld+json",
|
"Accept": "application/ld+json",
|
||||||
@@ -291,7 +303,8 @@ func fetchRemoteActor(app core.App, ctx context.Context, iri string, includeFoll
|
|||||||
req.Header.Add(k, v)
|
req.Header.Add(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
userActorId := strings.TrimPrefix(ctx.Value("actor").(string), "actor:")
|
actorVal, _ := ctx.Value("actor").(string)
|
||||||
|
userActorId := strings.TrimPrefix(actorVal, "actor:")
|
||||||
userActor, err := app.FindRecordById("activitypub_actors", userActorId)
|
userActor, err := app.FindRecordById("activitypub_actors", userActorId)
|
||||||
if userActor != nil && userActor.GetString("private_key") != "" {
|
if userActor != nil && userActor.GetString("private_key") != "" {
|
||||||
dbPrivateKey := userActor.GetString("private_key")
|
dbPrivateKey := userActor.GetString("private_key")
|
||||||
@@ -332,7 +345,7 @@ func fetchRemoteActor(app core.App, ctx context.Context, iri string, includeFoll
|
|||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
var pubActor pub.Actor
|
var pubActor pub.Actor
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&pubActor); err != nil {
|
if err := json.NewDecoder(io.LimitReader(resp.Body, 1<<20)).Decode(&pubActor); err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,6 +378,9 @@ func FetchCollection(app core.App, ctx context.Context, collectionURL string) (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", collectionURL, nil)
|
req, err := http.NewRequestWithContext(ctx, "GET", collectionURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
headers := map[string]string{
|
headers := map[string]string{
|
||||||
"Accept": "application/ld+json",
|
"Accept": "application/ld+json",
|
||||||
@@ -376,7 +392,8 @@ func FetchCollection(app core.App, ctx context.Context, collectionURL string) (*
|
|||||||
for k, v := range headers {
|
for k, v := range headers {
|
||||||
req.Header.Add(k, v)
|
req.Header.Add(k, v)
|
||||||
}
|
}
|
||||||
userActorId := strings.TrimPrefix(ctx.Value("actor").(string), "actor:")
|
actorVal, _ := ctx.Value("actor").(string)
|
||||||
|
userActorId := strings.TrimPrefix(actorVal, "actor:")
|
||||||
userActor, err := app.FindRecordById("activitypub_actors", userActorId)
|
userActor, err := app.FindRecordById("activitypub_actors", userActorId)
|
||||||
if userActor != nil && userActor.GetString("private_key") != "" {
|
if userActor != nil && userActor.GetString("private_key") != "" {
|
||||||
dbPrivateKey := userActor.GetString("private_key")
|
dbPrivateKey := userActor.GetString("private_key")
|
||||||
|
|||||||
@@ -113,14 +113,12 @@ func ProcessAnnounceActivity(app core.App, actor *core.Record, activity pub.Acti
|
|||||||
object := activity.Object.GetID().String()
|
object := activity.Object.GetID().String()
|
||||||
|
|
||||||
if strings.Contains(object, "/api/v1/trail") {
|
if strings.Contains(object, "/api/v1/trail") {
|
||||||
processTrailAnnounceActivity(app, actor, activity)
|
return processTrailAnnounceActivity(app, actor, activity)
|
||||||
|
|
||||||
} else if strings.Contains(object, "/api/v1/list") {
|
} else if strings.Contains(object, "/api/v1/list") {
|
||||||
processListAnnounceActivity(app, actor, activity)
|
return processListAnnounceActivity(app, actor, activity)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("unknown announce type")
|
return fmt.Errorf("unknown announce type")
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"pocketbase/util"
|
"pocketbase/util"
|
||||||
|
|
||||||
pub "github.com/go-ap/activitypub"
|
pub "github.com/go-ap/activitypub"
|
||||||
"github.com/pocketbase/dbx"
|
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/tools/filesystem"
|
"github.com/pocketbase/pocketbase/tools/filesystem"
|
||||||
"github.com/pocketbase/pocketbase/tools/security"
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
@@ -89,19 +88,11 @@ func CreateTrailActivity(app core.App, ctx context.Context, trail *core.Record,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": trailAuthor.Id})
|
inboxes, err := followerInboxes(app, trailAuthor.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
recipients := append(mentions, inboxes...)
|
||||||
recipients := mentions
|
|
||||||
for _, f := range follows {
|
|
||||||
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
recipients = append(recipients, follower.GetString("inbox"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return PostActivity(app, trailAuthor, activity, recipients)
|
return PostActivity(app, trailAuthor, activity, recipients)
|
||||||
}
|
}
|
||||||
@@ -264,15 +255,14 @@ func CreateSummitLogActivity(app core.App, ctx context.Context, summitLog *core.
|
|||||||
gpx = fmt.Sprintf("%s/api/v1/files/summit_logs/%s/%s", origin, summitLog.Id, summitLog.GetString("gpx"))
|
gpx = fmt.Sprintf("%s/api/v1/files/summit_logs/%s/%s", origin, summitLog.Id, summitLog.GetString("gpx"))
|
||||||
}
|
}
|
||||||
|
|
||||||
attachments := make(pub.ItemCollection, max(len(photos), 2))
|
attachments := make(pub.ItemCollection, 0, len(photos)+1)
|
||||||
for i := range len(photos) {
|
for i := range len(photos) {
|
||||||
iri := fmt.Sprintf("%s/api/v1/files/summit_logs/%s/%s", origin, summitLog.Id, photos[i])
|
iri := fmt.Sprintf("%s/api/v1/files/summit_logs/%s/%s", origin, summitLog.Id, photos[i])
|
||||||
|
attachments.Append(pub.Document{
|
||||||
attachments[i] = pub.Document{
|
|
||||||
Type: pub.ImageType,
|
Type: pub.ImageType,
|
||||||
MediaType: "image/jpeg",
|
MediaType: "image/jpeg",
|
||||||
URL: pub.IRI(iri),
|
URL: pub.IRI(iri),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
if gpx != "" {
|
if gpx != "" {
|
||||||
attachments.Append(pub.Document{
|
attachments.Append(pub.Document{
|
||||||
@@ -328,20 +318,11 @@ func CreateSummitLogActivity(app core.App, ctx context.Context, summitLog *core.
|
|||||||
activity.CC = cc
|
activity.CC = cc
|
||||||
activity.Published = time.Now()
|
activity.Published = time.Now()
|
||||||
|
|
||||||
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": summitLogAuthor.Id})
|
inboxes, err := followerInboxes(app, summitLogAuthor.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
recipients := append(mentions, inboxes...)
|
||||||
recipients := mentions
|
|
||||||
|
|
||||||
for _, f := range follows {
|
|
||||||
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
recipients = append(recipients, follower.GetString("inbox"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if summitLogAuthor.Id != summitLogTrailAuthor.Id {
|
if summitLogAuthor.Id != summitLogTrailAuthor.Id {
|
||||||
recipients = append(recipients, summitLogTrailAuthor.GetString("inbox"))
|
recipients = append(recipients, summitLogTrailAuthor.GetString("inbox"))
|
||||||
@@ -405,20 +386,11 @@ func CreateListActivity(app core.App, list *core.Record, typ pub.ActivityVocabul
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": listAuthor.Id})
|
recipients, err := followerInboxes(app, listAuthor.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
recipients := []string{}
|
|
||||||
for _, f := range follows {
|
|
||||||
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
recipients = append(recipients, follower.GetString("inbox"))
|
|
||||||
}
|
|
||||||
|
|
||||||
err = PostActivity(app, listAuthor, activity, recipients)
|
err = PostActivity(app, listAuthor, activity, recipients)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -469,7 +441,10 @@ func processCreateOrUpdateTrailActivity(activity pub.Activity, app core.App, act
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
trailObject, _ := pub.ToObject(activity.Object)
|
trailObject, err := pub.ToObject(activity.Object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for _, t := range trailObject.Tag {
|
for _, t := range trailObject.Tag {
|
||||||
if t.GetType() == pub.MentionType {
|
if t.GetType() == pub.MentionType {
|
||||||
@@ -487,11 +462,11 @@ func processCreateOrUpdateTrailActivity(activity pub.Activity, app core.App, act
|
|||||||
Seen: false,
|
Seen: false,
|
||||||
Author: actor.Id,
|
Author: actor.Id,
|
||||||
}
|
}
|
||||||
return util.SendNotification(app, notification, mentionedActor)
|
util.SendNotification(app, notification, mentionedActor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func processCreateOrUpdateCommentActivity(activity pub.Activity, app core.App, actor *core.Record) error {
|
func processCreateOrUpdateCommentActivity(activity pub.Activity, app core.App, actor *core.Record) error {
|
||||||
@@ -578,7 +553,7 @@ func processCreateOrUpdateCommentActivity(activity pub.Activity, app core.App, a
|
|||||||
Seen: false,
|
Seen: false,
|
||||||
Author: actor.Id,
|
Author: actor.Id,
|
||||||
}
|
}
|
||||||
return util.SendNotification(app, notification, mentionedActor)
|
util.SendNotification(app, notification, mentionedActor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if activity.Type == pub.CreateType {
|
if activity.Type == pub.CreateType {
|
||||||
@@ -629,6 +604,11 @@ func processCreateOrUpdateSummitLogActivity(activity pub.Activity, app core.App,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no need to do anything else if the actor is local
|
||||||
|
if actor.GetBool("is_local") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
newSummitLog := false
|
newSummitLog := false
|
||||||
record, err := app.FindFirstRecordByData("summit_logs", "iri", logObject.ID.String())
|
record, err := app.FindFirstRecordByData("summit_logs", "iri", logObject.ID.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -644,10 +624,6 @@ func processCreateOrUpdateSummitLogActivity(activity pub.Activity, app core.App,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// no need to do anything else if the actor is local
|
|
||||||
if actor.GetBool("is_local") {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var distance, duration, elevation_gain, elevation_loss float64
|
var distance, duration, elevation_gain, elevation_loss float64
|
||||||
tags, err := pub.ToItemCollection(logObject.Tag)
|
tags, err := pub.ToItemCollection(logObject.Tag)
|
||||||
@@ -752,7 +728,7 @@ func processCreateOrUpdateSummitLogActivity(activity pub.Activity, app core.App,
|
|||||||
Seen: false,
|
Seen: false,
|
||||||
Author: actor.Id,
|
Author: actor.Id,
|
||||||
}
|
}
|
||||||
return util.SendNotification(app, notification, mentionedActor)
|
util.SendNotification(app, notification, mentionedActor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
pub "github.com/go-ap/activitypub"
|
pub "github.com/go-ap/activitypub"
|
||||||
"github.com/meilisearch/meilisearch-go"
|
"github.com/meilisearch/meilisearch-go"
|
||||||
"github.com/pocketbase/dbx"
|
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/tools/security"
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
)
|
)
|
||||||
@@ -29,6 +28,10 @@ func CreateTrailDeleteActivity(app core.App, r *core.Record) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !author.GetBool("is_local") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -62,20 +65,11 @@ func CreateTrailDeleteActivity(app core.App, r *core.Record) error {
|
|||||||
activity.CC = pub.ItemCollection{pub.IRI(cc)}
|
activity.CC = pub.ItemCollection{pub.IRI(cc)}
|
||||||
activity.Published = time.Now()
|
activity.Published = time.Now()
|
||||||
|
|
||||||
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": author.Id})
|
recipients, err := followerInboxes(app, author.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
recipients := []string{}
|
|
||||||
for _, f := range follows {
|
|
||||||
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
recipients = append(recipients, follower.GetString("inbox"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return PostActivity(app, author, activity, recipients)
|
return PostActivity(app, author, activity, recipients)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,21 +179,11 @@ func CreateSummitLogDeleteActivity(app core.App, r *core.Record) error {
|
|||||||
activity.CC = cc
|
activity.CC = cc
|
||||||
activity.Published = time.Now()
|
activity.Published = time.Now()
|
||||||
|
|
||||||
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": author.Id})
|
recipients, err := followerInboxes(app, author.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
recipients := []string{}
|
|
||||||
|
|
||||||
for _, f := range follows {
|
|
||||||
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
recipients = append(recipients, follower.GetString("inbox"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if author.Id != summitLogTrailAuthor.Id {
|
if author.Id != summitLogTrailAuthor.Id {
|
||||||
recipients = append(recipients, summitLogTrailAuthor.GetString("inbox"))
|
recipients = append(recipients, summitLogTrailAuthor.GetString("inbox"))
|
||||||
}
|
}
|
||||||
@@ -256,20 +240,11 @@ func CreateListDeleteActivity(app core.App, r *core.Record) error {
|
|||||||
activity.CC = pub.ItemCollection{pub.IRI(cc)}
|
activity.CC = pub.ItemCollection{pub.IRI(cc)}
|
||||||
activity.Published = time.Now()
|
activity.Published = time.Now()
|
||||||
|
|
||||||
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": author.Id})
|
recipients, err := followerInboxes(app, author.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
recipients := []string{}
|
|
||||||
for _, f := range follows {
|
|
||||||
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
recipients = append(recipients, follower.GetString("inbox"))
|
|
||||||
}
|
|
||||||
|
|
||||||
err = PostActivity(app, author, activity, recipients)
|
err = PostActivity(app, author, activity, recipients)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ func UpdateListHandler(client meilisearch.ServiceManager) func(e *core.RecordEve
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = federation.CreateListActivity(e.App, e.Record, pub.CreateType)
|
err = federation.CreateListActivity(e.App, e.Record, pub.UpdateType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user