diff options
author | 2023-09-23 18:28:12 +0100 | |
---|---|---|
committer | 2023-09-23 18:28:12 +0100 | |
commit | 9f9fcf743dfc914f0e40f67e4f77177bb471b968 (patch) | |
tree | 5d04c99c652711d335bf99e244f9f79293d4c52b /internal/ap/activitystreams.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/ap/activitystreams.go')
-rw-r--r-- | internal/ap/activitystreams.go | 234 |
1 files changed, 16 insertions, 218 deletions
diff --git a/internal/ap/activitystreams.go b/internal/ap/activitystreams.go index 34a3013a4..f6c412e51 100644 --- a/internal/ap/activitystreams.go +++ b/internal/ap/activitystreams.go @@ -17,15 +17,6 @@ package ap -import ( - "net/url" - "strconv" - - "github.com/superseriousbusiness/activity/streams" - "github.com/superseriousbusiness/activity/streams/vocab" - "github.com/superseriousbusiness/gotosocial/internal/paging" -) - // https://www.w3.org/TR/activitystreams-vocabulary const ( ActivityAccept = "Accept" // ActivityStreamsAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept @@ -63,21 +54,22 @@ const ( ActorPerson = "Person" // ActivityStreamsPerson https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person ActorService = "Service" // ActivityStreamsService https://www.w3.org/TR/activitystreams-vocabulary/#dfn-service - ObjectArticle = "Article" // ActivityStreamsArticle https://www.w3.org/TR/activitystreams-vocabulary/#dfn-article - ObjectAudio = "Audio" // ActivityStreamsAudio https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audio - ObjectDocument = "Document" // ActivityStreamsDocument https://www.w3.org/TR/activitystreams-vocabulary/#dfn-document - ObjectEvent = "Event" // ActivityStreamsEvent https://www.w3.org/TR/activitystreams-vocabulary/#dfn-event - ObjectImage = "Image" // ActivityStreamsImage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image - ObjectNote = "Note" // ActivityStreamsNote https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note - ObjectPage = "Page" // ActivityStreamsPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-page - ObjectPlace = "Place" // ActivityStreamsPlace https://www.w3.org/TR/activitystreams-vocabulary/#dfn-place - ObjectProfile = "Profile" // ActivityStreamsProfile https://www.w3.org/TR/activitystreams-vocabulary/#dfn-profile - ObjectRelationship = "Relationship" // ActivityStreamsRelationship https://www.w3.org/TR/activitystreams-vocabulary/#dfn-relationship - ObjectTombstone = "Tombstone" // ActivityStreamsTombstone https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tombstone - ObjectVideo = "Video" // ActivityStreamsVideo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-video - ObjectCollection = "Collection" // ActivityStreamsCollection https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collection - ObjectCollectionPage = "CollectionPage" // ActivityStreamsCollectionPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collectionpage - ObjectOrderedCollection = "OrderedCollection" // ActivityStreamsOrderedCollection https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection + ObjectArticle = "Article" // ActivityStreamsArticle https://www.w3.org/TR/activitystreams-vocabulary/#dfn-article + ObjectAudio = "Audio" // ActivityStreamsAudio https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audio + ObjectDocument = "Document" // ActivityStreamsDocument https://www.w3.org/TR/activitystreams-vocabulary/#dfn-document + ObjectEvent = "Event" // ActivityStreamsEvent https://www.w3.org/TR/activitystreams-vocabulary/#dfn-event + ObjectImage = "Image" // ActivityStreamsImage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image + ObjectNote = "Note" // ActivityStreamsNote https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note + ObjectPage = "Page" // ActivityStreamsPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-page + ObjectPlace = "Place" // ActivityStreamsPlace https://www.w3.org/TR/activitystreams-vocabulary/#dfn-place + ObjectProfile = "Profile" // ActivityStreamsProfile https://www.w3.org/TR/activitystreams-vocabulary/#dfn-profile + ObjectRelationship = "Relationship" // ActivityStreamsRelationship https://www.w3.org/TR/activitystreams-vocabulary/#dfn-relationship + ObjectTombstone = "Tombstone" // ActivityStreamsTombstone https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tombstone + ObjectVideo = "Video" // ActivityStreamsVideo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-video + ObjectCollection = "Collection" // ActivityStreamsCollection https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collection + ObjectCollectionPage = "CollectionPage" // ActivityStreamsCollectionPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collectionpage + ObjectOrderedCollection = "OrderedCollection" // ActivityStreamsOrderedCollection https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection + ObjectOrderedCollectionPage = "OrderedCollectionPage" // ActivityStreamsOrderedCollectionPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollectionPage // Hashtag is not in the AS spec per se, but it tends to get used // as though 'Hashtag' is a named type under the Tag property. @@ -86,197 +78,3 @@ const ( // and https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tag TagHashtag = "Hashtag" ) - -type CollectionParams struct { - // Containing collection - // ID (i.e. NOT the page). - ID *url.URL - - // Total no. items. - Total int -} - -type CollectionPageParams struct { - // containing collection. - CollectionParams - - // Paging details. - Current *paging.Page - Next *paging.Page - Prev *paging.Page - Query url.Values - - // Item appender for each item at index. - Append func(int, ItemsPropertyBuilder) - Count int -} - -// CollectionPage is a simplified interface type -// that can be fulfilled by either of (where required): -// vocab.ActivityStreamsCollection -// vocab.ActivityStreamsOrderedCollection -type CollectionBuilder interface { - SetJSONLDId(vocab.JSONLDIdProperty) - SetActivityStreamsFirst(vocab.ActivityStreamsFirstProperty) - SetActivityStreamsTotalItems(i vocab.ActivityStreamsTotalItemsProperty) -} - -// CollectionPageBuilder is a simplified interface type -// that can be fulfilled by either of (where required): -// vocab.ActivityStreamsCollectionPage -// vocab.ActivityStreamsOrderedCollectionPage -type CollectionPageBuilder interface { - SetJSONLDId(vocab.JSONLDIdProperty) - SetActivityStreamsPartOf(vocab.ActivityStreamsPartOfProperty) - SetActivityStreamsNext(vocab.ActivityStreamsNextProperty) - SetActivityStreamsPrev(vocab.ActivityStreamsPrevProperty) - SetActivityStreamsTotalItems(i vocab.ActivityStreamsTotalItemsProperty) -} - -// ItemsPropertyBuilder is a simplified interface type -// that can be fulfilled by either of (where required): -// vocab.ActivityStreamsItemsProperty -// vocab.ActivityStreamsOrderedItemsProperty -type ItemsPropertyBuilder interface { - AppendIRI(*url.URL) - - // NOTE: add more of the items-property-like interface - // functions here as you require them for building pages. -} - -// NewASCollection builds and returns a new ActivityStreams Collection from given parameters. -func NewASCollection(params CollectionParams) vocab.ActivityStreamsCollection { - collection := streams.NewActivityStreamsCollection() - buildCollection(collection, params, 40) - return collection -} - -// NewASCollectionPage builds and returns a new ActivityStreams CollectionPage from given parameters (including item property appending function). -func NewASCollectionPage(params CollectionPageParams) vocab.ActivityStreamsCollectionPage { - collectionPage := streams.NewActivityStreamsCollectionPage() - itemsProp := streams.NewActivityStreamsItemsProperty() - buildCollectionPage(collectionPage, itemsProp, collectionPage.SetActivityStreamsItems, params) - return collectionPage -} - -// NewASOrderedCollection builds and returns a new ActivityStreams OrderedCollection from given parameters. -func NewASOrderedCollection(params CollectionParams) vocab.ActivityStreamsOrderedCollection { - collection := streams.NewActivityStreamsOrderedCollection() - buildCollection(collection, params, 40) - return collection -} - -// NewASOrderedCollectionPage builds and returns a new ActivityStreams OrderedCollectionPage from given parameters (including item property appending function). -func NewASOrderedCollectionPage(params CollectionPageParams) vocab.ActivityStreamsOrderedCollectionPage { - collectionPage := streams.NewActivityStreamsOrderedCollectionPage() - itemsProp := streams.NewActivityStreamsOrderedItemsProperty() - buildCollectionPage(collectionPage, itemsProp, collectionPage.SetActivityStreamsOrderedItems, params) - return collectionPage -} - -func buildCollection[C CollectionBuilder](collection C, params CollectionParams, pageLimit int) { - // Add the collection ID property. - idProp := streams.NewJSONLDIdProperty() - idProp.SetIRI(params.ID) - collection.SetJSONLDId(idProp) - - // Add the collection totalItems count property. - totalItems := streams.NewActivityStreamsTotalItemsProperty() - totalItems.Set(params.Total) - collection.SetActivityStreamsTotalItems(totalItems) - - // Clone the collection ID page - // to add first page query data. - firstIRI := new(url.URL) - *firstIRI = *params.ID - - // Note that simply adding a limit signals to our - // endpoint to use paging (which will start at beginning). - limit := "limit=" + strconv.Itoa(pageLimit) - firstIRI.RawQuery = appendQuery(firstIRI.RawQuery, limit) - - // Add the collection first IRI property. - first := streams.NewActivityStreamsFirstProperty() - first.SetIRI(firstIRI) - collection.SetActivityStreamsFirst(first) -} - -func buildCollectionPage[C CollectionPageBuilder, I ItemsPropertyBuilder](collectionPage C, itemsProp I, setItems func(I), params CollectionPageParams) { - // Add the partOf property for its containing collection ID. - partOfProp := streams.NewActivityStreamsPartOfProperty() - partOfProp.SetIRI(params.ID) - collectionPage.SetActivityStreamsPartOf(partOfProp) - - // Build the current page link IRI. - currentIRI := params.Current.ToLinkURL( - params.ID.Scheme, - params.ID.Host, - params.ID.Path, - params.Query, - ) - - // Add the collection ID property for - // the *current* collection page params. - idProp := streams.NewJSONLDIdProperty() - idProp.SetIRI(currentIRI) - collectionPage.SetJSONLDId(idProp) - - // Build the next page link IRI. - nextIRI := params.Next.ToLinkURL( - params.ID.Scheme, - params.ID.Host, - params.ID.Path, - params.Query, - ) - - if nextIRI != nil { - // Add the collection next property for the next page. - nextProp := streams.NewActivityStreamsNextProperty() - nextProp.SetIRI(nextIRI) - collectionPage.SetActivityStreamsNext(nextProp) - } - - // Build the prev page link IRI. - prevIRI := params.Prev.ToLinkURL( - params.ID.Scheme, - params.ID.Host, - params.ID.Path, - params.Query, - ) - - if prevIRI != nil { - // Add the collection prev property for the prev page. - prevProp := streams.NewActivityStreamsPrevProperty() - prevProp.SetIRI(prevIRI) - collectionPage.SetActivityStreamsPrev(prevProp) - } - - // Add the collection totalItems count property. - totalItems := streams.NewActivityStreamsTotalItemsProperty() - totalItems.Set(params.Total) - collectionPage.SetActivityStreamsTotalItems(totalItems) - - if params.Append == nil { - // nil check outside the for loop. - panic("nil params.Append function") - } - - // Append each of the items to the provided - // pre-allocated items property builder type. - for i := 0; i < params.Count; i++ { - params.Append(i, itemsProp) - } - - // Set the collection - // page items property. - setItems(itemsProp) -} - -// appendQuery appends part to an existing raw -// query with ampersand, else just returning part. -func appendQuery(raw, part string) string { - if raw != "" { - return raw + "&" + part - } - return part -} |