mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-27 03:41:02 +00:00
GNU social compatibility (#2100)
* Use SourceCompat everywhere (better compat with other software) * Name field should not be mandatory in Group * also check page.cc field for community id * add gnu social tests * better to use option<sourcecompat> * update gnu social tests, marked vote as "unlisted"
This commit is contained in:
parent
1e9f609cdb
commit
dfb0938738
29 changed files with 409 additions and 116 deletions
53
crates/apub/assets/gnusocial/activities/create_note.json
Normal file
53
crates/apub/assets/gnusocial/activities/create_note.json
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
{
|
||||||
|
"type": "Create",
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"gs": "https://www.gnu.org/software/social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"litepub": "http://litepub.social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chatMessage": "litepub:chatMessage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inConversation": {
|
||||||
|
"@id": "gs:inConversation",
|
||||||
|
"@type": "@id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://instance.gnusocial.test/activity/1339",
|
||||||
|
"published": "2022-03-01T20:58:48+00:00",
|
||||||
|
"actor": "https://instance.gnusocial.test/actor/42",
|
||||||
|
"object": {
|
||||||
|
"type": "Note",
|
||||||
|
"id": "https://instance.gnusocial.test/object/note/1339",
|
||||||
|
"published": "2022-03-01T21:00:16+00:00",
|
||||||
|
"attributedTo": "https://instance.gnusocial.test/actor/42",
|
||||||
|
"content": "<p>yay ^^</p>",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"source": {
|
||||||
|
"content": "yay ^^",
|
||||||
|
"mediaType": "text/plain"
|
||||||
|
},
|
||||||
|
"attachment": [],
|
||||||
|
"tag": [],
|
||||||
|
"inReplyTo": "https://instance.gnusocial.test/object/note/1338",
|
||||||
|
"inConversation": "https://instance.gnusocial.test/conversation/1338",
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
],
|
||||||
|
"cc": [
|
||||||
|
"https://instance.gnusocial.test/actor/42/subscribers"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
],
|
||||||
|
"cc": [
|
||||||
|
"https://instance.gnusocial.test/actor/42/subscribers"
|
||||||
|
]
|
||||||
|
}
|
53
crates/apub/assets/gnusocial/activities/create_page.json
Normal file
53
crates/apub/assets/gnusocial/activities/create_page.json
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
{
|
||||||
|
"type": "Create",
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"gs": "https://www.gnu.org/software/social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"litepub": "http://litepub.social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chatMessage": "litepub:chatMessage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inConversation": {
|
||||||
|
"@id": "gs:inConversation",
|
||||||
|
"@type": "@id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://instance.gnusocial.test/activity/1338",
|
||||||
|
"published": "2022-03-17T23:30:26+00:00",
|
||||||
|
"actor": "https://instance.gnusocial.test/actor/42",
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
],
|
||||||
|
"cc": [
|
||||||
|
"https://instance.gnusocial.test/actor/21"
|
||||||
|
],
|
||||||
|
"object": {
|
||||||
|
"type": "Page",
|
||||||
|
"id": "https://instance.gnusocial.test/object/note/1338",
|
||||||
|
"published": "2022-03-17T23:30:26+00:00",
|
||||||
|
"attributedTo": "https://instance.gnusocial.test/actor/42",
|
||||||
|
"name": "hello, world.",
|
||||||
|
"content": "<p>This is an interesting page.</p>",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"source": {
|
||||||
|
"content": "This is an interesting page.",
|
||||||
|
"mediaType": "text/markdown"
|
||||||
|
},
|
||||||
|
"attachment": [],
|
||||||
|
"tag": [],
|
||||||
|
"inConversation": "https://instance.gnusocial.test/conversation/1338",
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
],
|
||||||
|
"cc": [
|
||||||
|
"https://instance.gnusocial.test/actor/21"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
16
crates/apub/assets/gnusocial/activities/like_note.json
Normal file
16
crates/apub/assets/gnusocial/activities/like_note.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"type": "Like",
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams"
|
||||||
|
],
|
||||||
|
"id": "https://another_instance.gnusocial.test/activity/41362",
|
||||||
|
"published": "2022-03-20T17:54:15+00:00",
|
||||||
|
"actor": "https://another_instance.gnusocial.test/actor/43",
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
],
|
||||||
|
"cc": [
|
||||||
|
"https://instance.gnusocial.test/actor/42"
|
||||||
|
],
|
||||||
|
"object": "https://instance.gnusocial.test/object/note/1337"
|
||||||
|
}
|
42
crates/apub/assets/gnusocial/objects/group.json
Normal file
42
crates/apub/assets/gnusocial/objects/group.json
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"type": "Group",
|
||||||
|
"streams": [],
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"gs": "https://www.gnu.org/software/social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"litepub": "http://litepub.social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chatMessage": "litepub:chatMessage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inConversation": {
|
||||||
|
"@id": "gs:inConversation",
|
||||||
|
"@type": "@id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://instance.gnusocial.test/actor/21",
|
||||||
|
"inbox": "https://instance.gnusocial.test/actor/21/inbox.json",
|
||||||
|
"outbox": "https://instance.gnusocial.test/actor/21/outbox.json",
|
||||||
|
"following": "https://instance.gnusocial.test/actor/21/subscriptions",
|
||||||
|
"followers": "https://instance.gnusocial.test/actor/21/subscribers",
|
||||||
|
"liked": "https://instance.gnusocial.test/actor/21/favourites",
|
||||||
|
"preferredUsername": "hackers",
|
||||||
|
"publicKey": {
|
||||||
|
"id": "https://instance.gnusocial.test/actor/2#public-key",
|
||||||
|
"owner": "https://instance.gnusocial.test/actor/2",
|
||||||
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoZyKL+GyJbTV/ilVBlzz\n8OL/UwNi3KpfV5kQwXU0pPcBbw6y2JOfWnKUT1CfiHG3ntiOFnc+wQfHZk4hRSE8\n9Xe/G5Y215xW+gqx/kjt2GOENqzSzYXdEZ5Qsx6yumZD/yb6VZK9Og0HjX2mpRs9\nbactY76w4BQVntjZ17gSkMhYcyPFZTAIe7QDkeSPk5lkXfTwtaB3YcJSbQ3+s7La\npeEgukQDkrLUIP6cxayKrgUl4fhHdpx1Yk4Bzd/1XkZCjeBca94lP1p2M12amI+Z\nOLSTuLyEiCcku8aN+Ms9plwATmIDaGvKFVk0YVtBHdIJlYXV0yIscab3bqyhsLBK\njwIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||||
|
},
|
||||||
|
"name": "Hackers!",
|
||||||
|
"published": "2022-02-23T21:54:52+00:00",
|
||||||
|
"updated": "2022-02-23T21:55:16+00:00",
|
||||||
|
"url": "https://instance.gnusocial.test/!hackers",
|
||||||
|
"endpoints": {
|
||||||
|
"sharedInbox": "https://instance.gnusocial.test/inbox.json"
|
||||||
|
}
|
||||||
|
}
|
44
crates/apub/assets/gnusocial/objects/note.json
Normal file
44
crates/apub/assets/gnusocial/objects/note.json
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
{
|
||||||
|
"type": "Note",
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"gs": "https://www.gnu.org/software/social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"litepub": "http://litepub.social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chatMessage": "litepub:chatMessage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inConversation": {
|
||||||
|
"@id": "gs:inConversation",
|
||||||
|
"@type": "@id"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@language": "en"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://instance.gnusocial.test/object/note/1339",
|
||||||
|
"published": "2022-03-01T21:00:16+00:00",
|
||||||
|
"attributedTo": "https://instance.gnusocial.test/actor/42",
|
||||||
|
"content": "<p>yay ^^</p>",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"source": {
|
||||||
|
"content": "yay ^^",
|
||||||
|
"mediaType": "text/plain"
|
||||||
|
},
|
||||||
|
"attachment": [],
|
||||||
|
"tag": [],
|
||||||
|
"inReplyTo": "https://instance.gnusocial.test/object/note/1338",
|
||||||
|
"inConversation": "https://instance.gnusocial.test/conversation/1338",
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
],
|
||||||
|
"cc": [
|
||||||
|
"https://instance.gnusocial.test/actor/42/subscribers"
|
||||||
|
]
|
||||||
|
}
|
41
crates/apub/assets/gnusocial/objects/page.json
Normal file
41
crates/apub/assets/gnusocial/objects/page.json
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"type": "Page",
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"gs": "https://www.gnu.org/software/social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"litepub": "http://litepub.social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chatMessage": "litepub:chatMessage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inConversation": {
|
||||||
|
"@id": "gs:inConversation",
|
||||||
|
"@type": "@id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://instance.gnusocial.test/object/note/1338",
|
||||||
|
"published": "2022-03-17T23:30:26+00:00",
|
||||||
|
"attributedTo": "https://instance.gnusocial.test/actor/42",
|
||||||
|
"name": "hello, world.",
|
||||||
|
"content": "<p>This is an interesting page.</p>",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"source": {
|
||||||
|
"content": "This is an interesting page.",
|
||||||
|
"mediaType": "text/markdown"
|
||||||
|
},
|
||||||
|
"attachment": [],
|
||||||
|
"tag": [],
|
||||||
|
"inConversation": "https://instance.gnusocial.test/conversation/1338",
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
],
|
||||||
|
"cc": [
|
||||||
|
"https://instance.gnusocial.test/actor/21"
|
||||||
|
]
|
||||||
|
}
|
42
crates/apub/assets/gnusocial/objects/person.json
Normal file
42
crates/apub/assets/gnusocial/objects/person.json
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"type": "Person",
|
||||||
|
"streams": [],
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"gs": "https://www.gnu.org/software/social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"litepub": "http://litepub.social/ns#"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chatMessage": "litepub:chatMessage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inConversation": {
|
||||||
|
"@id": "gs:inConversation",
|
||||||
|
"@type": "@id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://instance.gnusocial.test/actor/42",
|
||||||
|
"inbox": "https://instance.gnusocial.test/actor/42/inbox.json",
|
||||||
|
"outbox": "https://instance.gnusocial.test/actor/42/outbox.json",
|
||||||
|
"following": "https://instance.gnusocial.test/actor/42/subscriptions",
|
||||||
|
"followers": "https://instance.gnusocial.test/actor/42/subscribers",
|
||||||
|
"liked": "https://instance.gnusocial.test/actor/42/favourites",
|
||||||
|
"preferredUsername": "diogo",
|
||||||
|
"publicKey": {
|
||||||
|
"id": "https://instance.gnusocial.test/actor/42#public-key",
|
||||||
|
"owner": "https://instance.gnusocial.test/actor/42",
|
||||||
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBB+3ldwA2qC1hQTtIho\n9KYhvvMlPdydn8dA6OlyIQ3Jy57ADt2e144jDSY5RQ3esmzWm2QqsI8rAsZsAraO\nl2+855y7Fw35WH4GBc7PJ6MLAEvMk1YWeS/rttXaDzh2i4n/AXkMuxDjS1IBqw2w\nn0qTz2sdGcBJ+mop6AB9Qt2lseBc5IW040jSnfLEDDIaYgoc5m2yRsjGKItOh3BG\njGHDb6JB9FySToSMGIt0/tE5k06wfvAxtkxX5dfGeKtciBpC2MGT169iyMIOM8DN\nFhSl8mowtV1NJQ7nN692USrmNvSJjqe9ugPCDPPvwQ5A6A61Qrgpz5pav/o5Sz69\nzQIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||||
|
},
|
||||||
|
"name": "Diogo Peralta Cordeiro",
|
||||||
|
"published": "2022-02-23T17:20:30+00:00",
|
||||||
|
"updated": "2022-02-25T02:12:48+00:00",
|
||||||
|
"url": "https://instance.gnusocial.test/@diogo",
|
||||||
|
"endpoints": {
|
||||||
|
"sharedInbox": "https://instance.gnusocial.test/inbox.json"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
"actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
|
"actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
|
||||||
"to": [
|
"to": [
|
||||||
"https://www.w3.org/ns/activitystreams#Public"
|
"http://enterprise.lemmy.ml/c/main"
|
||||||
],
|
],
|
||||||
"object": "http://ds9.lemmy.ml/post/1",
|
"object": "http://ds9.lemmy.ml/post/1",
|
||||||
"cc": [
|
"cc": [
|
||||||
"http://enterprise.lemmy.ml/c/main"
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
],
|
],
|
||||||
"type": "Dislike",
|
"type": "Dislike",
|
||||||
"id": "http://enterprise.lemmy.ml/activities/dislike/64d40d40-a829-43a5-8247-1fb595b3ca1c"
|
"id": "http://enterprise.lemmy.ml/activities/dislike/64d40d40-a829-43a5-8247-1fb595b3ca1c"
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
"actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
|
"actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
|
||||||
"to": [
|
"to": [
|
||||||
"https://www.w3.org/ns/activitystreams#Public"
|
"http://enterprise.lemmy.ml/c/main"
|
||||||
],
|
],
|
||||||
"object": "http://ds9.lemmy.ml/comment/1",
|
"object": "http://ds9.lemmy.ml/comment/1",
|
||||||
"cc": [
|
"cc": [
|
||||||
"http://enterprise.lemmy.ml/c/main"
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
],
|
],
|
||||||
"type": "Like",
|
"type": "Like",
|
||||||
"id": "http://ds9.lemmy.ml/activities/like/fd61d070-7382-46a9-b2b7-6bb253732877"
|
"id": "http://ds9.lemmy.ml/activities/like/fd61d070-7382-46a9-b2b7-6bb253732877"
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
{
|
{
|
||||||
"actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
|
"actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
|
||||||
"to": [
|
"to": [
|
||||||
"https://www.w3.org/ns/activitystreams#Public"
|
"http://enterprise.lemmy.ml/c/main"
|
||||||
],
|
],
|
||||||
"object": {
|
"object": {
|
||||||
"actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
|
"actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
|
||||||
"to": [
|
"to": [
|
||||||
"https://www.w3.org/ns/activitystreams#Public"
|
"http://enterprise.lemmy.ml/c/main"
|
||||||
],
|
],
|
||||||
"object": "http://ds9.lemmy.ml/post/1",
|
"object": "http://ds9.lemmy.ml/post/1",
|
||||||
"cc": [
|
"cc": [
|
||||||
"http://enterprise.lemmy.ml/c/main"
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
],
|
],
|
||||||
"type": "Like",
|
"type": "Like",
|
||||||
"id": "http://enterprise.lemmy.ml/activities/like/2227ab2c-79e2-4fca-a1d2-1d67dacf2457"
|
"id": "http://enterprise.lemmy.ml/activities/like/2227ab2c-79e2-4fca-a1d2-1d67dacf2457"
|
||||||
},
|
},
|
||||||
"cc": [
|
"cc": [
|
||||||
"http://enterprise.lemmy.ml/c/main"
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
],
|
],
|
||||||
"type": "Undo",
|
"type": "Undo",
|
||||||
"id": "http://enterprise.lemmy.ml/activities/undo/6cc6fb71-39fe-49ea-9506-f0423b101e98"
|
"id": "http://enterprise.lemmy.ml/activities/undo/6cc6fb71-39fe-49ea-9506-f0423b101e98"
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
{
|
{
|
||||||
"actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
|
"actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
|
||||||
"to": [
|
"to": [
|
||||||
"https://www.w3.org/ns/activitystreams#Public"
|
"http://enterprise.lemmy.ml/c/main"
|
||||||
],
|
],
|
||||||
"object": {
|
"object": {
|
||||||
"actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
|
"actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
|
||||||
"to": [
|
"to": [
|
||||||
"https://www.w3.org/ns/activitystreams#Public"
|
"http://enterprise.lemmy.ml/c/main"
|
||||||
],
|
],
|
||||||
"object": "http://ds9.lemmy.ml/comment/1",
|
"object": "http://ds9.lemmy.ml/comment/1",
|
||||||
"cc": [
|
"cc": [
|
||||||
"http://enterprise.lemmy.ml/c/main"
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
],
|
],
|
||||||
"type": "Like",
|
"type": "Like",
|
||||||
"id": "http://ds9.lemmy.ml/activities/like/efcf7ae2-dfcc-4ff4-9ce4-6adf251ff004"
|
"id": "http://ds9.lemmy.ml/activities/like/efcf7ae2-dfcc-4ff4-9ce4-6adf251ff004"
|
||||||
},
|
},
|
||||||
"cc": [
|
"cc": [
|
||||||
"http://enterprise.lemmy.ml/c/main"
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
],
|
],
|
||||||
"type": "Undo",
|
"type": "Undo",
|
||||||
"id": "http://ds9.lemmy.ml/activities/undo/3518565c-24a7-4d9e-8e0a-f7a2f45ac618"
|
"id": "http://ds9.lemmy.ml/activities/undo/3518565c-24a7-4d9e-8e0a-f7a2f45ac618"
|
||||||
|
|
|
@ -28,6 +28,9 @@ use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
|
|
||||||
impl UndoVote {
|
impl UndoVote {
|
||||||
|
/// UndoVote has as:Public value in cc field, unlike other activities. This indicates to other
|
||||||
|
/// software (like GNU social, or presumably Mastodon), that the like actor should not be
|
||||||
|
/// disclosed.
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn send(
|
pub async fn send(
|
||||||
object: &PostOrComment,
|
object: &PostOrComment,
|
||||||
|
@ -49,9 +52,9 @@ impl UndoVote {
|
||||||
)?;
|
)?;
|
||||||
let undo_vote = UndoVote {
|
let undo_vote = UndoVote {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: vec![public()],
|
to: vec![community.actor_id()],
|
||||||
object,
|
object,
|
||||||
cc: vec![community.actor_id()],
|
cc: vec![public()],
|
||||||
kind: UndoType::Undo,
|
kind: UndoType::Undo,
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
unparsed: Default::default(),
|
unparsed: Default::default(),
|
||||||
|
|
|
@ -28,6 +28,8 @@ use lemmy_db_schema::{
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
|
|
||||||
|
/// Vote has as:Public value in cc field, unlike other activities. This indicates to other software
|
||||||
|
/// (like GNU social, or presumably Mastodon), that the like actor should not be disclosed.
|
||||||
impl Vote {
|
impl Vote {
|
||||||
pub(in crate::activities::voting) fn new(
|
pub(in crate::activities::voting) fn new(
|
||||||
object: &PostOrComment,
|
object: &PostOrComment,
|
||||||
|
@ -38,9 +40,9 @@ impl Vote {
|
||||||
) -> Result<Vote, LemmyError> {
|
) -> Result<Vote, LemmyError> {
|
||||||
Ok(Vote {
|
Ok(Vote {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: vec![public()],
|
to: vec![community.actor_id()],
|
||||||
object: ObjectId::new(object.ap_id()),
|
object: ObjectId::new(object.ap_id()),
|
||||||
cc: vec![community.actor_id()],
|
cc: vec![public()],
|
||||||
kind: kind.clone(),
|
kind: kind.clone(),
|
||||||
id: generate_activity_id(kind, &context.settings().get_protocol_and_hostname())?,
|
id: generate_activity_id(kind, &context.settings().get_protocol_and_hostname())?,
|
||||||
unparsed: Default::default(),
|
unparsed: Default::default(),
|
||||||
|
|
|
@ -2,18 +2,15 @@ use crate::{
|
||||||
activities::{verify_is_public, verify_person_in_community},
|
activities::{verify_is_public, verify_person_in_community},
|
||||||
check_is_apub_id_valid,
|
check_is_apub_id_valid,
|
||||||
mentions::collect_non_local_mentions,
|
mentions::collect_non_local_mentions,
|
||||||
|
objects::read_from_string_or_source,
|
||||||
protocol::{
|
protocol::{
|
||||||
objects::{
|
objects::{note::Note, tombstone::Tombstone},
|
||||||
note::{Note, SourceCompat},
|
SourceCompat,
|
||||||
tombstone::Tombstone,
|
|
||||||
},
|
|
||||||
Source,
|
|
||||||
},
|
},
|
||||||
PostOrComment,
|
PostOrComment,
|
||||||
};
|
};
|
||||||
use activitystreams_kinds::{object::NoteType, public};
|
use activitystreams_kinds::{object::NoteType, public};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use html2md::parse_html;
|
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
object_id::ObjectId,
|
object_id::ObjectId,
|
||||||
|
@ -121,7 +118,7 @@ impl ApubObject for ApubComment {
|
||||||
cc: maa.ccs,
|
cc: maa.ccs,
|
||||||
content: markdown_to_html(&self.content),
|
content: markdown_to_html(&self.content),
|
||||||
media_type: Some(MediaTypeHtml::Html),
|
media_type: Some(MediaTypeHtml::Html),
|
||||||
source: SourceCompat::Lemmy(Source::new(self.content.clone())),
|
source: Some(SourceCompat::new(self.content.clone())),
|
||||||
in_reply_to,
|
in_reply_to,
|
||||||
published: Some(convert_datetime(self.published)),
|
published: Some(convert_datetime(self.published)),
|
||||||
updated: self.updated.map(convert_datetime),
|
updated: self.updated.map(convert_datetime),
|
||||||
|
@ -180,11 +177,7 @@ impl ApubObject for ApubComment {
|
||||||
.await?;
|
.await?;
|
||||||
let (post, parent_comment_id) = note.get_parents(context, request_counter).await?;
|
let (post, parent_comment_id) = note.get_parents(context, request_counter).await?;
|
||||||
|
|
||||||
let content = if let SourceCompat::Lemmy(source) = ¬e.source {
|
let content = read_from_string_or_source(¬e.content, ¬e.source);
|
||||||
source.content.clone()
|
|
||||||
} else {
|
|
||||||
parse_html(¬e.content)
|
|
||||||
};
|
|
||||||
let content_slurs_removed = remove_slurs(&content, &context.settings().slur_regex());
|
let content_slurs_removed = remove_slurs(&content, &context.settings().slur_regex());
|
||||||
|
|
||||||
let form = CommentForm {
|
let form = CommentForm {
|
||||||
|
@ -219,6 +212,7 @@ pub(crate) mod tests {
|
||||||
protocol::tests::file_to_json_object,
|
protocol::tests::file_to_json_object,
|
||||||
};
|
};
|
||||||
use assert_json_diff::assert_json_include;
|
use assert_json_diff::assert_json_include;
|
||||||
|
use html2md::parse_html;
|
||||||
use lemmy_db_schema::source::site::Site;
|
use lemmy_db_schema::source::site::Site;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
protocol::{
|
protocol::{
|
||||||
objects::{group::Group, tombstone::Tombstone, Endpoints},
|
objects::{group::Group, tombstone::Tombstone, Endpoints},
|
||||||
ImageObject,
|
ImageObject,
|
||||||
Source,
|
SourceCompat,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use activitystreams_kinds::actor::GroupType;
|
use activitystreams_kinds::actor::GroupType;
|
||||||
|
@ -85,9 +85,9 @@ impl ApubObject for ApubCommunity {
|
||||||
kind: GroupType::Group,
|
kind: GroupType::Group,
|
||||||
id: ObjectId::new(self.actor_id()),
|
id: ObjectId::new(self.actor_id()),
|
||||||
preferred_username: self.name.clone(),
|
preferred_username: self.name.clone(),
|
||||||
name: self.title.clone(),
|
name: Some(self.title.clone()),
|
||||||
summary: self.description.as_ref().map(|b| markdown_to_html(b)),
|
summary: self.description.as_ref().map(|b| markdown_to_html(b)),
|
||||||
source: self.description.clone().map(Source::new),
|
source: self.description.clone().map(SourceCompat::new),
|
||||||
icon: self.icon.clone().map(ImageObject::new),
|
icon: self.icon.clone().map(ImageObject::new),
|
||||||
image: self.banner.clone().map(ImageObject::new),
|
image: self.banner.clone().map(ImageObject::new),
|
||||||
sensitive: Some(self.nsfw),
|
sensitive: Some(self.nsfw),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
check_is_apub_id_valid,
|
check_is_apub_id_valid,
|
||||||
objects::{get_summary_from_string_or_source, verify_image_domain_matches},
|
objects::{read_from_string_or_source_opt, verify_image_domain_matches},
|
||||||
protocol::{objects::instance::Instance, ImageObject, Source},
|
protocol::{objects::instance::Instance, ImageObject, SourceCompat},
|
||||||
};
|
};
|
||||||
use activitystreams_kinds::actor::ServiceType;
|
use activitystreams_kinds::actor::ServiceType;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
|
@ -77,7 +77,7 @@ impl ApubObject for ApubSite {
|
||||||
id: ObjectId::new(self.actor_id()),
|
id: ObjectId::new(self.actor_id()),
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
content: self.sidebar.as_ref().map(|d| markdown_to_html(d)),
|
content: self.sidebar.as_ref().map(|d| markdown_to_html(d)),
|
||||||
source: self.sidebar.clone().map(Source::new),
|
source: self.sidebar.clone().map(SourceCompat::new),
|
||||||
summary: self.description.clone(),
|
summary: self.description.clone(),
|
||||||
media_type: self.sidebar.as_ref().map(|_| MediaTypeHtml::Html),
|
media_type: self.sidebar.as_ref().map(|_| MediaTypeHtml::Html),
|
||||||
icon: self.icon.clone().map(ImageObject::new),
|
icon: self.icon.clone().map(ImageObject::new),
|
||||||
|
@ -121,10 +121,7 @@ impl ApubObject for ApubSite {
|
||||||
) -> Result<Self, LemmyError> {
|
) -> Result<Self, LemmyError> {
|
||||||
let site_form = SiteForm {
|
let site_form = SiteForm {
|
||||||
name: apub.name.clone(),
|
name: apub.name.clone(),
|
||||||
sidebar: Some(get_summary_from_string_or_source(
|
sidebar: Some(read_from_string_or_source_opt(&apub.content, &apub.source)),
|
||||||
&apub.content,
|
|
||||||
&apub.source,
|
|
||||||
)),
|
|
||||||
updated: apub.updated.map(|u| u.clone().naive_local()),
|
updated: apub.updated.map(|u| u.clone().naive_local()),
|
||||||
icon: Some(apub.icon.clone().map(|i| i.url.into())),
|
icon: Some(apub.icon.clone().map(|i| i.url.into())),
|
||||||
banner: Some(apub.image.clone().map(|i| i.url.into())),
|
banner: Some(apub.image.clone().map(|i| i.url.into())),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::protocol::{ImageObject, Source};
|
use crate::protocol::{ImageObject, SourceCompat};
|
||||||
use html2md::parse_html;
|
use html2md::parse_html;
|
||||||
use lemmy_apub_lib::verify::verify_domains_match;
|
use lemmy_apub_lib::verify::verify_domains_match;
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
|
@ -11,12 +11,20 @@ pub mod person;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
pub mod private_message;
|
pub mod private_message;
|
||||||
|
|
||||||
pub(crate) fn get_summary_from_string_or_source(
|
pub(crate) fn read_from_string_or_source(raw: &str, source: &Option<SourceCompat>) -> String {
|
||||||
|
if let Some(SourceCompat::Lemmy(s)) = source {
|
||||||
|
s.content.clone()
|
||||||
|
} else {
|
||||||
|
parse_html(raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_from_string_or_source_opt(
|
||||||
raw: &Option<String>,
|
raw: &Option<String>,
|
||||||
source: &Option<Source>,
|
source: &Option<SourceCompat>,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
if let Some(source) = &source {
|
if let Some(SourceCompat::Lemmy(s2)) = source {
|
||||||
Some(source.content.clone())
|
Some(s2.content.clone())
|
||||||
} else {
|
} else {
|
||||||
raw.as_ref().map(|s| parse_html(s))
|
raw.as_ref().map(|s| parse_html(s))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ use crate::{
|
||||||
check_is_apub_id_valid,
|
check_is_apub_id_valid,
|
||||||
generate_outbox_url,
|
generate_outbox_url,
|
||||||
objects::{
|
objects::{
|
||||||
get_summary_from_string_or_source,
|
|
||||||
instance::fetch_instance_actor_for_object,
|
instance::fetch_instance_actor_for_object,
|
||||||
|
read_from_string_or_source_opt,
|
||||||
verify_image_domain_matches,
|
verify_image_domain_matches,
|
||||||
},
|
},
|
||||||
protocol::{
|
protocol::{
|
||||||
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
Endpoints,
|
Endpoints,
|
||||||
},
|
},
|
||||||
ImageObject,
|
ImageObject,
|
||||||
Source,
|
SourceCompat,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
|
@ -99,7 +99,7 @@ impl ApubObject for ApubPerson {
|
||||||
preferred_username: self.name.clone(),
|
preferred_username: self.name.clone(),
|
||||||
name: self.display_name.clone(),
|
name: self.display_name.clone(),
|
||||||
summary: self.bio.as_ref().map(|b| markdown_to_html(b)),
|
summary: self.bio.as_ref().map(|b| markdown_to_html(b)),
|
||||||
source: self.bio.clone().map(Source::new),
|
source: self.bio.clone().map(SourceCompat::new),
|
||||||
icon: self.avatar.clone().map(ImageObject::new),
|
icon: self.avatar.clone().map(ImageObject::new),
|
||||||
image: self.banner.clone().map(ImageObject::new),
|
image: self.banner.clone().map(ImageObject::new),
|
||||||
matrix_user_id: self.matrix_user_id.clone(),
|
matrix_user_id: self.matrix_user_id.clone(),
|
||||||
|
@ -134,7 +134,7 @@ impl ApubObject for ApubPerson {
|
||||||
let slur_regex = &context.settings().slur_regex();
|
let slur_regex = &context.settings().slur_regex();
|
||||||
check_slurs(&person.preferred_username, slur_regex)?;
|
check_slurs(&person.preferred_username, slur_regex)?;
|
||||||
check_slurs_opt(&person.name, slur_regex)?;
|
check_slurs_opt(&person.name, slur_regex)?;
|
||||||
let bio = get_summary_from_string_or_source(&person.summary, &person.source);
|
let bio = read_from_string_or_source_opt(&person.summary, &person.source);
|
||||||
check_slurs_opt(&bio, slur_regex)?;
|
check_slurs_opt(&bio, slur_regex)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ impl ApubObject for ApubPerson {
|
||||||
published: person.published.map(|u| u.naive_local()),
|
published: person.published.map(|u| u.naive_local()),
|
||||||
updated: person.updated.map(|u| u.naive_local()),
|
updated: person.updated.map(|u| u.naive_local()),
|
||||||
actor_id: Some(person.id.into()),
|
actor_id: Some(person.id.into()),
|
||||||
bio: Some(get_summary_from_string_or_source(
|
bio: Some(read_from_string_or_source_opt(
|
||||||
&person.summary,
|
&person.summary,
|
||||||
&person.source,
|
&person.source,
|
||||||
)),
|
)),
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{verify_is_public, verify_person_in_community},
|
activities::{verify_is_public, verify_person_in_community},
|
||||||
check_is_apub_id_valid,
|
check_is_apub_id_valid,
|
||||||
|
objects::read_from_string_or_source_opt,
|
||||||
protocol::{
|
protocol::{
|
||||||
objects::{
|
objects::{
|
||||||
page::{Page, PageType},
|
page::{Page, PageType},
|
||||||
tombstone::Tombstone,
|
tombstone::Tombstone,
|
||||||
},
|
},
|
||||||
ImageObject,
|
ImageObject,
|
||||||
Source,
|
SourceCompat,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use activitystreams_kinds::public;
|
use activitystreams_kinds::public;
|
||||||
|
@ -16,7 +17,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
object_id::ObjectId,
|
object_id::ObjectId,
|
||||||
traits::ApubObject,
|
traits::ApubObject,
|
||||||
values::{MediaTypeHtml, MediaTypeMarkdown},
|
values::MediaTypeHtml,
|
||||||
verify::verify_domains_match,
|
verify::verify_domains_match,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -100,12 +101,6 @@ impl ApubObject for ApubPost {
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
let source = self.body.clone().map(|body| Source {
|
|
||||||
content: body,
|
|
||||||
media_type: MediaTypeMarkdown::Markdown,
|
|
||||||
});
|
|
||||||
let image = self.thumbnail_url.clone().map(ImageObject::new);
|
|
||||||
|
|
||||||
let page = Page {
|
let page = Page {
|
||||||
r#type: PageType::Page,
|
r#type: PageType::Page,
|
||||||
id: ObjectId::new(self.ap_id.clone()),
|
id: ObjectId::new(self.ap_id.clone()),
|
||||||
|
@ -115,9 +110,9 @@ impl ApubObject for ApubPost {
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
content: self.body.as_ref().map(|b| markdown_to_html(b)),
|
content: self.body.as_ref().map(|b| markdown_to_html(b)),
|
||||||
media_type: Some(MediaTypeHtml::Html),
|
media_type: Some(MediaTypeHtml::Html),
|
||||||
source,
|
source: self.body.clone().map(SourceCompat::new),
|
||||||
url: self.url.clone().map(|u| u.into()),
|
url: self.url.clone().map(|u| u.into()),
|
||||||
image,
|
image: self.thumbnail_url.clone().map(ImageObject::new),
|
||||||
comments_enabled: Some(!self.locked),
|
comments_enabled: Some(!self.locked),
|
||||||
sensitive: Some(self.nsfw),
|
sensitive: Some(self.nsfw),
|
||||||
stickied: Some(self.stickied),
|
stickied: Some(self.stickied),
|
||||||
|
@ -175,10 +170,8 @@ impl ApubObject for ApubPost {
|
||||||
.map(|u| (u.title, u.description, u.html))
|
.map(|u| (u.title, u.description, u.html))
|
||||||
.unwrap_or((None, None, None));
|
.unwrap_or((None, None, None));
|
||||||
|
|
||||||
let body_slurs_removed = page
|
let body_slurs_removed = read_from_string_or_source_opt(&page.content, &page.source)
|
||||||
.source
|
.map(|s| remove_slurs(&s, &context.settings().slur_regex()));
|
||||||
.as_ref()
|
|
||||||
.map(|s| remove_slurs(&s.content, &context.settings().slur_regex()));
|
|
||||||
let form = PostForm {
|
let form = PostForm {
|
||||||
name: page.name,
|
name: page.name,
|
||||||
url: page.url.map(|u| u.into()),
|
url: page.url.map(|u| u.into()),
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
use crate::protocol::{
|
use crate::{
|
||||||
objects::chat_message::{ChatMessage, ChatMessageType},
|
objects::read_from_string_or_source,
|
||||||
Source,
|
protocol::{
|
||||||
|
objects::chat_message::{ChatMessage, ChatMessageType},
|
||||||
|
SourceCompat,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use html2md::parse_html;
|
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
object_id::ObjectId,
|
object_id::ObjectId,
|
||||||
|
@ -88,7 +90,7 @@ impl ApubObject for ApubPrivateMessage {
|
||||||
to: [ObjectId::new(recipient.actor_id)],
|
to: [ObjectId::new(recipient.actor_id)],
|
||||||
content: markdown_to_html(&self.content),
|
content: markdown_to_html(&self.content),
|
||||||
media_type: Some(MediaTypeHtml::Html),
|
media_type: Some(MediaTypeHtml::Html),
|
||||||
source: Some(Source::new(self.content.clone())),
|
source: Some(SourceCompat::new(self.content.clone())),
|
||||||
published: Some(convert_datetime(self.published)),
|
published: Some(convert_datetime(self.published)),
|
||||||
updated: self.updated.map(convert_datetime),
|
updated: self.updated.map(convert_datetime),
|
||||||
};
|
};
|
||||||
|
@ -131,16 +133,11 @@ impl ApubObject for ApubPrivateMessage {
|
||||||
let recipient = note.to[0]
|
let recipient = note.to[0]
|
||||||
.dereference(context, context.client(), request_counter)
|
.dereference(context, context.client(), request_counter)
|
||||||
.await?;
|
.await?;
|
||||||
let content = if let Some(source) = ¬e.source {
|
|
||||||
source.content.clone()
|
|
||||||
} else {
|
|
||||||
parse_html(¬e.content)
|
|
||||||
};
|
|
||||||
|
|
||||||
let form = PrivateMessageForm {
|
let form = PrivateMessageForm {
|
||||||
creator_id: creator.id,
|
creator_id: creator.id,
|
||||||
recipient_id: recipient.id,
|
recipient_id: recipient.id,
|
||||||
content,
|
content: read_from_string_or_source(¬e.content, ¬e.source),
|
||||||
published: note.published.map(|u| u.naive_local()),
|
published: note.published.map(|u| u.naive_local()),
|
||||||
updated: note.updated.map(|u| u.naive_local()),
|
updated: note.updated.map(|u| u.naive_local()),
|
||||||
deleted: None,
|
deleted: None,
|
||||||
|
|
|
@ -21,6 +21,7 @@ mod tests {
|
||||||
create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost},
|
create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost},
|
||||||
deletion::delete::Delete,
|
deletion::delete::Delete,
|
||||||
following::{follow::FollowCommunity, undo_follow::UndoFollowCommunity},
|
following::{follow::FollowCommunity, undo_follow::UndoFollowCommunity},
|
||||||
|
voting::vote::Vote,
|
||||||
},
|
},
|
||||||
tests::test_json,
|
tests::test_json,
|
||||||
};
|
};
|
||||||
|
@ -55,4 +56,11 @@ mod tests {
|
||||||
fn test_parse_friendica_activities() {
|
fn test_parse_friendica_activities() {
|
||||||
test_json::<CreateOrUpdateComment>("assets/friendica/activities/create_note.json").unwrap();
|
test_json::<CreateOrUpdateComment>("assets/friendica/activities/create_note.json").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_gnusocial_activities() {
|
||||||
|
test_json::<CreateOrUpdatePost>("assets/gnusocial/activities/create_page.json").unwrap();
|
||||||
|
test_json::<CreateOrUpdateComment>("assets/gnusocial/activities/create_note.json").unwrap();
|
||||||
|
test_json::<Vote>("assets/gnusocial/activities/like_note.json").unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use url::Url;
|
||||||
|
|
||||||
use lemmy_apub_lib::values::MediaTypeMarkdown;
|
use lemmy_apub_lib::values::MediaTypeMarkdown;
|
||||||
use lemmy_db_schema::newtypes::DbUrl;
|
use lemmy_db_schema::newtypes::DbUrl;
|
||||||
|
use serde_json::Value;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub mod activities;
|
pub mod activities;
|
||||||
|
@ -17,12 +18,20 @@ pub struct Source {
|
||||||
pub(crate) media_type: MediaTypeMarkdown,
|
pub(crate) media_type: MediaTypeMarkdown,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Source {
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub(crate) enum SourceCompat {
|
||||||
|
Lemmy(Source),
|
||||||
|
Other(Value),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SourceCompat {
|
||||||
pub(crate) fn new(content: String) -> Self {
|
pub(crate) fn new(content: String) -> Self {
|
||||||
Source {
|
SourceCompat::Lemmy(Source {
|
||||||
content,
|
content,
|
||||||
media_type: MediaTypeMarkdown::Markdown,
|
media_type: MediaTypeMarkdown::Markdown,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{person::ApubPerson, private_message::ApubPrivateMessage},
|
objects::{person::ApubPerson, private_message::ApubPrivateMessage},
|
||||||
protocol::Source,
|
protocol::SourceCompat,
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml};
|
use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml};
|
||||||
|
@ -19,7 +19,7 @@ pub struct ChatMessage {
|
||||||
pub(crate) content: String,
|
pub(crate) content: String,
|
||||||
|
|
||||||
pub(crate) media_type: Option<MediaTypeHtml>,
|
pub(crate) media_type: Option<MediaTypeHtml>,
|
||||||
pub(crate) source: Option<Source>,
|
pub(crate) source: Option<SourceCompat>,
|
||||||
pub(crate) published: Option<DateTime<FixedOffset>>,
|
pub(crate) published: Option<DateTime<FixedOffset>>,
|
||||||
pub(crate) updated: Option<DateTime<FixedOffset>>,
|
pub(crate) updated: Option<DateTime<FixedOffset>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,10 @@ use crate::{
|
||||||
},
|
},
|
||||||
objects::{
|
objects::{
|
||||||
community::ApubCommunity,
|
community::ApubCommunity,
|
||||||
get_summary_from_string_or_source,
|
read_from_string_or_source_opt,
|
||||||
verify_image_domain_matches,
|
verify_image_domain_matches,
|
||||||
},
|
},
|
||||||
protocol::{objects::Endpoints, ImageObject, Source},
|
protocol::{objects::Endpoints, ImageObject, SourceCompat},
|
||||||
};
|
};
|
||||||
use activitystreams_kinds::actor::GroupType;
|
use activitystreams_kinds::actor::GroupType;
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
|
@ -33,14 +33,14 @@ pub struct Group {
|
||||||
pub(crate) id: ObjectId<ApubCommunity>,
|
pub(crate) id: ObjectId<ApubCommunity>,
|
||||||
/// username, set at account creation and usually fixed after that
|
/// username, set at account creation and usually fixed after that
|
||||||
pub(crate) preferred_username: String,
|
pub(crate) preferred_username: String,
|
||||||
/// displayname
|
|
||||||
pub(crate) name: String,
|
|
||||||
pub(crate) inbox: Url,
|
pub(crate) inbox: Url,
|
||||||
pub(crate) followers: Url,
|
pub(crate) followers: Url,
|
||||||
pub(crate) public_key: PublicKey,
|
pub(crate) public_key: PublicKey,
|
||||||
|
|
||||||
|
/// title
|
||||||
|
pub(crate) name: Option<String>,
|
||||||
pub(crate) summary: Option<String>,
|
pub(crate) summary: Option<String>,
|
||||||
pub(crate) source: Option<Source>,
|
pub(crate) source: Option<SourceCompat>,
|
||||||
pub(crate) icon: Option<ImageObject>,
|
pub(crate) icon: Option<ImageObject>,
|
||||||
/// banner
|
/// banner
|
||||||
pub(crate) image: Option<ImageObject>,
|
pub(crate) image: Option<ImageObject>,
|
||||||
|
@ -67,17 +67,17 @@ impl Group {
|
||||||
|
|
||||||
let slur_regex = &context.settings().slur_regex();
|
let slur_regex = &context.settings().slur_regex();
|
||||||
check_slurs(&self.preferred_username, slur_regex)?;
|
check_slurs(&self.preferred_username, slur_regex)?;
|
||||||
check_slurs(&self.name, slur_regex)?;
|
check_slurs_opt(&self.name, slur_regex)?;
|
||||||
let description = get_summary_from_string_or_source(&self.summary, &self.source);
|
let description = read_from_string_or_source_opt(&self.summary, &self.source);
|
||||||
check_slurs_opt(&description, slur_regex)?;
|
check_slurs_opt(&description, slur_regex)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn into_form(self) -> CommunityForm {
|
pub(crate) fn into_form(self) -> CommunityForm {
|
||||||
CommunityForm {
|
CommunityForm {
|
||||||
name: self.preferred_username,
|
name: self.preferred_username.clone(),
|
||||||
title: self.name,
|
title: self.name.unwrap_or(self.preferred_username),
|
||||||
description: get_summary_from_string_or_source(&self.summary, &self.source),
|
description: read_from_string_or_source_opt(&self.summary, &self.source),
|
||||||
removed: None,
|
removed: None,
|
||||||
published: self.published.map(|u| u.naive_local()),
|
published: self.published.map(|u| u.naive_local()),
|
||||||
updated: self.updated.map(|u| u.naive_local()),
|
updated: self.updated.map(|u| u.naive_local()),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::instance::ApubSite,
|
objects::instance::ApubSite,
|
||||||
protocol::{ImageObject, Source},
|
protocol::{ImageObject, SourceCompat},
|
||||||
};
|
};
|
||||||
use activitystreams_kinds::actor::ServiceType;
|
use activitystreams_kinds::actor::ServiceType;
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
|
@ -25,7 +25,7 @@ pub struct Instance {
|
||||||
|
|
||||||
// sidebar
|
// sidebar
|
||||||
pub(crate) content: Option<String>,
|
pub(crate) content: Option<String>,
|
||||||
pub(crate) source: Option<Source>,
|
pub(crate) source: Option<SourceCompat>,
|
||||||
// short instance description
|
// short instance description
|
||||||
pub(crate) summary: Option<String>,
|
pub(crate) summary: Option<String>,
|
||||||
pub(crate) media_type: Option<MediaTypeHtml>,
|
pub(crate) media_type: Option<MediaTypeHtml>,
|
||||||
|
|
|
@ -74,4 +74,12 @@ mod tests {
|
||||||
test_json::<Person>("assets/friendica/objects/person.json").unwrap();
|
test_json::<Person>("assets/friendica/objects/person.json").unwrap();
|
||||||
test_json::<Note>("assets/friendica/objects/note.json").unwrap();
|
test_json::<Note>("assets/friendica/objects/note.json").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_object_gnusocial() {
|
||||||
|
test_json::<Person>("assets/gnusocial/objects/person.json").unwrap();
|
||||||
|
test_json::<Group>("assets/gnusocial/objects/group.json").unwrap();
|
||||||
|
test_json::<Page>("assets/gnusocial/objects/page.json").unwrap();
|
||||||
|
test_json::<Note>("assets/gnusocial/objects/note.json").unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
fetcher::post_or_comment::PostOrComment,
|
fetcher::post_or_comment::PostOrComment,
|
||||||
mentions::Mention,
|
mentions::Mention,
|
||||||
objects::{comment::ApubComment, person::ApubPerson, post::ApubPost},
|
objects::{comment::ApubComment, person::ApubPerson, post::ApubPost},
|
||||||
protocol::Source,
|
protocol::SourceCompat,
|
||||||
};
|
};
|
||||||
use activitystreams_kinds::object::NoteType;
|
use activitystreams_kinds::object::NoteType;
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
|
@ -12,7 +12,6 @@ use lemmy_db_schema::{newtypes::CommentId, source::post::Post, traits::Crud};
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
|
||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -33,30 +32,13 @@ pub struct Note {
|
||||||
pub(crate) in_reply_to: ObjectId<PostOrComment>,
|
pub(crate) in_reply_to: ObjectId<PostOrComment>,
|
||||||
|
|
||||||
pub(crate) media_type: Option<MediaTypeHtml>,
|
pub(crate) media_type: Option<MediaTypeHtml>,
|
||||||
#[serde(default)]
|
pub(crate) source: Option<SourceCompat>,
|
||||||
pub(crate) source: SourceCompat,
|
|
||||||
pub(crate) published: Option<DateTime<FixedOffset>>,
|
pub(crate) published: Option<DateTime<FixedOffset>>,
|
||||||
pub(crate) updated: Option<DateTime<FixedOffset>>,
|
pub(crate) updated: Option<DateTime<FixedOffset>>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub(crate) tag: Vec<Mention>,
|
pub(crate) tag: Vec<Mention>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pleroma puts a raw string in the source, so we have to handle it here for deserialization to work
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub(crate) enum SourceCompat {
|
|
||||||
Lemmy(Source),
|
|
||||||
Other(Value),
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SourceCompat {
|
|
||||||
fn default() -> Self {
|
|
||||||
SourceCompat::None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Note {
|
impl Note {
|
||||||
pub(crate) async fn get_parents(
|
pub(crate) async fn get_parents(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
|
objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
|
||||||
protocol::{ImageObject, Source},
|
protocol::{ImageObject, SourceCompat},
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
|
use itertools::Itertools;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
object_id::ObjectId,
|
object_id::ObjectId,
|
||||||
|
@ -37,7 +38,7 @@ pub struct Page {
|
||||||
pub(crate) cc: Vec<Url>,
|
pub(crate) cc: Vec<Url>,
|
||||||
pub(crate) content: Option<String>,
|
pub(crate) content: Option<String>,
|
||||||
pub(crate) media_type: Option<MediaTypeHtml>,
|
pub(crate) media_type: Option<MediaTypeHtml>,
|
||||||
pub(crate) source: Option<Source>,
|
pub(crate) source: Option<SourceCompat>,
|
||||||
pub(crate) url: Option<Url>,
|
pub(crate) url: Option<Url>,
|
||||||
pub(crate) image: Option<ImageObject>,
|
pub(crate) image: Option<ImageObject>,
|
||||||
pub(crate) comments_enabled: Option<bool>,
|
pub(crate) comments_enabled: Option<bool>,
|
||||||
|
@ -70,9 +71,9 @@ impl Page {
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<ApubCommunity, LemmyError> {
|
) -> Result<ApubCommunity, LemmyError> {
|
||||||
let mut to_iter = self.to.iter();
|
let mut iter = self.to.iter().merge(self.cc.iter());
|
||||||
loop {
|
loop {
|
||||||
if let Some(cid) = to_iter.next() {
|
if let Some(cid) = iter.next() {
|
||||||
let cid = ObjectId::new(cid.clone());
|
let cid = ObjectId::new(cid.clone());
|
||||||
if let Ok(c) = cid
|
if let Ok(c) = cid
|
||||||
.dereference(context, context.client(), request_counter)
|
.dereference(context, context.client(), request_counter)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::person::ApubPerson,
|
objects::person::ApubPerson,
|
||||||
protocol::{objects::Endpoints, ImageObject, Source},
|
protocol::{objects::Endpoints, ImageObject, SourceCompat},
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
use lemmy_apub_lib::{object_id::ObjectId, signatures::PublicKey};
|
use lemmy_apub_lib::{object_id::ObjectId, signatures::PublicKey};
|
||||||
|
@ -31,7 +31,7 @@ pub struct Person {
|
||||||
/// displayname
|
/// displayname
|
||||||
pub(crate) name: Option<String>,
|
pub(crate) name: Option<String>,
|
||||||
pub(crate) summary: Option<String>,
|
pub(crate) summary: Option<String>,
|
||||||
pub(crate) source: Option<Source>,
|
pub(crate) source: Option<SourceCompat>,
|
||||||
/// user avatar
|
/// user avatar
|
||||||
pub(crate) icon: Option<ImageObject>,
|
pub(crate) icon: Option<ImageObject>,
|
||||||
/// user banner
|
/// user banner
|
||||||
|
|
Loading…
Reference in a new issue