Add IRI to local resources (#1046)
* initial commit * add remote trail/list * fix errors * update to use new IRIs * use origin in migration instead * use UnsafeWithoutHooks * fix trail/list order of operations * fix remote trail/list fetch * fixes list document update * fix errors --------- Co-authored-by: Christian Beutel <>
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -11,4 +11,7 @@ run.sh
|
|||||||
build*.sh
|
build*.sh
|
||||||
start*.*
|
start*.*
|
||||||
|
|
||||||
data*/
|
data*/
|
||||||
|
.planning/
|
||||||
|
.claude
|
||||||
|
CLAUDE.md
|
||||||
@@ -3,9 +3,7 @@ package federation
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"pocketbase/util"
|
"pocketbase/util"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -180,12 +178,7 @@ func processTrailAnnounceActivity(app core.App, actor *core.Record, activity pub
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
trailUrl, err := url.Parse(activity.Object.GetID().String())
|
trail, err = app.FindFirstRecordByData("trails", "iri", activity.Object.GetID().String())
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
trailId := path.Base(trailUrl.Path)
|
|
||||||
trail, err = app.FindRecordById("trails", trailId)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -245,12 +238,7 @@ func processListAnnounceActivity(app core.App, actor *core.Record, activity pub.
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
listUrl, err := url.Parse(activity.Object.GetID().String())
|
list, err = app.FindFirstRecordByData("lists", "iri", activity.Object.GetID().String())
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
listId := path.Base(listUrl.Path)
|
|
||||||
list, err = app.FindRecordById("trails", listId)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -228,12 +226,7 @@ func CreateSummitLogActivity(app core.App, ctx context.Context, summitLog *core.
|
|||||||
}
|
}
|
||||||
|
|
||||||
var trailIRI pub.IRI
|
var trailIRI pub.IRI
|
||||||
if summitLogTrailAuthor.GetBool("isLocal") {
|
trailIRI = pub.IRI(summitLogTrail.GetString("iri"))
|
||||||
trailId := summitLog.GetString("trail")
|
|
||||||
trailIRI = pub.IRI(fmt.Sprintf("%s/api/v1/trail/%s", origin, trailId))
|
|
||||||
} else {
|
|
||||||
trailIRI = pub.IRI(summitLogTrail.GetString("iri"))
|
|
||||||
}
|
|
||||||
|
|
||||||
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
@@ -321,7 +314,7 @@ func CreateSummitLogActivity(app core.App, ctx context.Context, summitLog *core.
|
|||||||
logObject.Content = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, summitLog.GetString("text")))
|
logObject.Content = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, summitLog.GetString("text")))
|
||||||
logObject.AttributedTo = pub.IRI(summitLogAuthor.GetString("iri"))
|
logObject.AttributedTo = pub.IRI(summitLogAuthor.GetString("iri"))
|
||||||
logObject.Published = summitLog.GetDateTime("created").Time()
|
logObject.Published = summitLog.GetDateTime("created").Time()
|
||||||
logObject.ID = pub.IRI(fmt.Sprintf("%s/api/v1/summit-log/%s", origin, summitLog.Id))
|
logObject.ID = pub.IRI(summitLog.GetString("iri"))
|
||||||
logObject.URL = pub.IRI(fmt.Sprintf("%s/trail/view/@%s/%s", origin, summitLogTrailAuthor.GetString("preferred_username"), summitLog.GetString("trail")))
|
logObject.URL = pub.IRI(fmt.Sprintf("%s/trail/view/@%s/%s", origin, summitLogTrailAuthor.GetString("preferred_username"), summitLog.GetString("trail")))
|
||||||
logObject.InReplyTo = trailIRI
|
logObject.InReplyTo = trailIRI
|
||||||
logObject.Tag = tags
|
logObject.Tag = tags
|
||||||
@@ -512,14 +505,8 @@ func processCreateOrUpdateCommentActivity(activity pub.Activity, app core.App, a
|
|||||||
return fmt.Errorf("error processing comment: InReplyTo empty")
|
return fmt.Errorf("error processing comment: InReplyTo empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
trailUrl, err := url.Parse(commentObject.InReplyTo.GetLink().String())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
trailId := path.Base(trailUrl.Path)
|
|
||||||
|
|
||||||
var trail *core.Record
|
var trail *core.Record
|
||||||
trail, err = app.FindFirstRecordByFilter("trails", "iri={:iri} || id={:id}", dbx.Params{"id": trailId, "iri": commentObject.InReplyTo.GetID().String()})
|
trail, err = app.FindFirstRecordByData("trails", "iri", commentObject.InReplyTo.GetLink().String())
|
||||||
|
|
||||||
// if the trail is not present on this instance fetch it
|
// if the trail is not present on this instance fetch it
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -619,13 +606,7 @@ func processCreateOrUpdateSummitLogActivity(activity pub.Activity, app core.App,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
trailIRI, err := url.Parse(logObject.InReplyTo.GetID().String())
|
trail, err := app.FindFirstRecordByData("trails", "iri", logObject.InReplyTo.GetID().String())
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
trailId := path.Base(trailIRI.Path)
|
|
||||||
|
|
||||||
trail, err := app.FindFirstRecordByFilter("trails", "iri={:iri} || id={:id}", dbx.Params{"id": trailId, "iri": logObject.InReplyTo.GetID().String()})
|
|
||||||
// if the trail is not present on this instance fetch it
|
// if the trail is not present on this instance fetch it
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func CreateTrailDeleteActivity(app core.App, r *core.Record) error {
|
|||||||
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
to := "https://www.w3.org/ns/activitystreams#Public"
|
to := "https://www.w3.org/ns/activitystreams#Public"
|
||||||
cc := author.GetString("iri") + "/followers"
|
cc := author.GetString("iri") + "/followers"
|
||||||
object := fmt.Sprintf("%s/api/v1/trail/%s", origin, r.Id)
|
object := r.GetString("iri")
|
||||||
|
|
||||||
record := core.NewRecord(collection)
|
record := core.NewRecord(collection)
|
||||||
record.Set("id", recordId)
|
record.Set("id", recordId)
|
||||||
@@ -118,7 +118,7 @@ func CreateCommentDeleteActivity(app core.App, client meilisearch.ServiceManager
|
|||||||
|
|
||||||
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
to := commentTrailAuthor.GetString("iri")
|
to := commentTrailAuthor.GetString("iri")
|
||||||
object := fmt.Sprintf("%s/api/v1/comment/%s", origin, r.Id)
|
object := r.GetString("iri")
|
||||||
|
|
||||||
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
|
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
|
||||||
activity.Actor = pub.IRI(author.GetString("iri"))
|
activity.Actor = pub.IRI(author.GetString("iri"))
|
||||||
@@ -176,7 +176,7 @@ func CreateSummitLogDeleteActivity(app core.App, r *core.Record) error {
|
|||||||
|
|
||||||
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
to := summitLogTrailAuthor.GetString("iri")
|
to := summitLogTrailAuthor.GetString("iri")
|
||||||
object := fmt.Sprintf("%s/api/v1/summit-log/%s", origin, r.Id)
|
object := r.GetString("iri")
|
||||||
cc := pub.ItemCollection{pub.IRI(author.GetString("iri") + "/followers")}
|
cc := pub.ItemCollection{pub.IRI(author.GetString("iri") + "/followers")}
|
||||||
|
|
||||||
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
|
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
|
||||||
@@ -248,7 +248,7 @@ func CreateListDeleteActivity(app core.App, r *core.Record) error {
|
|||||||
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
to := "https://www.w3.org/ns/activitystreams#Public"
|
to := "https://www.w3.org/ns/activitystreams#Public"
|
||||||
cc := author.GetString("iri") + "/followers"
|
cc := author.GetString("iri") + "/followers"
|
||||||
object := fmt.Sprintf("%s/api/v1/list/%s", origin, r.Id)
|
object := r.GetString("iri")
|
||||||
|
|
||||||
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
|
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
|
||||||
activity.Actor = pub.IRI(author.GetString("iri"))
|
activity.Actor = pub.IRI(author.GetString("iri"))
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package federation
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"pocketbase/util"
|
"pocketbase/util"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -36,11 +35,6 @@ func CreateLikeActivity(app core.App, like *core.Record) error {
|
|||||||
|
|
||||||
object := trail.GetString("iri")
|
object := trail.GetString("iri")
|
||||||
|
|
||||||
if object == "" {
|
|
||||||
// trail is local
|
|
||||||
object = fmt.Sprintf("%s/api/v1/trail/%s", origin, trail.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -76,8 +70,7 @@ func ProcessLikeActivity(app core.App, actor *core.Record, activity pub.Activity
|
|||||||
return fmt.Errorf("ORIGIN not set")
|
return fmt.Errorf("ORIGIN not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
trailId := path.Base(activity.Object.GetID().String())
|
trail, err := app.FindFirstRecordByData("trails", "iri", activity.Object.GetID().String())
|
||||||
trail, err := app.FindRecordById("trails", trailId)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package federation
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
pub "github.com/go-ap/activitypub"
|
pub "github.com/go-ap/activitypub"
|
||||||
@@ -91,10 +90,6 @@ func CreateUnlikeActivity(app core.App, like *core.Record) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object := trail.GetString("iri")
|
object := trail.GetString("iri")
|
||||||
if object == "" {
|
|
||||||
// trail is local
|
|
||||||
object = fmt.Sprintf("%s/api/v1/trail/%s", origin, trail.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the original follow activity
|
// find the original follow activity
|
||||||
likeActivityRecord, err := app.FindFirstRecordByFilter("activitypub_activities", "actor={:actor}&&object={:object}&&type={:type}", dbx.Params{"actor": actor.GetString("iri"), "object": object, "type": string(pub.LikeType)})
|
likeActivityRecord, err := app.FindFirstRecordByFilter("activitypub_activities", "actor={:actor}&&object={:object}&&type={:type}", dbx.Params{"actor": actor.GetString("iri"), "object": object, "type": string(pub.LikeType)})
|
||||||
@@ -175,8 +170,7 @@ func processUnlikeActivity(app core.App, actor *core.Record, activity pub.Activi
|
|||||||
|
|
||||||
likeActivity := activity.Object.(*pub.Activity)
|
likeActivity := activity.Object.(*pub.Activity)
|
||||||
|
|
||||||
trailId := path.Base(likeActivity.Object.GetID().String())
|
trail, err := app.FindFirstRecordByData("trails", "iri", likeActivity.Object.GetID().String())
|
||||||
trail, err := app.FindRecordById("trails", trailId)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package hooks
|
package hooks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"pocketbase/federation"
|
"pocketbase/federation"
|
||||||
"pocketbase/util"
|
"pocketbase/util"
|
||||||
|
|
||||||
@@ -12,7 +14,23 @@ import (
|
|||||||
func CreateCommentHandler() func(e *core.RecordRequestEvent) error {
|
func CreateCommentHandler() func(e *core.RecordRequestEvent) error {
|
||||||
return func(e *core.RecordRequestEvent) error {
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
|
||||||
e.Next()
|
err := e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add local iri
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
if e.Record.GetString("iri") == "" {
|
||||||
|
e.Record.Set("iri", fmt.Sprintf("%s/api/v1/comment/%s", origin, e.Record.Id))
|
||||||
|
}
|
||||||
|
err = e.App.UnsafeWithoutHooks().Save(e.Record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
userActor, err := e.App.FindFirstRecordByData("activitypub_actors", "user", e.Auth.Id)
|
userActor, err := e.App.FindFirstRecordByData("activitypub_actors", "user", e.Auth.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package hooks
|
package hooks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"pocketbase/federation"
|
"pocketbase/federation"
|
||||||
"pocketbase/util"
|
"pocketbase/util"
|
||||||
|
|
||||||
@@ -18,20 +20,32 @@ func CreateListHandler(client meilisearch.ServiceManager) func(e *core.RecordEve
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add local iri
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
if e.Record.GetString("iri") == "" {
|
||||||
|
e.Record.Set("iri", fmt.Sprintf("%s/api/v1/list/%s", origin, e.Record.Id))
|
||||||
|
if err = e.App.UnsafeWithoutHooks().Save(e.Record); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := util.IndexLists(e.App, []*core.Record{record}, client); err != nil {
|
if err := util.IndexLists(e.App, []*core.Record{record}, client); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if !author.GetBool("isLocal") {
|
if !author.GetBool("isLocal") {
|
||||||
// this happens if someone fetches a remote list
|
// this happens if someone fetches a remote list
|
||||||
// we create a stub list record for later reference
|
// we create a stub list record for later reference
|
||||||
// no need to create an activity for that
|
// no need to create an activity for that
|
||||||
return e.Next()
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
err = e.Next()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = federation.CreateListActivity(e.App, e.Record, pub.CreateType)
|
err = federation.CreateListActivity(e.App, e.Record, pub.CreateType)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package hooks
|
package hooks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"pocketbase/federation"
|
"pocketbase/federation"
|
||||||
"pocketbase/util"
|
"pocketbase/util"
|
||||||
|
|
||||||
@@ -11,12 +13,24 @@ import (
|
|||||||
|
|
||||||
func CreateSummitLogHandler(client meilisearch.ServiceManager) func(e *core.RecordRequestEvent) error {
|
func CreateSummitLogHandler(client meilisearch.ServiceManager) func(e *core.RecordRequestEvent) error {
|
||||||
return func(e *core.RecordRequestEvent) error {
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
|
||||||
err := e.Next()
|
err := e.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add local iri
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
if e.Record.GetString("iri") == "" {
|
||||||
|
e.Record.Set("iri", fmt.Sprintf("%s/api/v1/summit-log/%s", origin, e.Record.Id))
|
||||||
|
}
|
||||||
|
err = e.App.UnsafeWithoutHooks().Save(e.Record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
userActor, err := e.App.FindFirstRecordByData("activitypub_actors", "user", e.Auth.Id)
|
userActor, err := e.App.FindFirstRecordByData("activitypub_actors", "user", e.Auth.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package hooks
|
package hooks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
"pocketbase/federation"
|
"pocketbase/federation"
|
||||||
"pocketbase/util"
|
"pocketbase/util"
|
||||||
"time"
|
"time"
|
||||||
@@ -23,21 +25,35 @@ func CreateTrailHandler(client meilisearch.ServiceManager) func(e *core.RecordEv
|
|||||||
if err := util.SavePolyline(e.App, record); err != nil {
|
if err := util.SavePolyline(e.App, record); err != nil {
|
||||||
log.Printf("failed to save polyline for trail %s: %v", record.Id, err)
|
log.Printf("failed to save polyline for trail %s: %v", record.Id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add local iri
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
if e.Record.GetString("iri") == "" {
|
||||||
|
e.Record.Set("iri", fmt.Sprintf("%s/api/v1/trail/%s", origin, e.Record.Id))
|
||||||
|
if err = e.App.UnsafeWithoutHooks().Save(e.Record); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := util.IndexTrails(e.App, []*core.Record{record}, client); err != nil {
|
if err := util.IndexTrails(e.App, []*core.Record{record}, client); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !userActor.GetBool("isLocal") {
|
|
||||||
// this happens if someone fetches a remote trail
|
|
||||||
// we create a stub trail record for later reference
|
|
||||||
// no need to create an activity for that
|
|
||||||
return e.Next()
|
|
||||||
}
|
|
||||||
|
|
||||||
err = e.Next()
|
err = e.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !userActor.GetBool("isLocal") {
|
||||||
|
// this happens if someone fetches a remote list
|
||||||
|
// we create a stub list record for later reference
|
||||||
|
// no need to create an activity for that
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
ctx, err := util.GetSafeActorContext(nil, userActor)
|
ctx, err := util.GetSafeActorContext(nil, userActor)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
28
db/hooks/waypoint.go
Normal file
28
db/hooks/waypoint.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package hooks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateWaypointHandler() func(e *core.RecordRequestEvent) error {
|
||||||
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
err := e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add local iri
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
if e.Record.GetString("iri") == "" {
|
||||||
|
e.Record.Set("iri", fmt.Sprintf("%s/api/v1/waypoint/%s", origin, e.Record.Id))
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.App.UnsafeWithoutHooks().Save(e.Record)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -98,6 +98,8 @@ func setupEventHandlers(app *pocketbase.PocketBase, client meilisearch.ServiceMa
|
|||||||
app.OnRecordUpdateRequest("summit_logs").BindFunc(hooks.UpdateSummitLogHandler())
|
app.OnRecordUpdateRequest("summit_logs").BindFunc(hooks.UpdateSummitLogHandler())
|
||||||
app.OnRecordDeleteRequest("summit_logs").BindFunc(hooks.DeleteSummitLogHandler(client))
|
app.OnRecordDeleteRequest("summit_logs").BindFunc(hooks.DeleteSummitLogHandler(client))
|
||||||
|
|
||||||
|
app.OnRecordCreateRequest("waypoints").BindFunc(hooks.CreateWaypointHandler())
|
||||||
|
|
||||||
app.OnRecordCreateRequest("comments").BindFunc(hooks.CreateCommentHandler())
|
app.OnRecordCreateRequest("comments").BindFunc(hooks.CreateCommentHandler())
|
||||||
app.OnRecordUpdateRequest("comments").BindFunc(hooks.UpdateCommentHandler())
|
app.OnRecordUpdateRequest("comments").BindFunc(hooks.UpdateCommentHandler())
|
||||||
app.OnRecordDeleteRequest("comments").BindFunc(hooks.DeleteCommentHandler(client))
|
app.OnRecordDeleteRequest("comments").BindFunc(hooks.DeleteCommentHandler(client))
|
||||||
|
|||||||
126
db/migrations/1780566579_add_iri_to_local_resources.go
Normal file
126
db/migrations/1780566579_add_iri_to_local_resources.go
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
comments, err := app.FindAllRecords("comments")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range comments {
|
||||||
|
iri := c.GetString("iri")
|
||||||
|
if iri != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
iri = fmt.Sprintf("%s/api/v1/comment/%s", origin, c.Id)
|
||||||
|
c.Set("iri", iri)
|
||||||
|
|
||||||
|
if err := app.Save(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ---
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
lists, err := app.FindAllRecords("lists")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, l := range lists {
|
||||||
|
iri := l.GetString("iri")
|
||||||
|
if iri != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
iri = fmt.Sprintf("%s/api/v1/list/%s", origin, l.Id)
|
||||||
|
l.Set("iri", iri)
|
||||||
|
|
||||||
|
if err := app.UnsafeWithoutHooks().Save(l); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ---
|
||||||
|
|
||||||
|
// Summit Logs
|
||||||
|
summitLogs, err := app.FindAllRecords("summit_logs")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sl := range summitLogs {
|
||||||
|
iri := sl.GetString("iri")
|
||||||
|
if iri != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
iri = fmt.Sprintf("%s/api/v1/summit-log/%s", origin, sl.Id)
|
||||||
|
sl.Set("iri", iri)
|
||||||
|
|
||||||
|
if err := app.Save(sl); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ---
|
||||||
|
|
||||||
|
// Trails
|
||||||
|
trails, err := app.FindAllRecords("trails")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range trails {
|
||||||
|
iri := t.GetString("iri")
|
||||||
|
if iri != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
iri = fmt.Sprintf("%s/api/v1/trail/%s", origin, t.Id)
|
||||||
|
t.Set("iri", iri)
|
||||||
|
|
||||||
|
if err := app.UnsafeWithoutHooks().Save(t); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ---
|
||||||
|
|
||||||
|
// Waypoints
|
||||||
|
|
||||||
|
wps, err := app.FindAllRecords("waypoints")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, wp := range wps {
|
||||||
|
iri := wp.GetString("iri")
|
||||||
|
if iri != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
iri = fmt.Sprintf("%s/api/v1/waypoint/%s", origin, wp.Id)
|
||||||
|
wp.Set("iri", iri)
|
||||||
|
|
||||||
|
if err := app.Save(wp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"pocketbase/federation"
|
"pocketbase/federation"
|
||||||
"pocketbase/util"
|
"pocketbase/util"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -350,13 +349,10 @@ func syncSummitLogs(txApp core.App, ctx context.Context, trail *core.Record, ori
|
|||||||
slID, _ := raw["id"].(string)
|
slID, _ := raw["id"].(string)
|
||||||
iri, _ := raw["iri"].(string)
|
iri, _ := raw["iri"].(string)
|
||||||
if iri == "" {
|
if iri == "" {
|
||||||
iri = fmt.Sprintf("%s/api/v1/summit_logs/%s", origin, slID)
|
iri = fmt.Sprintf("%s/api/v1/summit-log/%s", origin, slID)
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteSummitLogUrl, _ := url.Parse(iri)
|
sl, _ := txApp.FindFirstRecordByData("summit_logs", "iri", iri)
|
||||||
possibleLocalId := path.Base(remoteSummitLogUrl.Path)
|
|
||||||
|
|
||||||
sl, _ := txApp.FindFirstRecordByFilter("summit_logs", "iri={:iri} || id={:id}", dbx.Params{"id": possibleLocalId, "iri": iri})
|
|
||||||
if sl == nil {
|
if sl == nil {
|
||||||
sl = core.NewRecord(col)
|
sl = core.NewRecord(col)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,13 @@ func RemoteTrailCommentsList(e *core.RequestEvent) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trailAuthor, err := e.App.FindRecordById("activitypub_actors", trail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Sync remote data first (Fetch + Save)
|
// Sync remote data first (Fetch + Save)
|
||||||
if trail.GetString("iri") != "" {
|
if trail.GetString("iri") != "" && !trailAuthor.GetBool("isLocal") {
|
||||||
_ = syncRemoteComments(e, trail)
|
_ = syncRemoteComments(e, trail)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,11 +154,8 @@ func syncRemoteComments(e *core.RequestEvent, trail *core.Record) error {
|
|||||||
remoteIRI = fmt.Sprintf("%s://%s/api/v1/comment/%s", u.Scheme, u.Host, remoteID)
|
remoteIRI = fmt.Sprintf("%s://%s/api/v1/comment/%s", u.Scheme, u.Host, remoteID)
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteCommentUrl, _ := url.Parse(remoteIRI)
|
|
||||||
possibleLocalId := path.Base(remoteCommentUrl.Path)
|
|
||||||
|
|
||||||
// Find existing record by IRI or ID to avoid duplicates
|
// Find existing record by IRI or ID to avoid duplicates
|
||||||
commentRecord, _ := txApp.FindFirstRecordByFilter("comments", "iri={:iri} || id={:id}", dbx.Params{"id": possibleLocalId, "iri": remoteIRI})
|
commentRecord, _ := txApp.FindFirstRecordByData("comments", "iri", remoteIRI)
|
||||||
if commentRecord == nil {
|
if commentRecord == nil {
|
||||||
commentRecord = core.NewRecord(collection)
|
commentRecord = core.NewRecord(collection)
|
||||||
commentRecord.Set("iri", remoteIRI)
|
commentRecord.Set("iri", remoteIRI)
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -151,24 +150,13 @@ func TrailFromActivity(activity pub.Activity, app core.App, actor *core.Record)
|
|||||||
if !actor.GetBool("isLocal") {
|
if !actor.GetBool("isLocal") {
|
||||||
return nil, fmt.Errorf("refusing remote activity referencing local trail %q", iri)
|
return nil, fmt.Errorf("refusing remote activity referencing local trail %q", iri)
|
||||||
}
|
}
|
||||||
trailUrl, parseErr := url.Parse(iri)
|
|
||||||
if parseErr != nil {
|
return app.FindFirstRecordByData("trails", "iri", iri)
|
||||||
return nil, parseErr
|
|
||||||
}
|
|
||||||
return app.FindRecordById("trails", path.Base(trailUrl.Path))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var record *core.Record
|
var record *core.Record
|
||||||
if actor.GetBool(("isLocal")) {
|
|
||||||
trailUrl, parseErr := url.Parse(iri)
|
record, err = app.FindFirstRecordByData("trails", "iri", iri)
|
||||||
if parseErr != nil {
|
|
||||||
return nil, parseErr
|
|
||||||
}
|
|
||||||
trailId := path.Base(trailUrl.Path)
|
|
||||||
record, err = app.FindRecordById("trails", trailId)
|
|
||||||
} else {
|
|
||||||
record, err = app.FindFirstRecordByData("trails", "iri", iri)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
@@ -432,7 +420,7 @@ func ObjectFromTrail(app core.App, trail *core.Record, mentions *pub.ItemCollect
|
|||||||
}
|
}
|
||||||
trailObject.AttributedTo = pub.IRI(trailAuthor.GetString("iri"))
|
trailObject.AttributedTo = pub.IRI(trailAuthor.GetString("iri"))
|
||||||
trailObject.Published = trail.GetDateTime("created").Time()
|
trailObject.Published = trail.GetDateTime("created").Time()
|
||||||
trailObject.ID = pub.IRI(fmt.Sprintf("%s/api/v1/trail/%s", origin, trail.Id))
|
trailObject.ID = pub.IRI(trail.GetString("iri"))
|
||||||
trailObject.URL = pub.IRI(activityURL)
|
trailObject.URL = pub.IRI(activityURL)
|
||||||
|
|
||||||
trailObject.StartTime = trail.GetDateTime("date").Time()
|
trailObject.StartTime = trail.GetDateTime("date").Time()
|
||||||
@@ -455,24 +443,14 @@ func ListFromActivity(activity pub.Activity, app core.App, actor *core.Record) (
|
|||||||
if !actor.GetBool("isLocal") {
|
if !actor.GetBool("isLocal") {
|
||||||
return nil, fmt.Errorf("refusing remote activity referencing local list %q", iri)
|
return nil, fmt.Errorf("refusing remote activity referencing local list %q", iri)
|
||||||
}
|
}
|
||||||
listURL, parseErr := url.Parse(iri)
|
|
||||||
if parseErr != nil {
|
return app.FindFirstRecordByData("lists", "iri", iri)
|
||||||
return nil, parseErr
|
|
||||||
}
|
|
||||||
return app.FindRecordById("lists", path.Base(listURL.Path))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var record *core.Record
|
var record *core.Record
|
||||||
if actor.GetBool(("isLocal")) {
|
|
||||||
listURL, parseErr := url.Parse(iri)
|
record, err = app.FindFirstRecordByData("lists", "iri", iri)
|
||||||
if parseErr != nil {
|
|
||||||
return nil, parseErr
|
|
||||||
}
|
|
||||||
listId := path.Base(listURL.Path)
|
|
||||||
record, err = app.FindRecordById("lists", listId)
|
|
||||||
} else {
|
|
||||||
record, err = app.FindFirstRecordByData("lists", "iri", iri)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
collection, err := app.FindCollectionByNameOrId("lists")
|
collection, err := app.FindCollectionByNameOrId("lists")
|
||||||
@@ -568,7 +546,7 @@ func ObjectFromList(app core.App, list *core.Record) (*pub.Object, error) {
|
|||||||
|
|
||||||
listObject.AttributedTo = pub.IRI(listAuthor.GetString("iri"))
|
listObject.AttributedTo = pub.IRI(listAuthor.GetString("iri"))
|
||||||
listObject.Published = list.GetDateTime("created").Time()
|
listObject.Published = list.GetDateTime("created").Time()
|
||||||
listObject.ID = pub.IRI(fmt.Sprintf("%s/api/v1/list/%s", origin, list.Id))
|
listObject.ID = pub.IRI(list.GetString("iri"))
|
||||||
listObject.URL = pub.IRI(activityURL)
|
listObject.URL = pub.IRI(activityURL)
|
||||||
listObject.Attachment = attachments
|
listObject.Attachment = attachments
|
||||||
return listObject, nil
|
return listObject, nil
|
||||||
@@ -589,24 +567,13 @@ func ObjectFromComment(app core.App, comment *core.Record, mentions *pub.ItemCol
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
commentTrailAuthor, err := app.FindRecordById("activitypub_actors", commentTrail.GetString("author"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
trailURL := ""
|
|
||||||
if commentTrailAuthor.GetBool("isLocal") {
|
|
||||||
trailURL = fmt.Sprintf("https://%s/api/v1/trail/%s", commentTrailAuthor.GetString("domain"), comment.GetString("trail"))
|
|
||||||
} else {
|
|
||||||
trailURL = commentTrail.GetString("iri")
|
|
||||||
}
|
|
||||||
|
|
||||||
commentObject := pub.ObjectNew(pub.NoteType)
|
commentObject := pub.ObjectNew(pub.NoteType)
|
||||||
commentObject.ID = pub.IRI(fmt.Sprintf("%s/api/v1/comment/%s", origin, comment.Id))
|
commentObject.ID = pub.IRI(comment.GetString("iri"))
|
||||||
commentObject.Content = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, comment.GetString("text")))
|
commentObject.Content = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, comment.GetString("text")))
|
||||||
commentObject.Published = comment.GetDateTime("created").Time()
|
commentObject.Published = comment.GetDateTime("created").Time()
|
||||||
commentObject.AttributedTo = pub.IRI(commentAuthor.GetString("iri"))
|
commentObject.AttributedTo = pub.IRI(commentAuthor.GetString("iri"))
|
||||||
commentObject.InReplyTo = pub.IRI(trailURL)
|
commentObject.InReplyTo = pub.IRI(commentTrail.GetString("iri"))
|
||||||
|
|
||||||
if mentions != nil {
|
if mentions != nil {
|
||||||
commentObject.Tag = *mentions
|
commentObject.Tag = *mentions
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ func documentFromListRecord(r *core.Record, author *core.Record, includeShares b
|
|||||||
totalDuration := 0.0
|
totalDuration := 0.0
|
||||||
trails := len(r.GetStringSlice("trails"))
|
trails := len(r.GetStringSlice("trails"))
|
||||||
|
|
||||||
if r.GetString("iri") != "" {
|
if r.GetString("iri") != "" && !author.GetBool("isLocal") {
|
||||||
doc, err := documentFromRemoteRecord(r, "lists")
|
doc, err := documentFromRemoteRecord(r, "lists")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
totalElevationGain = doc["elevation_gain"].(float64)
|
totalElevationGain = doc["elevation_gain"].(float64)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
<div class="self-start min-w-0 basis-full transition-transform">
|
<div class="self-start min-w-0 basis-full transition-transform">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<h5 class="text-xl font-semibold overflow-hidden overflow-ellipsis shrink-0 max-w-3/4 whitespace-nowrap">
|
<h5 class="text-xl font-semibold overflow-hidden text-ellipsis shrink-0 max-w-3/4 whitespace-nowrap">
|
||||||
{list.name}
|
{list.name}
|
||||||
</h5>
|
</h5>
|
||||||
<div class="basis-full"></div>
|
<div class="basis-full"></div>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export function handleFromRecordWithIRI(record: any) {
|
|||||||
throw new Error("object has no author info")
|
throw new Error("object has no author info")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!record.iri) {
|
if (!record.iri || record.iri.length == 0) {
|
||||||
return `@${record.expand.author.preferred_username}`
|
return `@${record.expand.author.preferred_username}`
|
||||||
}
|
}
|
||||||
const url = new URL(record.iri ?? "")
|
const url = new URL(record.iri ?? "")
|
||||||
|
|||||||
Reference in New Issue
Block a user