Files
wanderer/db/federation/delete.go
Flomp 9276690d60 Federation (#327)
* initial commit federation

* more federation

* more federation

* more federation

* completes follow, accept, undo

* add trail create activity

* process trail create activity

* more trail create activity

* adds missing endpoints

* adds update and delete activity

* adds comment activities

* adds activities back

* adds summit logs activities

* deletes follow counts table

* fixes migrations

* fixes migrations

* fixes migrations

* fixes migrations

* adds remote profiles

* ctd

* ctd

* we are getting closer...

* adds public summit logs

* fixes federated trails in lists

* adds remote lists

* adds list activites

* fixes lists

* adds notifications

* adds iri redirect

* fixes comments and summitlogs

* fixes follows and profiles

* adds asynchronous send

* fixes list search

* adds encryption key

* bug fixes

* fixes activity signing

* removes custon activity object types

* adds html editor

* fixes html editor

* fixes display issues on mastodon

* adds federated sharing

* finishes announcements

* fixes small summit log issues

* adds trail likes

* finalizes likes

* fixes images for komoot

* add disable federation option

* adds private profiles

* updates docs

* adds federated comments

* adds trail and comments actvitiypub routes

* adds mentions to editor

* adds mentions to trails, comments, summit logs

* updates theme

* updates theme

* update docs

* update docs

* updates docs

* fixes various frontend problems

* fixes activitypub follows api

* updates docs

* updates docs

---------

Co-authored-by: Christian Beutel <>
2025-06-21 10:09:22 +02:00

378 lines
9.7 KiB
Go

package federation
import (
"fmt"
"net/url"
"os"
"path"
"strings"
"time"
pub "github.com/go-ap/activitypub"
"github.com/meilisearch/meilisearch-go"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/security"
)
func CreateTrailDeleteActivity(app core.App, r *core.Record) error {
origin := os.Getenv("ORIGIN")
if origin == "" {
return fmt.Errorf("ORIGIN not set")
}
author, err := app.FindRecordById("activitypub_actors", r.GetString("author"))
if err != nil {
return err
}
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
if err != nil {
return err
}
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
to := "https://www.w3.org/ns/activitystreams#Public"
cc := author.GetString("iri") + "/followers"
object := fmt.Sprintf("%s/api/v1/trail/%s", origin, r.Id)
record := core.NewRecord(collection)
record.Set("id", recordId)
record.Set("iri", id)
record.Set("type", string(pub.DeleteType))
record.Set("to", to)
record.Set("cc", cc)
record.Set("object", object)
record.Set("actor", author.GetString("iri"))
record.Set("published", time.Now())
err = app.Save(record)
if err != nil {
return err
}
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
activity.Actor = pub.IRI(author.GetString("iri"))
activity.To = pub.ItemCollection{pub.IRI(to)}
activity.CC = pub.ItemCollection{pub.IRI(cc)}
activity.Published = time.Now()
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": author.Id})
if err != nil {
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)
}
func CreateCommentDeleteActivity(app core.App, client meilisearch.ServiceManager, r *core.Record) error {
origin := os.Getenv("ORIGIN")
if origin == "" {
return fmt.Errorf("ORIGIN not set")
}
author, err := app.FindRecordById("activitypub_actors", r.GetString("author"))
if err != nil {
return err
}
if !author.GetBool("isLocal") {
return nil
}
commentTrail, err := app.FindRecordById("trails", r.GetString("trail"))
if err != nil {
return err
}
commentTrailAuthor, err := app.FindRecordById("activitypub_actors", commentTrail.GetString("author"))
if err != nil {
return err
}
if commentTrailAuthor.GetBool("isLocal") {
return nil
}
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
if err != nil {
return err
}
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
to := commentTrailAuthor.GetString("iri")
object := fmt.Sprintf("%s/api/v1/comment/%s", origin, r.Id)
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
activity.Actor = pub.IRI(author.GetString("iri"))
activity.To = pub.ItemCollection{pub.IRI(to)}
activity.Published = time.Now()
err = PostActivity(app, author, activity, []string{to + "/inbox"})
if err != nil {
return err
}
record := core.NewRecord(collection)
record.Set("id", recordId)
record.Set("iri", id)
record.Set("type", string(pub.DeleteType))
record.Set("to", to)
record.Set("object", object)
record.Set("actor", author.GetString("iri"))
record.Set("published", time.Now())
return app.Save(record)
}
func CreateSummitLogDeleteActivity(app core.App, r *core.Record) error {
origin := os.Getenv("ORIGIN")
if origin == "" {
return fmt.Errorf("ORIGIN not set")
}
author, err := app.FindRecordById("activitypub_actors", r.GetString("author"))
if err != nil {
return err
}
if !author.GetBool("isLocal") {
return nil
}
summitLogTrail, err := app.FindRecordById("trails", r.GetString("trail"))
if err != nil {
return err
}
summitLogTrailAuthor, err := app.FindRecordById("activitypub_actors", summitLogTrail.GetString("author"))
if err != nil {
return err
}
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
if err != nil {
return err
}
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
to := summitLogTrailAuthor.GetString("iri")
object := fmt.Sprintf("%s/api/v1/summit-log/%s", origin, r.Id)
cc := pub.ItemCollection{pub.IRI(author.GetString("iri") + "/followers")}
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
activity.Actor = pub.IRI(author.GetString("iri"))
activity.To = pub.ItemCollection{pub.IRI(to)}
activity.CC = cc
activity.Published = time.Now()
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": author.Id})
if err != nil {
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 {
recipients = append(recipients, summitLogTrailAuthor.GetString("inbox"))
}
err = PostActivity(app, author, activity, recipients)
if err != nil {
return err
}
record := core.NewRecord(collection)
record.Set("id", recordId)
record.Set("iri", id)
record.Set("type", string(pub.DeleteType))
record.Set("to", to)
record.Set("cc", cc)
record.Set("object", object)
record.Set("actor", author.GetString("iri"))
record.Set("published", time.Now())
return app.Save(record)
}
func CreateListDeleteActivity(app core.App, r *core.Record) error {
origin := os.Getenv("ORIGIN")
if origin == "" {
return fmt.Errorf("ORIGIN not set")
}
author, err := app.FindRecordById("activitypub_actors", r.GetString("author"))
if err != nil {
return err
}
if !author.GetBool("isLocal") {
return nil
}
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
if err != nil {
return err
}
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
to := "https://www.w3.org/ns/activitystreams#Public"
cc := author.GetString("iri") + "/followers"
object := fmt.Sprintf("%s/api/v1/list/%s", origin, r.Id)
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
activity.Actor = pub.IRI(author.GetString("iri"))
activity.To = pub.ItemCollection{pub.IRI(to)}
activity.CC = pub.ItemCollection{pub.IRI(cc)}
activity.Published = time.Now()
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": author.Id})
if err != nil {
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)
if err != nil {
return err
}
record := core.NewRecord(collection)
record.Set("id", recordId)
record.Set("iri", id)
record.Set("type", string(pub.DeleteType))
record.Set("to", to)
record.Set("cc", cc)
record.Set("object", object)
record.Set("actor", author.GetString("iri"))
record.Set("published", time.Now())
return app.Save(record)
}
func ProcessDeleteActivity(app core.App, actor *core.Record, activity pub.Activity) error {
// no need to do anything if the actor is local
if actor.GetBool("isLocal") {
return nil
}
object := activity.Object.GetID().String()
var err error
switch {
case strings.Contains(object, "trail"):
err = processDeleteTrailActivity(app, activity)
case strings.Contains(object, "comment"):
err = processDeleteCommentActivity(app, actor, activity)
case strings.Contains(object, "summit-log"):
err = processDeleteSummitLogActivity(app, actor, activity)
case strings.Contains(object, "list"):
err = processDeleteListActivity(app, actor, activity)
}
if err != nil {
return err
}
return nil
}
func processDeleteTrailActivity(app core.App, activity pub.Activity) error {
trailUrl, err := url.Parse(activity.Object.GetID().String())
if err != nil {
return err
}
recordId := path.Base(trailUrl.Path)
trail, err := app.FindRecordById("trails", recordId)
if err != nil {
return err
}
return app.Delete(trail)
}
func processDeleteCommentActivity(app core.App, actor *core.Record, activity pub.Activity) error {
object := activity.Object.GetID().String()
comment, err := app.FindFirstRecordByData("comments", "iri", object)
if err != nil {
return err
}
if comment.GetString("author") != actor.Id {
return fmt.Errorf("actor is not comment author")
}
err = app.Delete(comment)
if err != nil {
return err
}
return nil
}
func processDeleteSummitLogActivity(app core.App, actor *core.Record, activity pub.Activity) error {
object := activity.Object.GetID().String()
summitLog, err := app.FindFirstRecordByData("summit_logs", "iri", object)
if err != nil {
return err
}
if summitLog.GetString("author") != actor.Id {
return fmt.Errorf("actor is not summit log author")
}
return app.Delete(summitLog)
}
func processDeleteListActivity(app core.App, actor *core.Record, activity pub.Activity) error {
object := activity.Object.GetID().String()
list, err := app.FindFirstRecordByData("lists", "iri", object)
if err != nil {
return err
}
if list.GetString("author") != actor.Id {
return fmt.Errorf("actor is not summit log author")
}
return app.Delete(list)
}