mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-12-01 16:12:45 +00:00
[feature] Federate custom emoji (outbound) (#791)
* Federate local custom emoji * Add test for converting a status with tags to AP
This commit is contained in:
parent
077e66381f
commit
bf9d146987
|
@ -144,6 +144,8 @@ type TypeConverter interface {
|
||||||
FollowToAS(ctx context.Context, f *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) (vocab.ActivityStreamsFollow, error)
|
FollowToAS(ctx context.Context, f *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) (vocab.ActivityStreamsFollow, error)
|
||||||
// MentionToAS converts a gts model mention into an activity streams Mention, suitable for federation
|
// MentionToAS converts a gts model mention into an activity streams Mention, suitable for federation
|
||||||
MentionToAS(ctx context.Context, m *gtsmodel.Mention) (vocab.ActivityStreamsMention, error)
|
MentionToAS(ctx context.Context, m *gtsmodel.Mention) (vocab.ActivityStreamsMention, error)
|
||||||
|
// EmojiToAS converts a gts emoji into a mastodon ns Emoji, suitable for federation
|
||||||
|
EmojiToAS(ctx context.Context, e *gtsmodel.Emoji) (vocab.TootEmoji, error)
|
||||||
// AttachmentToAS converts a gts model media attachment into an activity streams Attachment, suitable for federation
|
// AttachmentToAS converts a gts model media attachment into an activity streams Attachment, suitable for federation
|
||||||
AttachmentToAS(ctx context.Context, a *gtsmodel.MediaAttachment) (vocab.ActivityStreamsDocument, error)
|
AttachmentToAS(ctx context.Context, a *gtsmodel.MediaAttachment) (vocab.ActivityStreamsDocument, error)
|
||||||
// FaveToAS converts a gts model status fave into an activityStreams LIKE, suitable for federation.
|
// FaveToAS converts a gts model status fave into an activityStreams LIKE, suitable for federation.
|
||||||
|
|
|
@ -439,7 +439,13 @@ func (c *converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (vocab.A
|
||||||
}
|
}
|
||||||
|
|
||||||
// tag -- emojis
|
// tag -- emojis
|
||||||
// TODO
|
for _, emoji := range s.Emojis {
|
||||||
|
asMention, err := c.EmojiToAS(ctx, emoji)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("StatusToAS: error converting emoji to AS emoji: %s", err)
|
||||||
|
}
|
||||||
|
tagProp.AppendTootEmoji(asMention)
|
||||||
|
}
|
||||||
|
|
||||||
// tag -- hashtags
|
// tag -- hashtags
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -632,6 +638,58 @@ func (c *converter) MentionToAS(ctx context.Context, m *gtsmodel.Mention) (vocab
|
||||||
return mention, nil
|
return mention, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
we're making something like this:
|
||||||
|
{
|
||||||
|
"id": "https://example.com/emoji/123",
|
||||||
|
"type": "Emoji",
|
||||||
|
"name": ":kappa:",
|
||||||
|
"icon": {
|
||||||
|
"type": "Image",
|
||||||
|
"mediaType": "image/png",
|
||||||
|
"url": "https://example.com/files/kappa.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
func (c *converter) EmojiToAS(ctx context.Context, e *gtsmodel.Emoji) (vocab.TootEmoji, error) {
|
||||||
|
// create the emoji
|
||||||
|
emoji := streams.NewTootEmoji()
|
||||||
|
|
||||||
|
// set the ID property to the blocks's URI
|
||||||
|
idProp := streams.NewJSONLDIdProperty()
|
||||||
|
idIRI, err := url.Parse(e.URI)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("EmojiToAS: error parsing uri %s: %s", e.URI, err)
|
||||||
|
}
|
||||||
|
idProp.Set(idIRI)
|
||||||
|
emoji.SetJSONLDId(idProp)
|
||||||
|
|
||||||
|
nameProp := streams.NewActivityStreamsNameProperty()
|
||||||
|
nameString := fmt.Sprintf(":%s:", e.Shortcode)
|
||||||
|
nameProp.AppendXMLSchemaString(nameString)
|
||||||
|
emoji.SetActivityStreamsName(nameProp)
|
||||||
|
|
||||||
|
iconProperty := streams.NewActivityStreamsIconProperty()
|
||||||
|
iconImage := streams.NewActivityStreamsImage()
|
||||||
|
|
||||||
|
mediaType := streams.NewActivityStreamsMediaTypeProperty()
|
||||||
|
mediaType.Set(e.ImageContentType)
|
||||||
|
iconImage.SetActivityStreamsMediaType(mediaType)
|
||||||
|
|
||||||
|
emojiURLProperty := streams.NewActivityStreamsUrlProperty()
|
||||||
|
emojiURL, err := url.Parse(e.ImageURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("EmojiToAS: error parsing url %s: %s", e.ImageURL, err)
|
||||||
|
}
|
||||||
|
emojiURLProperty.AppendIRI(emojiURL)
|
||||||
|
iconImage.SetActivityStreamsUrl(emojiURLProperty)
|
||||||
|
|
||||||
|
iconProperty.AppendActivityStreamsImage(iconImage)
|
||||||
|
emoji.SetActivityStreamsIcon(iconProperty)
|
||||||
|
|
||||||
|
return emoji, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *converter) AttachmentToAS(ctx context.Context, a *gtsmodel.MediaAttachment) (vocab.ActivityStreamsDocument, error) {
|
func (c *converter) AttachmentToAS(ctx context.Context, a *gtsmodel.MediaAttachment) (vocab.ActivityStreamsDocument, error) {
|
||||||
// type -- Document
|
// type -- Document
|
||||||
doc := streams.NewActivityStreamsDocument()
|
doc := streams.NewActivityStreamsDocument()
|
||||||
|
@ -667,15 +725,15 @@ func (c *converter) AttachmentToAS(ctx context.Context, a *gtsmodel.MediaAttachm
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We want to end up with something like this:
|
We want to end up with something like this:
|
||||||
|
|
||||||
{
|
{
|
||||||
"@context": "https://www.w3.org/ns/activitystreams",
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
"actor": "https://ondergrond.org/users/dumpsterqueer",
|
"actor": "https://ondergrond.org/users/dumpsterqueer",
|
||||||
"id": "https://ondergrond.org/users/dumpsterqueer#likes/44584",
|
"id": "https://ondergrond.org/users/dumpsterqueer#likes/44584",
|
||||||
"object": "https://testingtesting123.xyz/users/gotosocial_test_account/statuses/771aea80-a33d-4d6d-8dfd-57d4d2bfcbd4",
|
"object": "https://testingtesting123.xyz/users/gotosocial_test_account/statuses/771aea80-a33d-4d6d-8dfd-57d4d2bfcbd4",
|
||||||
"type": "Like"
|
"type": "Like"
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
func (c *converter) FaveToAS(ctx context.Context, f *gtsmodel.StatusFave) (vocab.ActivityStreamsLike, error) {
|
func (c *converter) FaveToAS(ctx context.Context, f *gtsmodel.StatusFave) (vocab.ActivityStreamsLike, error) {
|
||||||
// check if targetStatus is already pinned to this fave, and fetch it if not
|
// check if targetStatus is already pinned to this fave, and fetch it if not
|
||||||
|
@ -825,7 +883,7 @@ func (c *converter) BoostToAS(ctx context.Context, boostWrapperStatus *gtsmodel.
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
we want to end up with something like this:
|
we want to end up with something like this:
|
||||||
|
|
||||||
{
|
{
|
||||||
"@context": "https://www.w3.org/ns/activitystreams",
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
@ -895,7 +953,7 @@ func (c *converter) BlockToAS(ctx context.Context, b *gtsmodel.Block) (vocab.Act
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
the goal is to end up with something like this:
|
the goal is to end up with something like this:
|
||||||
|
|
||||||
{
|
{
|
||||||
"@context": "https://www.w3.org/ns/activitystreams",
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
@ -960,7 +1018,8 @@ func (c *converter) StatusToASRepliesCollection(ctx context.Context, status *gts
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
the goal is to end up with something like this:
|
the goal is to end up with something like this:
|
||||||
|
|
||||||
{
|
{
|
||||||
"@context": "https://www.w3.org/ns/activitystreams",
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
"id": "https://example.org/users/whatever/statuses/01FCNEXAGAKPEX1J7VJRPJP490/replies?only_other_accounts=true&page=true",
|
"id": "https://example.org/users/whatever/statuses/01FCNEXAGAKPEX1J7VJRPJP490/replies?only_other_accounts=true&page=true",
|
||||||
|
@ -1030,7 +1089,8 @@ func (c *converter) StatusURIsToASRepliesPage(ctx context.Context, status *gtsmo
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
the goal is to end up with something like this:
|
the goal is to end up with something like this:
|
||||||
|
|
||||||
{
|
{
|
||||||
"id": "https://example.org/users/whatever/outbox?page=true",
|
"id": "https://example.org/users/whatever/outbox?page=true",
|
||||||
"type": "OrderedCollectionPage",
|
"type": "OrderedCollectionPage",
|
||||||
|
@ -1134,7 +1194,7 @@ func (c *converter) StatusesToASOutboxPage(ctx context.Context, outboxID string,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
we want something that looks like this:
|
we want something that looks like this:
|
||||||
|
|
||||||
{
|
{
|
||||||
"@context": "https://www.w3.org/ns/activitystreams",
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
|
|
@ -94,6 +94,25 @@ func (suite *InternalToASTestSuite) TestStatusToAS() {
|
||||||
suite.Equal(`{"@context":"https://www.w3.org/ns/activitystreams","attachment":[],"attributedTo":"http://localhost:8080/users/the_mighty_zork","cc":"http://localhost:8080/users/the_mighty_zork/followers","content":"hello everyone!","id":"http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY","published":"2021-10-20T12:40:37+02:00","replies":{"first":{"id":"http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/replies?page=true","next":"http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/replies?only_other_accounts=false\u0026page=true","partOf":"http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/replies","type":"CollectionPage"},"id":"http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/replies","type":"Collection"},"sensitive":true,"summary":"introduction post","tag":[],"to":"https://www.w3.org/ns/activitystreams#Public","type":"Note","url":"http://localhost:8080/@the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY"}`, string(bytes))
|
suite.Equal(`{"@context":"https://www.w3.org/ns/activitystreams","attachment":[],"attributedTo":"http://localhost:8080/users/the_mighty_zork","cc":"http://localhost:8080/users/the_mighty_zork/followers","content":"hello everyone!","id":"http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY","published":"2021-10-20T12:40:37+02:00","replies":{"first":{"id":"http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/replies?page=true","next":"http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/replies?only_other_accounts=false\u0026page=true","partOf":"http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/replies","type":"CollectionPage"},"id":"http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/replies","type":"Collection"},"sensitive":true,"summary":"introduction post","tag":[],"to":"https://www.w3.org/ns/activitystreams#Public","type":"Note","url":"http://localhost:8080/@the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY"}`, string(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (suite *InternalToASTestSuite) TestStatusWithTagsToAS() {
|
||||||
|
ctx := context.Background()
|
||||||
|
//get the entire status with all tags
|
||||||
|
testStatus, err := suite.db.GetStatusByID(ctx, suite.testStatuses["admin_account_status_1"].ID)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
asStatus, err := suite.typeconverter.StatusToAS(ctx, testStatus)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
ser, err := streams.Serialize(asStatus)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
bytes, err := json.Marshal(ser)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
suite.Equal(`{"@context":["https://www.w3.org/ns/activitystreams","http://joinmastodon.org/ns"],"attachment":{"blurhash":"LNJRdVM{00Rj%Mayt7j[4nWBofRj","mediaType":"image/jpeg","name":"Black and white image of some 50's style text saying: Welcome On Board","type":"Document","url":"http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpeg"},"attributedTo":"http://localhost:8080/users/admin","cc":"http://localhost:8080/users/admin/followers","content":"hello world! #welcome ! first post on the instance :rainbow: !","id":"http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R","published":"2021-10-20T11:36:45Z","replies":{"first":{"id":"http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R/replies?page=true","next":"http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R/replies?only_other_accounts=false\u0026page=true","partOf":"http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R/replies","type":"CollectionPage"},"id":"http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R/replies","type":"Collection"},"sensitive":false,"summary":"","tag":{"icon":{"mediaType":"image/png","type":"Image","url":"http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png"},"id":"http://localhost:8080/emoji/01F8MH9H8E4VG3KDYJR9EGPXCQ","name":":rainbow:","type":"Emoji"},"to":"https://www.w3.org/ns/activitystreams#Public","type":"Note","url":"http://localhost:8080/@admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R"}`, string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *InternalToASTestSuite) TestStatusToASWithMentions() {
|
func (suite *InternalToASTestSuite) TestStatusToASWithMentions() {
|
||||||
testStatusID := suite.testStatuses["admin_account_status_3"].ID
|
testStatusID := suite.testStatuses["admin_account_status_3"].ID
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
Loading…
Reference in a new issue