summaryrefslogtreecommitdiff
path: root/internal/typeutils
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2023-05-09 12:16:10 +0200
committerLibravatar GitHub <noreply@github.com>2023-05-09 11:16:10 +0100
commit0e29f1f5bb68a48d9b837d7f4e0a16370734955b (patch)
treef08d203ec8ca8aeea728e5251b1dc3956524b4f4 /internal/typeutils
parent[chore/performance] Make sender multiplier configurable (#1750) (diff)
downloadgotosocial-0e29f1f5bb68a48d9b837d7f4e0a16370734955b.tar.xz
[feature] Enable federation in/out of profile PropertyValue fields (#1722)
Co-authored-by: kim <grufwub@gmail.com> Co-authored-by: kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>
Diffstat (limited to 'internal/typeutils')
-rw-r--r--internal/typeutils/astointernal.go3
-rw-r--r--internal/typeutils/internaltoas.go20
-rw-r--r--internal/typeutils/internaltoas_test.go139
-rw-r--r--internal/typeutils/internaltofrontend.go37
-rw-r--r--internal/typeutils/internaltofrontend_test.go39
-rw-r--r--internal/typeutils/wrap_test.go6
6 files changed, 202 insertions, 42 deletions
diff --git a/internal/typeutils/astointernal.go b/internal/typeutils/astointernal.go
index f94ac128a..7c0b60ad5 100644
--- a/internal/typeutils/astointernal.go
+++ b/internal/typeutils/astointernal.go
@@ -86,7 +86,8 @@ func (c *converter) ASRepresentationToAccount(ctx context.Context, accountable a
acct.Emojis = emojis
}
- // TODO: fields aka attachment array
+ // fields aka attachment array
+ acct.Fields = ap.ExtractFields(accountable)
// note aka summary
acct.Note = ap.ExtractSummary(accountable)
diff --git a/internal/typeutils/internaltoas.go b/internal/typeutils/internaltoas.go
index ceff1cb4d..3c1615cfb 100644
--- a/internal/typeutils/internaltoas.go
+++ b/internal/typeutils/internaltoas.go
@@ -240,7 +240,25 @@ func (c *converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
// attachment
// Used for profile fields.
- // TODO: The PropertyValue type has to be added: https://schema.org/PropertyValue
+ if len(a.Fields) != 0 {
+ attachmentProp := streams.NewActivityStreamsAttachmentProperty()
+
+ for _, field := range a.Fields {
+ propertyValue := streams.NewSchemaPropertyValue()
+
+ nameProp := streams.NewActivityStreamsNameProperty()
+ nameProp.AppendXMLSchemaString(field.Name)
+ propertyValue.SetActivityStreamsName(nameProp)
+
+ valueProp := streams.NewSchemaValueProperty()
+ valueProp.Set(field.Value)
+ propertyValue.SetSchemaValue(valueProp)
+
+ attachmentProp.AppendSchemaPropertyValue(propertyValue)
+ }
+
+ person.SetActivityStreamsAttachment(attachmentProp)
+ }
// endpoints
// NOT IMPLEMENTED -- this is for shared inbox which we don't use
diff --git a/internal/typeutils/internaltoas_test.go b/internal/typeutils/internaltoas_test.go
index 486866160..60c59326c 100644
--- a/internal/typeutils/internaltoas_test.go
+++ b/internal/typeutils/internaltoas_test.go
@@ -21,11 +21,11 @@ import (
"context"
"encoding/json"
"errors"
+ "fmt"
"strings"
"testing"
"github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
@@ -43,7 +43,7 @@ func (suite *InternalToASTestSuite) TestAccountToAS() {
asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount)
suite.NoError(err)
- ser, err := streams.Serialize(asPerson)
+ ser, err := ap.Serialize(asPerson)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -85,6 +85,107 @@ func (suite *InternalToASTestSuite) TestAccountToAS() {
}`, trimmed)
}
+func (suite *InternalToASTestSuite) TestAccountToASWithFields() {
+ testAccount := &gtsmodel.Account{}
+ *testAccount = *suite.testAccounts["local_account_2"]
+
+ asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount)
+ suite.NoError(err)
+
+ ser, err := ap.Serialize(asPerson)
+ suite.NoError(err)
+
+ bytes, err := json.MarshalIndent(ser, "", " ")
+ suite.NoError(err)
+
+ // trim off everything up to 'attachment';
+ // this is necessary because the order of multiple 'context' entries is not determinate
+ trimmed := strings.Split(string(bytes), "\"attachment\"")[1]
+
+ fmt.Printf("\n\n\n%s\n\n\n", string(bytes))
+
+ suite.Equal(`: [
+ {
+ "name": "should you follow me?",
+ "type": "PropertyValue",
+ "value": "maybe!"
+ },
+ {
+ "name": "age",
+ "type": "PropertyValue",
+ "value": "120"
+ }
+ ],
+ "discoverable": false,
+ "featured": "http://localhost:8080/users/1happyturtle/collections/featured",
+ "followers": "http://localhost:8080/users/1happyturtle/followers",
+ "following": "http://localhost:8080/users/1happyturtle/following",
+ "id": "http://localhost:8080/users/1happyturtle",
+ "inbox": "http://localhost:8080/users/1happyturtle/inbox",
+ "manuallyApprovesFollowers": true,
+ "name": "happy little turtle :3",
+ "outbox": "http://localhost:8080/users/1happyturtle/outbox",
+ "preferredUsername": "1happyturtle",
+ "publicKey": {
+ "id": "http://localhost:8080/users/1happyturtle#main-key",
+ "owner": "http://localhost:8080/users/1happyturtle",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtTc6Jpg6LrRPhVQG4KLz\n2+YqEUUtZPd4YR+TKXuCnwEG9ZNGhgP046xa9h3EWzrZXaOhXvkUQgJuRqPrAcfN\nvc8jBHV2xrUeD8pu/MWKEabAsA/tgCv3nUC47HQ3/c12aHfYoPz3ufWsGGnrkhci\nv8PaveJ3LohO5vjCn1yZ00v6osMJMViEZvZQaazyE9A8FwraIexXabDpoy7tkHRg\nA1fvSkg4FeSG1XMcIz2NN7xyUuFACD+XkuOk7UqzRd4cjPUPLxiDwIsTlcgGOd3E\nUFMWVlPxSGjY2hIKa3lEHytaYK9IMYdSuyCsJshd3/yYC9LqxZY2KdlKJ80VOVyh\nyQIDAQAB\n-----END PUBLIC KEY-----\n"
+ },
+ "summary": "\u003cp\u003ei post about things that concern me\u003c/p\u003e",
+ "tag": [],
+ "type": "Person",
+ "url": "http://localhost:8080/@1happyturtle"
+}`, trimmed)
+}
+
+func (suite *InternalToASTestSuite) TestAccountToASWithOneField() {
+ testAccount := &gtsmodel.Account{}
+ *testAccount = *suite.testAccounts["local_account_2"]
+ testAccount.Fields = testAccount.Fields[0:1] // Take only one field.
+
+ asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount)
+ suite.NoError(err)
+
+ ser, err := ap.Serialize(asPerson)
+ suite.NoError(err)
+
+ bytes, err := json.MarshalIndent(ser, "", " ")
+ suite.NoError(err)
+
+ // trim off everything up to 'attachment';
+ // this is necessary because the order of multiple 'context' entries is not determinate
+ trimmed := strings.Split(string(bytes), "\"attachment\"")[1]
+
+ // Despite only one field being set, attachments should still be a slice/array.
+ suite.Equal(`: [
+ {
+ "name": "should you follow me?",
+ "type": "PropertyValue",
+ "value": "maybe!"
+ }
+ ],
+ "discoverable": false,
+ "featured": "http://localhost:8080/users/1happyturtle/collections/featured",
+ "followers": "http://localhost:8080/users/1happyturtle/followers",
+ "following": "http://localhost:8080/users/1happyturtle/following",
+ "id": "http://localhost:8080/users/1happyturtle",
+ "inbox": "http://localhost:8080/users/1happyturtle/inbox",
+ "manuallyApprovesFollowers": true,
+ "name": "happy little turtle :3",
+ "outbox": "http://localhost:8080/users/1happyturtle/outbox",
+ "preferredUsername": "1happyturtle",
+ "publicKey": {
+ "id": "http://localhost:8080/users/1happyturtle#main-key",
+ "owner": "http://localhost:8080/users/1happyturtle",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtTc6Jpg6LrRPhVQG4KLz\n2+YqEUUtZPd4YR+TKXuCnwEG9ZNGhgP046xa9h3EWzrZXaOhXvkUQgJuRqPrAcfN\nvc8jBHV2xrUeD8pu/MWKEabAsA/tgCv3nUC47HQ3/c12aHfYoPz3ufWsGGnrkhci\nv8PaveJ3LohO5vjCn1yZ00v6osMJMViEZvZQaazyE9A8FwraIexXabDpoy7tkHRg\nA1fvSkg4FeSG1XMcIz2NN7xyUuFACD+XkuOk7UqzRd4cjPUPLxiDwIsTlcgGOd3E\nUFMWVlPxSGjY2hIKa3lEHytaYK9IMYdSuyCsJshd3/yYC9LqxZY2KdlKJ80VOVyh\nyQIDAQAB\n-----END PUBLIC KEY-----\n"
+ },
+ "summary": "\u003cp\u003ei post about things that concern me\u003c/p\u003e",
+ "tag": [],
+ "type": "Person",
+ "url": "http://localhost:8080/@1happyturtle"
+}`, trimmed)
+}
+
func (suite *InternalToASTestSuite) TestAccountToASWithEmoji() {
testAccount := &gtsmodel.Account{}
*testAccount = *suite.testAccounts["local_account_1"] // take zork for this test
@@ -93,7 +194,7 @@ func (suite *InternalToASTestSuite) TestAccountToASWithEmoji() {
asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount)
suite.NoError(err)
- ser, err := streams.Serialize(asPerson)
+ ser, err := ap.Serialize(asPerson)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -154,7 +255,7 @@ func (suite *InternalToASTestSuite) TestAccountToASWithSharedInbox() {
asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount)
suite.NoError(err)
- ser, err := streams.Serialize(asPerson)
+ ser, err := ap.Serialize(asPerson)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -206,7 +307,7 @@ func (suite *InternalToASTestSuite) TestOutboxToASCollection() {
collection, err := suite.typeconverter.OutboxToASCollection(ctx, testAccount.OutboxURI)
suite.NoError(err)
- ser, err := streams.Serialize(collection)
+ ser, err := ap.Serialize(collection)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -227,7 +328,7 @@ func (suite *InternalToASTestSuite) TestStatusToAS() {
asStatus, err := suite.typeconverter.StatusToAS(ctx, testStatus)
suite.NoError(err)
- ser, err := streams.Serialize(asStatus)
+ ser, err := ap.Serialize(asStatus)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -268,7 +369,7 @@ func (suite *InternalToASTestSuite) TestStatusWithTagsToASWithIDs() {
asStatus, err := suite.typeconverter.StatusToAS(ctx, testStatus)
suite.NoError(err)
- ser, err := streams.Serialize(asStatus)
+ ser, err := ap.Serialize(asStatus)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -328,7 +429,7 @@ func (suite *InternalToASTestSuite) TestStatusWithTagsToASFromDB() {
asStatus, err := suite.typeconverter.StatusToAS(ctx, testStatus)
suite.NoError(err)
- ser, err := streams.Serialize(asStatus)
+ ser, err := ap.Serialize(asStatus)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -389,7 +490,7 @@ func (suite *InternalToASTestSuite) TestStatusToASWithMentions() {
asStatus, err := suite.typeconverter.StatusToAS(ctx, testStatus)
suite.NoError(err)
- ser, err := streams.Serialize(asStatus)
+ ser, err := ap.Serialize(asStatus)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -437,7 +538,7 @@ func (suite *InternalToASTestSuite) TestStatusToASDeletePublicReply() {
asDelete, err := suite.typeconverter.StatusToASDelete(ctx, testStatus)
suite.NoError(err)
- ser, err := streams.Serialize(asDelete)
+ ser, err := ap.Serialize(asDelete)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -475,7 +576,7 @@ func (suite *InternalToASTestSuite) TestStatusToASDeletePublicReplyOriginalDelet
asDelete, err := suite.typeconverter.StatusToASDelete(ctx, testStatus)
suite.NoError(err)
- ser, err := streams.Serialize(asDelete)
+ ser, err := ap.Serialize(asDelete)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -501,7 +602,7 @@ func (suite *InternalToASTestSuite) TestStatusToASDeletePublic() {
asDelete, err := suite.typeconverter.StatusToASDelete(ctx, testStatus)
suite.NoError(err)
- ser, err := streams.Serialize(asDelete)
+ ser, err := ap.Serialize(asDelete)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -524,7 +625,7 @@ func (suite *InternalToASTestSuite) TestStatusToASDeleteDirectMessage() {
asDelete, err := suite.typeconverter.StatusToASDelete(ctx, testStatus)
suite.NoError(err)
- ser, err := streams.Serialize(asDelete)
+ ser, err := ap.Serialize(asDelete)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -551,7 +652,7 @@ func (suite *InternalToASTestSuite) TestStatusesToASOutboxPage() {
page, err := suite.typeconverter.StatusesToASOutboxPage(ctx, testAccount.OutboxURI, "", "", statuses)
suite.NoError(err)
- ser, err := streams.Serialize(page)
+ ser, err := ap.Serialize(page)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -604,7 +705,7 @@ func (suite *InternalToASTestSuite) TestSelfBoostFollowersOnlyToAS() {
asBoost, err := suite.typeconverter.BoostToAS(ctx, boostWrapperStatus, testAccount, testAccount)
suite.NoError(err)
- ser, err := streams.Serialize(asBoost)
+ ser, err := ap.Serialize(asBoost)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -637,7 +738,7 @@ func (suite *InternalToASTestSuite) TestReportToAS() {
flag, err := suite.typeconverter.ReportToASFlag(ctx, testReport)
suite.NoError(err)
- ser, err := streams.Serialize(flag)
+ ser, err := ap.Serialize(flag)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -670,7 +771,7 @@ func (suite *InternalToASTestSuite) TestPinnedStatusesToASSomeItems() {
suite.FailNow(err.Error())
}
- ser, err := ap.SerializeOrderedCollection(collection)
+ ser, err := ap.Serialize(collection)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -702,7 +803,7 @@ func (suite *InternalToASTestSuite) TestPinnedStatusesToASNoItems() {
suite.FailNow(err.Error())
}
- ser, err := ap.SerializeOrderedCollection(collection)
+ ser, err := ap.Serialize(collection)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
@@ -731,7 +832,7 @@ func (suite *InternalToASTestSuite) TestPinnedStatusesToASOneItem() {
suite.FailNow(err.Error())
}
- ser, err := ap.SerializeOrderedCollection(collection)
+ ser, err := ap.Serialize(collection)
suite.NoError(err)
bytes, err := json.MarshalIndent(ser, "", " ")
diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go
index 88646c311..1e5fb024f 100644
--- a/internal/typeutils/internaltofrontend.go
+++ b/internal/typeutils/internaltofrontend.go
@@ -77,7 +77,7 @@ func (c *converter) AccountToAPIAccountSensitive(ctx context.Context, a *gtsmode
Language: a.Language,
StatusContentType: statusContentType,
Note: a.NoteRaw,
- Fields: apiAccount.Fields,
+ Fields: c.fieldsToAPIFields(a.FieldsRaw),
FollowRequestsCount: frc,
}
@@ -131,7 +131,6 @@ func (c *converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
aviURLStatic string
headerURL string
headerURLStatic string
- fields = make([]apimodel.Field, len(a.Fields))
)
if a.AvatarMediaAttachment != nil {
@@ -144,19 +143,8 @@ func (c *converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
headerURLStatic = a.HeaderMediaAttachment.Thumbnail.URL
}
- // GTS model fields -> frontend.
- for i, field := range a.Fields {
- mField := apimodel.Field{
- Name: field.Name,
- Value: field.Value,
- }
-
- if !field.VerifiedAt.IsZero() {
- mField.VerifiedAt = util.FormatISO8601(field.VerifiedAt)
- }
-
- fields[i] = mField
- }
+ // convert account gts model fields to front api model fields
+ fields := c.fieldsToAPIFields(a.Fields)
// GTS model emojis -> frontend.
apiEmojis, err := c.convertEmojisToAPIEmojis(ctx, a.Emojis, a.EmojiIDs)
@@ -239,6 +227,25 @@ func (c *converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
return accountFrontend, nil
}
+func (c *converter) fieldsToAPIFields(f []*gtsmodel.Field) []apimodel.Field {
+ fields := make([]apimodel.Field, len(f))
+
+ for i, field := range f {
+ mField := apimodel.Field{
+ Name: field.Name,
+ Value: field.Value,
+ }
+
+ if !field.VerifiedAt.IsZero() {
+ mField.VerifiedAt = func() *string { s := util.FormatISO8601(field.VerifiedAt); return &s }()
+ }
+
+ fields[i] = mField
+ }
+
+ return fields
+}
+
func (c *converter) AccountToAPIAccountBlocked(ctx context.Context, a *gtsmodel.Account) (*apimodel.Account, error) {
var (
acct string
diff --git a/internal/typeutils/internaltofrontend_test.go b/internal/typeutils/internaltofrontend_test.go
index c8ab5a8e1..558d3acea 100644
--- a/internal/typeutils/internaltofrontend_test.go
+++ b/internal/typeutils/internaltofrontend_test.go
@@ -873,7 +873,18 @@ func (suite *InternalToFrontendTestSuite) TestReportToFrontend2() {
"statuses_count": 7,
"last_status_at": "2021-10-20T10:40:37.000Z",
"emojis": [],
- "fields": [],
+ "fields": [
+ {
+ "name": "should you follow me?",
+ "value": "maybe!",
+ "verified_at": null
+ },
+ {
+ "name": "age",
+ "value": "120",
+ "verified_at": null
+ }
+ ],
"role": {
"name": "user"
}
@@ -977,7 +988,18 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend1() {
"statuses_count": 7,
"last_status_at": "2021-10-20T10:40:37.000Z",
"emojis": [],
- "fields": [],
+ "fields": [
+ {
+ "name": "should you follow me?",
+ "value": "maybe!",
+ "verified_at": null
+ },
+ {
+ "name": "age",
+ "value": "120",
+ "verified_at": null
+ }
+ ],
"role": {
"name": "user"
}
@@ -1137,7 +1159,18 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend2() {
"statuses_count": 7,
"last_status_at": "2021-10-20T10:40:37.000Z",
"emojis": [],
- "fields": [],
+ "fields": [
+ {
+ "name": "should you follow me?",
+ "value": "maybe!",
+ "verified_at": null
+ },
+ {
+ "name": "age",
+ "value": "120",
+ "verified_at": null
+ }
+ ],
"role": {
"name": "user"
}
diff --git a/internal/typeutils/wrap_test.go b/internal/typeutils/wrap_test.go
index 2978a0251..46d28f5c4 100644
--- a/internal/typeutils/wrap_test.go
+++ b/internal/typeutils/wrap_test.go
@@ -23,7 +23,7 @@ import (
"testing"
"github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/activity/streams"
+ "github.com/superseriousbusiness/gotosocial/internal/ap"
)
type WrapTestSuite struct {
@@ -40,7 +40,7 @@ func (suite *WrapTestSuite) TestWrapNoteInCreateIRIOnly() {
suite.NoError(err)
suite.NotNil(create)
- createI, err := streams.Serialize(create)
+ createI, err := ap.Serialize(create)
suite.NoError(err)
bytes, err := json.MarshalIndent(createI, "", " ")
@@ -68,7 +68,7 @@ func (suite *WrapTestSuite) TestWrapNoteInCreate() {
suite.NoError(err)
suite.NotNil(create)
- createI, err := streams.Serialize(create)
+ createI, err := ap.Serialize(create)
suite.NoError(err)
bytes, err := json.MarshalIndent(createI, "", " ")