diff options
author | 2023-09-23 18:28:12 +0100 | |
---|---|---|
committer | 2023-09-23 18:28:12 +0100 | |
commit | 9f9fcf743dfc914f0e40f67e4f77177bb471b968 (patch) | |
tree | 5d04c99c652711d335bf99e244f9f79293d4c52b /internal/federation/dereferencing/collectionpage.go | |
parent | [chore] deinterface the typeutils.Converter and update to use state structure... (diff) | |
download | gotosocial-9f9fcf743dfc914f0e40f67e4f77177bb471b968.tar.xz |
[bugfix] support both CollectionPage AND OrderedCollectionPage in status replies (#2220)
Diffstat (limited to 'internal/federation/dereferencing/collectionpage.go')
-rw-r--r-- | internal/federation/dereferencing/collectionpage.go | 94 |
1 files changed, 80 insertions, 14 deletions
diff --git a/internal/federation/dereferencing/collectionpage.go b/internal/federation/dereferencing/collectionpage.go index d76c4b2ab..dc4ac7b4b 100644 --- a/internal/federation/dereferencing/collectionpage.go +++ b/internal/federation/dereferencing/collectionpage.go @@ -20,49 +20,115 @@ package dereferencing import ( "context" "encoding/json" - "errors" - "fmt" "net/url" "github.com/superseriousbusiness/activity/streams" "github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/gotosocial/internal/ap" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/log" ) // dereferenceCollectionPage returns the activitystreams CollectionPage at the specified IRI, or an error if something goes wrong. -func (d *deref) dereferenceCollectionPage(ctx context.Context, username string, pageIRI *url.URL) (ap.CollectionPageable, error) { +func (d *deref) dereferenceCollectionPage(ctx context.Context, username string, pageIRI *url.URL) (ap.CollectionPageIterator, error) { if blocked, err := d.state.DB.IsDomainBlocked(ctx, pageIRI.Host); blocked || err != nil { - return nil, fmt.Errorf("DereferenceCollectionPage: domain %s is blocked", pageIRI.Host) + return nil, gtserror.Newf("domain %s is blocked", pageIRI.Host) } transport, err := d.transportController.NewTransportForUsername(ctx, username) if err != nil { - return nil, fmt.Errorf("DereferenceCollectionPage: error creating transport: %s", err) + return nil, gtserror.Newf("error creating transport: %w", err) } b, err := transport.Dereference(ctx, pageIRI) if err != nil { - return nil, fmt.Errorf("DereferenceCollectionPage: error deferencing %s: %s", pageIRI.String(), err) + return nil, gtserror.Newf("error deferencing %s: %w", pageIRI.String(), err) } m := make(map[string]interface{}) if err := json.Unmarshal(b, &m); err != nil { - return nil, fmt.Errorf("DereferenceCollectionPage: error unmarshalling bytes into json: %s", err) + return nil, gtserror.Newf("error unmarshalling bytes into json: %w", err) } t, err := streams.ToType(ctx, m) if err != nil { - return nil, fmt.Errorf("DereferenceCollectionPage: error resolving json into ap vocab type: %s", err) + return nil, gtserror.Newf("error resolving json into ap vocab type: %w", err) } - if t.GetTypeName() != ap.ObjectCollectionPage { - return nil, fmt.Errorf("DereferenceCollectionPage: type name %s not supported", t.GetTypeName()) + page, err := ap.ToCollectionPageIterator(t) + if err != nil { + return nil, gtserror.Newf("error resolving vocab type as page: %w", err) + } + + return page, nil +} + +// getAttachedStatusCollection is a small utility function to fetch the first page of an +// attached activity streams collection from a provided statusable object, along with a URI. +func getAttachedStatusCollectionPage(status ap.Statusable) (ap.CollectionPageIterator, string) { //nolint:gocritic + // Look for an attached status replies (as collection) + replies := status.GetActivityStreamsReplies() + if replies == nil { + return nil, "" + } + + // Look for an attached collection page, wrap and return. + if page := getRepliesCollectionPage(replies); page != nil { + return ap.WrapCollectionPage(page), getIDString(page) + } + + // Look for an attached ordered collection page, wrap and return. + if page := getRepliesOrderedCollectionPage(replies); page != nil { + return ap.WrapOrderedCollectionPage(page), getIDString(page) } - p, ok := t.(vocab.ActivityStreamsCollectionPage) - if !ok { - return nil, errors.New("DereferenceCollectionPage: error resolving type as activitystreams collection page") + log.Warnf(nil, "replies without collection page: %s", getIDString(status)) + return nil, "" +} + +func getRepliesCollectionPage(replies vocab.ActivityStreamsRepliesProperty) vocab.ActivityStreamsCollectionPage { + // Get the status replies collection + collection := replies.GetActivityStreamsCollection() + if collection == nil { + return nil } - return p, nil + // Get the "first" property of the replies collection + first := collection.GetActivityStreamsFirst() + if first == nil { + return nil + } + + // Return the first activity stream collection page + return first.GetActivityStreamsCollectionPage() +} + +func getRepliesOrderedCollectionPage(replies vocab.ActivityStreamsRepliesProperty) vocab.ActivityStreamsOrderedCollectionPage { + // Get the status replies collection + collection := replies.GetActivityStreamsOrderedCollection() + if collection == nil { + return nil + } + + // Get the "first" property of the replies collection + first := collection.GetActivityStreamsFirst() + if first == nil { + return nil + } + + // Return the first activity stream collection page + return first.GetActivityStreamsOrderedCollectionPage() +} + +// getIDString is shorthand to fetch an ID URI string from AP type with attached JSONLDId. +func getIDString(a ap.WithJSONLDId) string { + id := a.GetJSONLDId() + if id == nil { + return "" + } + uri := id.Get() + if uri == nil { + return "" + } + return uri.String() } |