diff options
author | 2023-03-01 18:52:44 +0100 | |
---|---|---|
committer | 2023-03-01 17:52:44 +0000 | |
commit | 24cec4e7aab33b6c44ba6d1ecf16895f254351b8 (patch) | |
tree | cf0107a34e0fa00ab1b68aed4b52afe502147393 /internal/typeutils | |
parent | [chore/performance] simplify storage driver to use storage.Storage directly (... (diff) | |
download | gotosocial-24cec4e7aab33b6c44ba6d1ecf16895f254351b8.tar.xz |
[feature] Federate pinned posts (aka `featuredCollection`) in and out (#1560)
* start fiddling
* the ol' fiddle + update
* start working on fetching statuses
* poopy doopy doo where r u uwu
* further adventures in featuring statuses
* finishing up
* fmt
* simply status unpin loop
* move empty featured check back to caller function
* remove unnecessary log.WithContext calls
* remove unnecessary IsIRI() checks
* add explanatory comment about status URIs
* change log level to error
* better test names
Diffstat (limited to 'internal/typeutils')
-rw-r--r-- | internal/typeutils/astointernal.go | 11 | ||||
-rw-r--r-- | internal/typeutils/converter.go | 3 | ||||
-rw-r--r-- | internal/typeutils/internaltoas.go | 28 | ||||
-rw-r--r-- | internal/typeutils/internaltoas_test.go | 92 |
4 files changed, 131 insertions, 3 deletions
diff --git a/internal/typeutils/astointernal.go b/internal/typeutils/astointernal.go index 11633ad4e..4e1b59613 100644 --- a/internal/typeutils/astointernal.go +++ b/internal/typeutils/astointernal.go @@ -181,9 +181,14 @@ func (c *converter) ASRepresentationToAccount(ctx context.Context, accountable a acct.FollowersURI = accountable.GetActivityStreamsFollowers().GetIRI().String() } - // FeaturedURI - if accountable.GetTootFeatured() != nil && accountable.GetTootFeatured().GetIRI() != nil { - acct.FeaturedCollectionURI = accountable.GetTootFeatured().GetIRI().String() + // FeaturedURI aka pinned collection: + // Only trust featured URI if it has at least two domains, + // from the right, in common with the domain of the account + if featured := accountable.GetTootFeatured(); featured != nil && featured.IsIRI() { + if featuredURI := featured.GetIRI(); // nocollapse + featuredURI != nil && dns.CompareDomainName(acct.Domain, featuredURI.Host) >= 2 { + acct.FeaturedCollectionURI = featuredURI.String() + } } // TODO: FeaturedTagsURI diff --git a/internal/typeutils/converter.go b/internal/typeutils/converter.go index c63bd8d8c..ec0c1bb8c 100644 --- a/internal/typeutils/converter.go +++ b/internal/typeutils/converter.go @@ -178,6 +178,9 @@ type TypeConverter interface { // // Appropriate 'next' and 'prev' fields will be created based on the highest and lowest IDs present in the statuses slice. StatusesToASOutboxPage(ctx context.Context, outboxID string, maxID string, minID string, statuses []*gtsmodel.Status) (vocab.ActivityStreamsOrderedCollectionPage, error) + // StatusesToASFeaturedCollection converts a slice of statuses into an ordered collection + // of URIs, suitable for serializing and serving via the activitypub API. + StatusesToASFeaturedCollection(ctx context.Context, featuredCollectionID string, statuses []*gtsmodel.Status) (vocab.ActivityStreamsOrderedCollection, error) // ReportToASFlag converts a gts model report into an activitystreams FLAG, suitable for federation. ReportToASFlag(ctx context.Context, r *gtsmodel.Report) (vocab.ActivityStreamsFlag, error) diff --git a/internal/typeutils/internaltoas.go b/internal/typeutils/internaltoas.go index 06b49c18f..bbcf6c84b 100644 --- a/internal/typeutils/internaltoas.go +++ b/internal/typeutils/internaltoas.go @@ -1296,6 +1296,34 @@ func (c *converter) OutboxToASCollection(ctx context.Context, outboxID string) ( return collection, nil } +func (c *converter) StatusesToASFeaturedCollection(ctx context.Context, featuredCollectionID string, statuses []*gtsmodel.Status) (vocab.ActivityStreamsOrderedCollection, error) { + collection := streams.NewActivityStreamsOrderedCollection() + + collectionIDProp := streams.NewJSONLDIdProperty() + featuredCollectionIDURI, err := url.Parse(featuredCollectionID) + if err != nil { + return nil, fmt.Errorf("error parsing url %s", featuredCollectionID) + } + collectionIDProp.SetIRI(featuredCollectionIDURI) + collection.SetJSONLDId(collectionIDProp) + + itemsProp := streams.NewActivityStreamsOrderedItemsProperty() + for _, s := range statuses { + uri, err := url.Parse(s.URI) + if err != nil { + return nil, fmt.Errorf("error parsing url %s", s.URI) + } + itemsProp.AppendIRI(uri) + } + collection.SetActivityStreamsOrderedItems(itemsProp) + + totalItemsProp := streams.NewActivityStreamsTotalItemsProperty() + totalItemsProp.Set(len(statuses)) + collection.SetActivityStreamsTotalItems(totalItemsProp) + + return collection, nil +} + func (c *converter) ReportToASFlag(ctx context.Context, r *gtsmodel.Report) (vocab.ActivityStreamsFlag, error) { flag := streams.NewActivityStreamsFlag() diff --git a/internal/typeutils/internaltoas_test.go b/internal/typeutils/internaltoas_test.go index 2ea393db3..887d78884 100644 --- a/internal/typeutils/internaltoas_test.go +++ b/internal/typeutils/internaltoas_test.go @@ -21,11 +21,13 @@ package typeutils_test import ( "context" "encoding/json" + "errors" "strings" "testing" "github.com/stretchr/testify/suite" "github.com/superseriousbusiness/activity/streams" + "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/testrig" ) @@ -544,6 +546,96 @@ func (suite *InternalToASTestSuite) TestReportToAS() { }`, string(bytes)) } +func (suite *InternalToASTestSuite) TestPinnedStatusesToASSomeItems() { + ctx := context.Background() + + testAccount := suite.testAccounts["admin_account"] + statuses, err := suite.db.GetAccountPinnedStatuses(ctx, testAccount.ID) + if err != nil { + suite.FailNow(err.Error()) + } + + collection, err := suite.typeconverter.StatusesToASFeaturedCollection(ctx, testAccount.FeaturedCollectionURI, statuses) + if err != nil { + suite.FailNow(err.Error()) + } + + ser, err := streams.Serialize(collection) + suite.NoError(err) + + bytes, err := json.MarshalIndent(ser, "", " ") + suite.NoError(err) + + suite.Equal(`{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "http://localhost:8080/users/admin/collections/featured", + "orderedItems": [ + "http://localhost:8080/users/admin/statuses/01F8MHAAY43M6RJ473VQFCVH37", + "http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R" + ], + "totalItems": 2, + "type": "OrderedCollection" +}`, string(bytes)) +} + +func (suite *InternalToASTestSuite) TestPinnedStatusesToASNoItems() { + ctx := context.Background() + + testAccount := suite.testAccounts["local_account_1"] + statuses, err := suite.db.GetAccountPinnedStatuses(ctx, testAccount.ID) + if err != nil && !errors.Is(err, db.ErrNoEntries) { + suite.FailNow(err.Error()) + } + + collection, err := suite.typeconverter.StatusesToASFeaturedCollection(ctx, testAccount.FeaturedCollectionURI, statuses) + if err != nil { + suite.FailNow(err.Error()) + } + + ser, err := streams.Serialize(collection) + suite.NoError(err) + + bytes, err := json.MarshalIndent(ser, "", " ") + suite.NoError(err) + + suite.Equal(`{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "http://localhost:8080/users/the_mighty_zork/collections/featured", + "orderedItems": [], + "totalItems": 0, + "type": "OrderedCollection" +}`, string(bytes)) +} + +func (suite *InternalToASTestSuite) TestPinnedStatusesToASOneItem() { + ctx := context.Background() + + testAccount := suite.testAccounts["local_account_2"] + statuses, err := suite.db.GetAccountPinnedStatuses(ctx, testAccount.ID) + if err != nil { + suite.FailNow(err.Error()) + } + + collection, err := suite.typeconverter.StatusesToASFeaturedCollection(ctx, testAccount.FeaturedCollectionURI, statuses) + if err != nil { + suite.FailNow(err.Error()) + } + + ser, err := streams.Serialize(collection) + suite.NoError(err) + + bytes, err := json.MarshalIndent(ser, "", " ") + suite.NoError(err) + + suite.Equal(`{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "http://localhost:8080/users/1happyturtle/collections/featured", + "orderedItems": "http://localhost:8080/users/1happyturtle/statuses/01G20ZM733MGN8J344T4ZDDFY1", + "totalItems": 1, + "type": "OrderedCollection" +}`, string(bytes)) +} + func TestInternalToASTestSuite(t *testing.T) { suite.Run(t, new(InternalToASTestSuite)) } |