--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "target": "http://enterprise.lemmy.ml/c/main/moderators",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Add",
+ "id": "http://enterprise.lemmy.ml/activities/add/ec069147-77c3-447f-88c8-0ef1df10403f"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/c/main",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Page",
+ "id": "http://enterprise.lemmy.ml/post/7",
+ "attributedTo": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "http://enterprise.lemmy.ml/c/main",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "name": "post 4",
+ "mediaType": "text/html",
+ "commentsEnabled": true,
+ "sensitive": false,
+ "stickied": false,
+ "published": "2021-11-01T12:11:22.871846+00:00"
+ },
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Create",
+ "id": "http://enterprise.lemmy.ml/activities/create/2807c9ec-3ad8-4859-a9e0-28b59b6e499f"
+ },
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main/followers"
+ ],
+ "type": "Announce",
+ "id": "http://enterprise.lemmy.ml/activities/announce/8030b171-803a-4108-94b1-342688f375cf"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "target": "http://enterprise.lemmy.ml/c/main",
+ "type": "Block",
+ "id": "http://enterprise.lemmy.ml/activities/block/5d42fffb-0903-4625-86d4-0b39bb344fc2"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Remove",
+ "target": "http://enterprise.lemmy.ml/c/main/moderators",
+ "id": "http://enterprise.lemmy.ml/activities/remove/aab114f8-cfbd-4935-a5b7-e1a64603650d"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "object": "http://enterprise.lemmy.ml/post/7",
+ "summary": "report this post",
+ "type": "Flag",
+ "id": "http://ds9.lemmy.ml/activities/flag/98b0933f-5e45-4a95-a15f-e0dc86361ba4"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "target": "http://enterprise.lemmy.ml/c/main",
+ "type": "Block",
+ "id": "http://enterprise.lemmy.ml/activities/block/726f43ab-bd0e-4ab3-89c8-627e976f553c"
+ },
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Undo",
+ "id": "http://enterprise.lemmy.ml/activities/undo/06a20ffb-3e32-42fb-8f4c-674b36d7c557"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Group",
+ "id": "http://enterprise.lemmy.ml/c/main",
+ "preferredUsername": "main",
+ "name": "The Updated Community",
+ "summary": "<p>updated 2</p>\n",
+ "source": {
+ "content": "updated 2",
+ "mediaType": "text/markdown"
+ },
+ "sensitive": false,
+ "moderators": "http://enterprise.lemmy.ml/c/main/moderators",
+ "inbox": "http://enterprise.lemmy.ml/c/main/inbox",
+ "outbox": "http://enterprise.lemmy.ml/c/main/outbox",
+ "followers": "http://enterprise.lemmy.ml/c/main/followers",
+ "endpoints": {
+ "sharedInbox": "http://enterprise.lemmy.ml/inbox"
+ },
+ "publicKey": {
+ "id": "http://enterprise.lemmy.ml/c/main#main-key",
+ "owner": "http://enterprise.lemmy.ml/c/main",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA16Xh06V1l2yy0WAIMUTV\nnvZIuAuKDxzDQUNT+n8gmcVuvBu7tkpbPTQ3DjGB3bQfGC2ekew/yldwOXyZ7ry1\npbJSYSrCBJrAlPLs/ao3OPTqmcl3vnSWti/hqopEV+Um2t7fwpkCjVrnzVKRSlys\nihnrth64ZiwAqq2llpaXzWc1SR2URZYSdnry/4d9UNrZVkumIeg1gk9KbCAo4j/O\njsv/aBjpZcTeLmtMZf6fcrvGre9duJdx6e2Tg/YNcnSnARosqev/UwVTzzGNVWXg\n9rItaa0a0aea4se4Bn6QXvOBbcq3+OYZMR6a34hh5BTeNG8WbpwmVahS0WFUsv9G\nswIDAQAB\n-----END PUBLIC KEY-----\n"
+ },
+ "published": "2021-10-29T15:05:51.476984+00:00",
+ "updated": "2021-11-01T12:23:50.151874+00:00"
+ },
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Update",
+ "id": "http://ds9.lemmy.ml/activities/update/d3717cf5-096d-473f-9530-5d52f9d51f5f"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Note",
+ "id": "http://ds9.lemmy.ml/comment/1",
+ "attributedTo": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "content": "hello",
+ "mediaType": "text/html",
+ "source": {
+ "content": "hello",
+ "mediaType": "text/markdown"
+ },
+ "inReplyTo": "http://ds9.lemmy.ml/post/1",
+ "published": "2021-11-01T11:45:49.794920+00:00"
+ },
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main",
+ "http://ds9.lemmy.ml/u/lemmy_alpha"
+ ],
+ "tag": [],
+ "type": "Create",
+ "id": "http://ds9.lemmy.ml/activities/create/1e77d67c-44ac-45ed-bf2a-460e21f60236"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Page",
+ "id": "http://ds9.lemmy.ml/post/1",
+ "attributedTo": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "http://enterprise.lemmy.ml/c/main",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "name": "test post",
+ "content": "<p>test body</p>\n",
+ "mediaType": "text/html",
+ "source": {
+ "content": "test body",
+ "mediaType": "text/markdown"
+ },
+ "url": "https://lemmy.ml/pictrs/image/xl8W7FZfk9.jpg",
+ "commentsEnabled": true,
+ "sensitive": false,
+ "stickied": false,
+ "published": "2021-10-29T15:10:51.557399+00:00"
+ },
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Create",
+ "id": "http://ds9.lemmy.ml/activities/create/eee6a57a-622f-464d-b560-73ae1fcd3ddf"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Page",
+ "id": "http://ds9.lemmy.ml/post/1",
+ "attributedTo": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "http://enterprise.lemmy.ml/c/main",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "name": "test post 1",
+ "content": "<p>test body</p>\n",
+ "mediaType": "text/html",
+ "source": {
+ "content": "test body",
+ "mediaType": "text/markdown"
+ },
+ "url": "https://lemmy.ml/pictrs/image/xl8W7FZfk9.jpg",
+ "commentsEnabled": true,
+ "sensitive": false,
+ "stickied": false,
+ "published": "2021-10-29T15:10:51.557399+00:00",
+ "updated": "2021-10-29T15:11:35.976374+00:00"
+ },
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Update",
+ "id": "http://ds9.lemmy.ml/activities/update/ab360117-e165-4de4-b7fc-906b62c98631"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/post/1",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Delete",
+ "id": "http://ds9.lemmy.ml/activities/delete/f2abee48-c7bb-41d5-9e27-8775ff32db12"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/comment/1",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Delete",
+ "summary": "bad comment",
+ "id": "http://enterprise.lemmy.ml/activities/delete/42ca1a79-f99e-4518-a2ca-ba2df221eb5e"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/post/1",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Delete",
+ "id": "http://ds9.lemmy.ml/activities/delete/b13cca96-7737-41e1-9769-8fbf972b3509"
+ },
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Undo",
+ "id": "http://ds9.lemmy.ml/activities/undo/5e939cfb-b8a1-4de8-950f-9d684e9162b9"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/comment/1",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Delete",
+ "summary": "bad comment",
+ "id": "http://enterprise.lemmy.ml/activities/delete/2598435c-87a3-49cd-81f3-a44b03b7af9d"
+ },
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Undo",
+ "id": "http://enterprise.lemmy.ml/activities/undo/a850cf21-3866-4b3a-b80b-56aa00997fee"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/c/main",
+ "to": [
+ "http://ds9.lemmy.ml/u/lemmy_alpha"
+ ],
+ "object": {
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "object": "http://enterprise.lemmy.ml/c/main",
+ "type": "Follow",
+ "id": "http://ds9.lemmy.ml/activities/follow/6abcd50b-b8ca-4952-86b0-a6dd8cc12866"
+ },
+ "type": "Accept",
+ "id": "http://enterprise.lemmy.ml/activities/accept/75f080cc-3d45-4654-8186-8f3bb853fa27"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "object": "http://enterprise.lemmy.ml/c/main",
+ "type": "Follow",
+ "id": "http://ds9.lemmy.ml/activities/follow/6abcd50b-b8ca-4952-86b0-a6dd8cc12866"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "object": {
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "object": "http://enterprise.lemmy.ml/c/main",
+ "type": "Follow",
+ "id": "http://ds9.lemmy.ml/activities/follow/dc2f1bc5-f3a0-4daa-a46b-428cbfbd023c"
+ },
+ "type": "Undo",
+ "id": "http://ds9.lemmy.ml/activities/undo/dd83c482-8ebd-4b6c-9008-c8373bd1a86a"
+}
\ No newline at end of file
--- /dev/null
+{
+ "id": "http://enterprise.lemmy.ml/activities/create/987d05fa-f637-46d7-85be-13d112bc269f",
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "http://ds9.lemmy.ml/u/lemmy_alpha"
+ ],
+ "object": {
+ "type": "ChatMessage",
+ "id": "http://enterprise.lemmy.ml/private_message/1",
+ "attributedTo": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "http://ds9.lemmy.ml/u/lemmy_alpha"
+ ],
+ "content": "hello",
+ "mediaType": "text/html",
+ "source": {
+ "content": "hello",
+ "mediaType": "text/markdown"
+ },
+ "published": "2021-10-29T15:31:56.058289+00:00"
+ },
+ "type": "Create"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "http://enterprise.lemmy.ml/u/lemmy_beta"
+ ],
+ "object": "http://enterprise.lemmy.ml/private_message/1",
+ "type": "Delete",
+ "id": "http://enterprise.lemmy.ml/activities/delete/041d9858-5eef-4ad9-84ae-7455b4d87ed9"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "http://ds9.lemmy.ml/u/lemmy_alpha"
+ ],
+ "object": {
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "http://enterprise.lemmy.ml/u/lemmy_beta"
+ ],
+ "object": "http://enterprise.lemmy.ml/private_message/1",
+ "type": "Delete",
+ "id": "http://enterprise.lemmy.ml/activities/delete/616c41be-04ed-4bd4-b865-30712186b122"
+ },
+ "type": "Undo",
+ "id": "http://enterprise.lemmy.ml/activities/undo/35e5b337-014c-4bbe-8d63-6fac96f51409"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/post/1",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Dislike",
+ "id": "http://enterprise.lemmy.ml/activities/dislike/64d40d40-a829-43a5-8247-1fb595b3ca1c"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/comment/1",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Like",
+ "id": "http://ds9.lemmy.ml/activities/like/fd61d070-7382-46a9-b2b7-6bb253732877"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/post/1",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Like",
+ "id": "http://enterprise.lemmy.ml/activities/like/2227ab2c-79e2-4fca-a1d2-1d67dacf2457"
+ },
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Undo",
+ "id": "http://enterprise.lemmy.ml/activities/undo/6cc6fb71-39fe-49ea-9506-f0423b101e98"
+}
\ No newline at end of file
--- /dev/null
+{
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": "http://ds9.lemmy.ml/comment/1",
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Like",
+ "id": "http://ds9.lemmy.ml/activities/like/efcf7ae2-dfcc-4ff4-9ce4-6adf251ff004"
+ },
+ "cc": [
+ "http://enterprise.lemmy.ml/c/main"
+ ],
+ "type": "Undo",
+ "id": "http://ds9.lemmy.ml/activities/undo/3518565c-24a7-4d9e-8e0a-f7a2f45ac618"
+}
\ No newline at end of file
--- /dev/null
+{
+ "id": "http://enterprise.lemmy.ml/c/main/followers",
+ "type": "Collection",
+ "totalItems": 3,
+ "items": []
+}
\ No newline at end of file
--- /dev/null
+{
+ "type": "OrderedCollection",
+ "id": "https://enterprise.lemmy.ml/c/tenforward/moderators",
+ "orderedItems": [
+ "https://enterprise.lemmy.ml/u/picard"
+ ]
+}
\ No newline at end of file
--- /dev/null
+{
+ "type": "OrderedCollection",
+ "id": "https://ds9.lemmy.ml/c/main/outbox",
+ "totalItems": 7,
+ "orderedItems": [
+ {
+ "actor": "https://ds9.lemmy.ml/u/dess_ds9",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Page",
+ "id": "https://ds9.lemmy.ml/post/1685",
+ "attributedTo": "https://ds9.lemmy.ml/u/dess_ds9",
+ "to": [
+ "https://ds9.lemmy.ml/c/main",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "name": "Test post",
+ "mediaType": "text/html",
+ "commentsEnabled": true,
+ "sensitive": false,
+ "stickied": false,
+ "published": "2021-09-30T16:37:58.425718+00:00",
+ "updated": "2021-09-30T16:39:50.934055+00:00"
+ },
+ "cc": [
+ "https://ds9.lemmy.ml/c/main"
+ ],
+ "type": "Create",
+ "id": "https://ds9.lemmy.ml/activities/create/157bc329-05cb-4dc3-ad9e-5110fde3f3aa"
+ },
+ {
+ "actor": "https://ds9.lemmy.ml/u/nutomic",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Page",
+ "id": "https://ds9.lemmy.ml/post/1665",
+ "attributedTo": "https://ds9.lemmy.ml/u/nutomic",
+ "to": [
+ "https://ds9.lemmy.ml/c/main",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "name": "another webmention test",
+ "mediaType": "text/html",
+ "url": "https://webmention.rocks/test/1",
+ "commentsEnabled": true,
+ "sensitive": false,
+ "stickied": false,
+ "published": "2021-09-17T13:22:15.026912+00:00"
+ },
+ "cc": [
+ "https://ds9.lemmy.ml/c/main"
+ ],
+ "type": "Create",
+ "id": "https://ds9.lemmy.ml/activities/create/c54e4509-16ac-42bf-b3b4-0bf8516f8152"
+ },
+ {
+ "actor": "https://ds9.lemmy.ml/u/nutomic",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Page",
+ "id": "https://ds9.lemmy.ml/post/1664",
+ "attributedTo": "https://ds9.lemmy.ml/u/nutomic",
+ "to": [
+ "https://ds9.lemmy.ml/c/main",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "name": "another test",
+ "mediaType": "text/html",
+ "url": "https://webmention.rocks/test/1",
+ "commentsEnabled": true,
+ "sensitive": false,
+ "stickied": false,
+ "published": "2021-09-17T13:13:21.675891+00:00"
+ },
+ "cc": [
+ "https://ds9.lemmy.ml/c/main"
+ ],
+ "type": "Create",
+ "id": "https://ds9.lemmy.ml/activities/create/25f7d2cb-11d5-4c9c-aa3c-85fbff9f9e0c"
+ },
+ {
+ "actor": "https://ds9.lemmy.ml/u/nutomic",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Page",
+ "id": "https://ds9.lemmy.ml/post/1663",
+ "attributedTo": "https://ds9.lemmy.ml/u/nutomic",
+ "to": [
+ "https://ds9.lemmy.ml/c/main",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "name": "Webmention test from Lemmy",
+ "mediaType": "text/html",
+ "url": "https://webmention.rocks/test/1",
+ "commentsEnabled": true,
+ "sensitive": false,
+ "stickied": false,
+ "published": "2021-09-17T13:00:15.392844+00:00"
+ },
+ "cc": [
+ "https://ds9.lemmy.ml/c/main"
+ ],
+ "type": "Create",
+ "id": "https://ds9.lemmy.ml/activities/create/cfbd12b8-2e11-42b6-a609-b482decbaf11"
+ },
+ {
+ "actor": "https://ds9.lemmy.ml/u/dess_tester_3",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Page",
+ "id": "https://ds9.lemmy.ml/post/1644",
+ "attributedTo": "https://ds9.lemmy.ml/u/dess_tester_3",
+ "to": [
+ "https://ds9.lemmy.ml/c/main",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "name": "The best wireless earbuds you can buy right now | Engadget",
+ "mediaType": "text/html",
+ "url": "https://www.engadget.com/best-wireless-earbuds-120058222.html",
+ "image": {
+ "type": "Image",
+ "url": "https://ds9.lemmy.ml/pictrs/image/0WWsYOuwAE.jpg"
+ },
+ "commentsEnabled": true,
+ "sensitive": false,
+ "stickied": false,
+ "published": "2021-08-26T01:22:06.428368+00:00"
+ },
+ "cc": [
+ "https://ds9.lemmy.ml/c/main"
+ ],
+ "type": "Create",
+ "id": "https://ds9.lemmy.ml/activities/create/76c94408-944a-4a2f-a88b-d10f12b472b0"
+ },
+ {
+ "actor": "https://ds9.lemmy.ml/u/dess_ds9",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Page",
+ "id": "https://ds9.lemmy.ml/post/1643",
+ "attributedTo": "https://ds9.lemmy.ml/u/dess_ds9",
+ "to": [
+ "https://ds9.lemmy.ml/c/main",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "name": "First Look: Cadillac’s luxury EV debut seems like a winner | Engadges",
+ "content": "<p>test</p>\n",
+ "mediaType": "text/html",
+ "source": {
+ "content": "test",
+ "mediaType": "text/markdown"
+ },
+ "url": "https://www.engadget.com/cadillac-lyriq-luxury-ev-first-look-video-171543752.html",
+ "image": {
+ "type": "Image",
+ "url": "https://ds9.lemmy.ml/pictrs/image/gnmtvgXP31.jpg"
+ },
+ "commentsEnabled": true,
+ "sensitive": false,
+ "stickied": false,
+ "published": "2021-08-23T23:43:06.560543+00:00",
+ "updated": "2021-08-23T23:52:51.832606+00:00"
+ },
+ "cc": [
+ "https://ds9.lemmy.ml/c/main"
+ ],
+ "type": "Create",
+ "id": "https://ds9.lemmy.ml/activities/create/b1f95918-f593-4951-91cf-2c3340cd9509"
+ },
+ {
+ "actor": "https://ds9.lemmy.ml/u/dess_ds9_2",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "object": {
+ "type": "Page",
+ "id": "https://ds9.lemmy.ml/post/1642",
+ "attributedTo": "https://ds9.lemmy.ml/u/dess_ds9_2",
+ "to": [
+ "https://ds9.lemmy.ml/c/main",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "name": "A test post from DS9",
+ "mediaType": "text/html",
+ "commentsEnabled": true,
+ "sensitive": false,
+ "stickied": false,
+ "published": "2021-08-06T14:10:47.493075+00:00"
+ },
+ "cc": [
+ "https://ds9.lemmy.ml/c/main"
+ ],
+ "type": "Create",
+ "id": "https://ds9.lemmy.ml/activities/create/6359b2e7-badb-4241-b5ee-b093078361bd"
+ }
+ ]
+}
\ No newline at end of file
--- /dev/null
+{
+ "type": "OrderedCollection",
+ "id": "http://ds9.lemmy.ml/u/lemmy_alpha/outbox",
+ "orderedItems": [],
+ "totalItems": 0
+}
\ No newline at end of file
"content": "This is a post in the /c/tenforward community",
"mediaType": "text/markdown"
},
+ "url": "https://enterprise.lemmy.ml/pictrs/image/eOtYb9iEiB.png",
+ "image": {
+ "type": "Image",
+ "url": "https://enterprise.lemmy.ml/pictrs/image/eOtYb9iEiB.png"
+ },
"sensitive": false,
"commentsEnabled": true,
"stickied": true,
"type": "Image",
"url": "https://enterprise.lemmy.ml/pictrs/image/XenaYI5hTn.png"
},
+ "matrix_user_id": "@picard:matrix.org",
"inbox": "https://enterprise.lemmy.ml/u/picard/inbox",
"outbox": "https://enterprise.lemmy.ml/u/picard/outbox",
"endpoints": {
Ok(community.into())
}
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::objects::tests::file_to_json_object;
- use serial_test::serial;
-
- #[actix_rt::test]
- #[serial]
- async fn test_parse_pleroma_create_comment() {
- file_to_json_object::<CreateOrUpdateComment>("assets/pleroma/activities/create-note.json");
- }
-}
-use serde::{Deserialize, Serialize};
-
-use lemmy_apub_lib::{
- traits::{ActivityFields, ActivityHandler, ActorType},
- verify::verify_urls_match,
-};
-use lemmy_utils::LemmyError;
-use lemmy_websocket::LemmyContext;
-
use crate::{
activities::community::announce::GetCommunity,
objects::community::ApubCommunity,
voting::{undo_vote::UndoVote, vote::Vote},
},
};
+use lemmy_apub_lib::traits::{ActivityFields, ActivityHandler};
+use lemmy_utils::LemmyError;
+use lemmy_websocket::LemmyContext;
+use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler, ActivityFields)]
#[serde(untagged)]
AddMod(a) => a.get_community(context, request_counter).await?,
RemoveMod(a) => a.get_community(context, request_counter).await?,
};
- verify_urls_match(self.actor(), &community.actor_id())?;
Ok(community)
}
}
Ok(ApubCommunityModerators { 0: vec![] })
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::objects::{
+ community::tests::parse_lemmy_community,
+ person::tests::parse_lemmy_person,
+ tests::{file_to_json_object, init_context},
+ };
+ use lemmy_db_schema::{
+ source::{
+ community::Community,
+ person::{Person, PersonForm},
+ },
+ traits::Crud,
+ };
+ use serial_test::serial;
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_lemmy_community_moderators() {
+ let context = init_context();
+ let community = parse_lemmy_community(&context).await;
+ let community_id = community.id;
+
+ let old_mod = PersonForm {
+ name: "holly".into(),
+ ..PersonForm::default()
+ };
+ let old_mod = Person::create(&context.pool().get().unwrap(), &old_mod).unwrap();
+ let community_moderator_form = CommunityModeratorForm {
+ community_id: community.id,
+ person_id: old_mod.id,
+ };
+
+ CommunityModerator::join(&context.pool().get().unwrap(), &community_moderator_form).unwrap();
+
+ let new_mod = parse_lemmy_person(&context).await;
+
+ let json: GroupModerators =
+ file_to_json_object("assets/lemmy/collections/group_moderators.json");
+ let url = Url::parse("https://enterprise.lemmy.ml/c/tenforward").unwrap();
+ let mut request_counter = 0;
+ let community_context = CommunityContext {
+ 0: community,
+ 1: context,
+ };
+ ApubCommunityModerators::from_apub(&json, &community_context, &url, &mut request_counter)
+ .await
+ .unwrap();
+ assert_eq!(request_counter, 0);
+
+ let current_moderators = blocking(community_context.1.pool(), move |conn| {
+ CommunityModeratorView::for_community(conn, community_id)
+ })
+ .await
+ .unwrap()
+ .unwrap();
+
+ assert_eq!(current_moderators.len(), 1);
+ assert_eq!(current_moderators[0].moderator.id, new_mod.id);
+
+ Person::delete(&*community_context.1.pool().get().unwrap(), old_mod.id).unwrap();
+ Person::delete(&*community_context.1.pool().get().unwrap(), new_mod.id).unwrap();
+ Community::delete(
+ &*community_context.1.pool().get().unwrap(),
+ community_context.0.id,
+ )
+ .unwrap();
+ }
+}
use crate::{
fetcher::object_id::ObjectId,
- objects::{
- comment::ApubComment,
- community::ApubCommunity,
- person::{ApubPerson, Person},
- post::ApubPost,
- },
- protocol::objects::{group::Group, note::Note, page::Page},
+ objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
+ protocol::objects::{group::Group, note::Note, page::Page, person::Person},
};
/// Attempt to parse the query as URL, and fetch an ActivityPub object from it.
objects::community::ApubCommunity,
protocol::{
activities::community::announce::AnnounceActivity,
- collections::group_followers::CommunityFollowers,
+ collections::group_followers::GroupFollowers,
},
};
use actix_web::{body::Body, web, web::Payload, HttpRequest, HttpResponse};
use lemmy_api_common::blocking;
-use lemmy_apub_lib::{
- traits::{ActivityFields, ActorType, ApubObject},
- verify::verify_domains_match,
-};
+use lemmy_apub_lib::traits::{ActivityFields, ApubObject};
use lemmy_db_schema::source::community::Community;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
if let GroupInboxActivities::AnnouncableActivities(announcable) = activity {
let community = announcable.get_community(context, &mut 0).await?;
let actor_id = ObjectId::new(announcable.actor().clone());
- verify_domains_match(&community.actor_id(), announcable.id_unchecked())?;
verify_person_in_community(&actor_id, &community, context, &mut 0).await?;
if community.local {
AnnounceActivity::send(announcable, &community, vec![], context).await?;
Community::read_from_name(conn, &info.community_name)
})
.await??;
- let followers = CommunityFollowers::new(community, &context).await?;
+ let followers = GroupFollowers::new(community, &context).await?;
Ok(create_apub_response(&followers))
}
receive_activity,
},
objects::person::ApubPerson,
- protocol::collections::person_outbox::UserOutbox,
+ protocol::collections::person_outbox::PersonOutbox,
};
use actix_web::{body::Body, web, web::Payload, HttpRequest, HttpResponse};
use lemmy_api_common::blocking;
Person::find_by_name(conn, &info.user_name)
})
.await??;
- let outbox = UserOutbox::new(person).await?;
+ let outbox = PersonOutbox::new(person).await?;
Ok(create_apub_response(&outbox))
}
pub(crate) mod tests {
use super::*;
use crate::objects::{
- community::ApubCommunity,
- person::ApubPerson,
+ community::{tests::parse_lemmy_community, ApubCommunity},
+ person::{tests::parse_lemmy_person, ApubPerson},
post::ApubPost,
tests::{file_to_json_object, init_context},
};
use assert_json_diff::assert_json_include;
use serial_test::serial;
- pub(crate) async fn prepare_comment_test(
+ async fn prepare_comment_test(
url: &Url,
context: &LemmyContext,
) -> (ApubPerson, ApubCommunity, ApubPost) {
- let person_json = file_to_json_object("assets/lemmy/objects/person.json");
- let person = ApubPerson::from_apub(&person_json, context, url, &mut 0)
- .await
- .unwrap();
- let community_json = file_to_json_object("assets/lemmy/objects/group.json");
- let community = ApubCommunity::from_apub(&community_json, context, url, &mut 0)
- .await
- .unwrap();
+ let person = parse_lemmy_person(context).await;
+ let community = parse_lemmy_community(context).await;
let post_json = file_to_json_object("assets/lemmy/objects/page.json");
let post = ApubPost::from_apub(&post_json, context, url, &mut 0)
.await
}
#[cfg(test)]
-mod tests {
+pub(crate) mod tests {
use super::*;
use crate::objects::tests::{file_to_json_object, init_context};
- use assert_json_diff::assert_json_include;
use lemmy_db_schema::traits::Crud;
use serial_test::serial;
- #[actix_rt::test]
- #[serial]
- async fn test_parse_lemmy_community() {
- let context = init_context();
+ pub(crate) async fn parse_lemmy_community(context: &LemmyContext) -> ApubCommunity {
let mut json: Group = file_to_json_object("assets/lemmy/objects/group.json");
- let json_orig = json.clone();
// change these links so they dont fetch over the network
- json.moderators = Some(ObjectId::new(
- Url::parse("https://enterprise.lemmy.ml/c/tenforward/not_moderators").unwrap(),
- ));
+ json.moderators = None;
json.outbox =
ObjectId::new(Url::parse("https://enterprise.lemmy.ml/c/tenforward/not_outbox").unwrap());
let url = Url::parse("https://enterprise.lemmy.ml/c/tenforward").unwrap();
let mut request_counter = 0;
- let community = ApubCommunity::from_apub(&json, &context, &url, &mut request_counter)
+ let community = ApubCommunity::from_apub(&json, context, &url, &mut request_counter)
.await
.unwrap();
+ // this makes two requests to the (intentionally) broken outbox/moderators collections
+ assert_eq!(request_counter, 1);
+ community
+ }
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_lemmy_community() {
+ let context = init_context();
+ let community = parse_lemmy_community(&context).await;
- assert_eq!(community.actor_id.clone().into_inner(), url);
assert_eq!(community.title, "Ten Forward");
assert!(community.public_key.is_some());
assert!(!community.local);
assert_eq!(community.description.as_ref().unwrap().len(), 132);
- // this makes two requests to the (intentionally) broken outbox/moderators collections
- assert_eq!(request_counter, 2);
-
- let to_apub = community.to_apub(&context).await.unwrap();
- assert_json_include!(actual: json_orig, expected: to_apub);
Community::delete(&*context.pool().get().unwrap(), community.id).unwrap();
}
check_is_apub_id_valid,
generate_outbox_url,
objects::get_summary_from_string_or_source,
- protocol::{ImageObject, Source},
+ protocol::{
+ objects::person::{Person, UserTypes},
+ ImageObject,
+ Source,
+ },
};
-use activitystreams::{actor::Endpoints, object::kind::ImageType, unparsed::Unparsed};
-use chrono::{DateTime, FixedOffset, NaiveDateTime};
+use activitystreams::{actor::Endpoints, object::kind::ImageType};
+use chrono::NaiveDateTime;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
- signatures::PublicKey,
traits::{ActorType, ApubObject},
values::MediaTypeMarkdown,
verify::verify_domains_match,
LemmyError,
};
use lemmy_websocket::LemmyContext;
-use serde::{Deserialize, Serialize};
-use serde_with::skip_serializing_none;
use std::ops::Deref;
use url::Url;
-#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)]
-pub enum UserTypes {
- Person,
- Service,
-}
-
-#[skip_serializing_none]
-#[derive(Clone, Debug, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct Person {
- #[serde(rename = "type")]
- kind: UserTypes,
- id: Url,
- /// username, set at account creation and can never be changed
- preferred_username: String,
- /// displayname (can be changed at any time)
- name: Option<String>,
- summary: Option<String>,
- source: Option<Source>,
- /// user avatar
- icon: Option<ImageObject>,
- /// user banner
- image: Option<ImageObject>,
- matrix_user_id: Option<String>,
- inbox: Url,
- /// mandatory field in activitypub, currently empty in lemmy
- outbox: Url,
- endpoints: Endpoints<Url>,
- public_key: PublicKey,
- published: Option<DateTime<FixedOffset>>,
- updated: Option<DateTime<FixedOffset>>,
- #[serde(flatten)]
- unparsed: Unparsed,
-}
-
-// TODO: can generate this with a derive macro
-impl Person {
- pub(crate) fn id(&self, expected_domain: &Url) -> Result<&Url, LemmyError> {
- verify_domains_match(&self.id, expected_domain)?;
- Ok(&self.id)
- }
-}
-
#[derive(Clone, Debug, PartialEq)]
pub struct ApubPerson(DbPerson);
expected_domain: &Url,
_request_counter: &mut i32,
) -> Result<ApubPerson, LemmyError> {
- let actor_id = Some(person.id(expected_domain)?.clone().into());
+ verify_domains_match(&person.id, expected_domain)?;
+ let actor_id = Some(person.id.clone().into());
let name = person.preferred_username.clone();
let display_name: Option<String> = person.name.clone();
let bio = get_summary_from_string_or_source(&person.summary, &person.source);
}
#[cfg(test)]
-mod tests {
+pub(crate) mod tests {
use super::*;
use crate::objects::tests::{file_to_json_object, init_context};
- use assert_json_diff::assert_json_include;
use lemmy_db_schema::traits::Crud;
use serial_test::serial;
- #[actix_rt::test]
- #[serial]
- async fn test_parse_lemmy_person() {
- let context = init_context();
+ pub(crate) async fn parse_lemmy_person(context: &LemmyContext) -> ApubPerson {
let json = file_to_json_object("assets/lemmy/objects/person.json");
let url = Url::parse("https://enterprise.lemmy.ml/u/picard").unwrap();
let mut request_counter = 0;
- let person = ApubPerson::from_apub(&json, &context, &url, &mut request_counter)
+ let person = ApubPerson::from_apub(&json, context, &url, &mut request_counter)
.await
.unwrap();
+ assert_eq!(request_counter, 0);
+ person
+ }
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_lemmy_person() {
+ let context = init_context();
+ let person = parse_lemmy_person(&context).await;
- assert_eq!(person.actor_id.clone().into_inner(), url);
assert_eq!(person.display_name, Some("Jean-Luc Picard".to_string()));
assert!(person.public_key.is_some());
assert!(!person.local);
assert_eq!(person.bio.as_ref().unwrap().len(), 39);
- assert_eq!(request_counter, 0);
-
- let to_apub = person.to_apub(&context).await.unwrap();
- assert_json_include!(actual: json, expected: to_apub);
DbPerson::delete(&*context.pool().get().unwrap(), person.id).unwrap();
}
mod tests {
use super::*;
use crate::objects::{
- community::ApubCommunity,
- person::ApubPerson,
+ community::tests::parse_lemmy_community,
+ person::tests::parse_lemmy_person,
post::ApubPost,
tests::{file_to_json_object, init_context},
};
- use assert_json_diff::assert_json_include;
use serial_test::serial;
#[actix_rt::test]
#[serial]
async fn test_parse_lemmy_post() {
let context = init_context();
- let url = Url::parse("https://enterprise.lemmy.ml/post/55143").unwrap();
- let community_json = file_to_json_object("assets/lemmy/objects/group.json");
- let community = ApubCommunity::from_apub(&community_json, &context, &url, &mut 0)
- .await
- .unwrap();
- let person_json = file_to_json_object("assets/lemmy/objects/person.json");
- let person = ApubPerson::from_apub(&person_json, &context, &url, &mut 0)
- .await
- .unwrap();
+ let community = parse_lemmy_community(&context).await;
+ let person = parse_lemmy_person(&context).await;
+
let json = file_to_json_object("assets/lemmy/objects/page.json");
+ let url = Url::parse("https://enterprise.lemmy.ml/post/55143").unwrap();
let mut request_counter = 0;
let post = ApubPost::from_apub(&json, &context, &url, &mut request_counter)
.await
assert!(post.stickied);
assert_eq!(request_counter, 0);
- let to_apub = post.to_apub(&context).await.unwrap();
- assert_json_include!(actual: json, expected: to_apub);
-
Post::delete(&*context.pool().get().unwrap(), post.id).unwrap();
Person::delete(&*context.pool().get().unwrap(), person.id).unwrap();
Community::delete(&*context.pool().get().unwrap(), community.id).unwrap();
pub mod report;
pub mod undo_block_user;
pub mod update;
+
+#[cfg(test)]
+mod tests {
+ use crate::protocol::{
+ activities::community::{
+ add_mod::AddMod,
+ block_user::BlockUserFromCommunity,
+ remove_mod::RemoveMod,
+ report::Report,
+ undo_block_user::UndoBlockUserFromCommunity,
+ update::UpdateCommunity,
+ },
+ tests::test_parse_lemmy_item,
+ };
+ use activitystreams::activity::Announce;
+ use serial_test::serial;
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_lemmy_community() {
+ test_parse_lemmy_item::<Announce>(
+ "assets/lemmy/activities/community/announce_create_page.json",
+ );
+
+ test_parse_lemmy_item::<AddMod>("assets/lemmy/activities/community/add_mod.json");
+ test_parse_lemmy_item::<RemoveMod>("assets/lemmy/activities/community/remove_mod.json");
+
+ test_parse_lemmy_item::<BlockUserFromCommunity>(
+ "assets/lemmy/activities/community/block_user.json",
+ );
+ test_parse_lemmy_item::<UndoBlockUserFromCommunity>(
+ "assets/lemmy/activities/community/undo_block_user.json",
+ );
+
+ test_parse_lemmy_item::<UpdateCommunity>(
+ "assets/lemmy/activities/community/update_community.json",
+ );
+
+ test_parse_lemmy_item::<Report>("assets/lemmy/activities/community/report_page.json");
+ }
+}
pub mod comment;
pub mod post;
+
+#[cfg(test)]
+mod tests {
+ use crate::{
+ objects::tests::file_to_json_object,
+ protocol::{
+ activities::create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost},
+ tests::test_parse_lemmy_item,
+ },
+ };
+ use serial_test::serial;
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_lemmy_create_or_update() {
+ test_parse_lemmy_item::<CreateOrUpdatePost>(
+ "assets/lemmy/activities/create_or_update/create_page.json",
+ );
+ test_parse_lemmy_item::<CreateOrUpdatePost>(
+ "assets/lemmy/activities/create_or_update/update_page.json",
+ );
+ test_parse_lemmy_item::<CreateOrUpdateComment>(
+ "assets/lemmy/activities/create_or_update/create_note.json",
+ );
+ }
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_pleroma_create_or_update() {
+ file_to_json_object::<CreateOrUpdateComment>("assets/pleroma/activities/create_note.json");
+ }
+}
pub mod delete;
pub mod undo_delete;
+
+#[cfg(test)]
+mod tests {
+ use crate::protocol::{
+ activities::deletion::{delete::Delete, undo_delete::UndoDelete},
+ tests::test_parse_lemmy_item,
+ };
+ use serial_test::serial;
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_lemmy_voting() {
+ test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/remove_note.json");
+ test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/delete_page.json");
+
+ test_parse_lemmy_item::<UndoDelete>("assets/lemmy/activities/deletion/undo_remove_note.json");
+ test_parse_lemmy_item::<UndoDelete>("assets/lemmy/activities/deletion/undo_delete_page.json");
+ }
+}
pub(crate) mod accept;
pub mod follow;
pub mod undo_follow;
+
+#[cfg(test)]
+mod tests {
+ use crate::protocol::{
+ activities::following::{
+ accept::AcceptFollowCommunity,
+ follow::FollowCommunity,
+ undo_follow::UndoFollowCommunity,
+ },
+ tests::test_parse_lemmy_item,
+ };
+ use serial_test::serial;
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_lemmy_accept_follow() {
+ test_parse_lemmy_item::<FollowCommunity>("assets/lemmy/activities/following/follow.json");
+ test_parse_lemmy_item::<AcceptFollowCommunity>("assets/lemmy/activities/following/accept.json");
+ test_parse_lemmy_item::<UndoFollowCommunity>(
+ "assets/lemmy/activities/following/undo_follow.json",
+ );
+ }
+}
pub mod create_or_update;
pub mod delete;
pub mod undo_delete;
+
+#[cfg(test)]
+mod tests {
+ use crate::protocol::{
+ activities::private_message::{
+ create_or_update::CreateOrUpdatePrivateMessage,
+ delete::DeletePrivateMessage,
+ undo_delete::UndoDeletePrivateMessage,
+ },
+ tests::test_parse_lemmy_item,
+ };
+ use serial_test::serial;
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_lemmy_private_message() {
+ test_parse_lemmy_item::<CreateOrUpdatePrivateMessage>(
+ "assets/lemmy/activities/private_message/create.json",
+ );
+ test_parse_lemmy_item::<DeletePrivateMessage>(
+ "assets/lemmy/activities/private_message/delete.json",
+ );
+ test_parse_lemmy_item::<UndoDeletePrivateMessage>(
+ "assets/lemmy/activities/private_message/undo_delete.json",
+ );
+ }
+}
pub mod undo_vote;
pub mod vote;
+
+#[cfg(test)]
+mod tests {
+ use crate::protocol::{
+ activities::voting::{undo_vote::UndoVote, vote::Vote},
+ tests::test_parse_lemmy_item,
+ };
+ use serial_test::serial;
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_lemmy_voting() {
+ test_parse_lemmy_item::<Vote>("assets/lemmy/activities/voting/like_note.json");
+ test_parse_lemmy_item::<Vote>("assets/lemmy/activities/voting/dislike_page.json");
+
+ test_parse_lemmy_item::<UndoVote>("assets/lemmy/activities/voting/undo_like_note.json");
+ test_parse_lemmy_item::<UndoVote>("assets/lemmy/activities/voting/undo_dislike_page.json");
+ }
+}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
-pub(crate) struct CommunityFollowers {
+pub(crate) struct GroupFollowers {
id: Url,
r#type: CollectionType,
total_items: i32,
items: Vec<()>,
}
-impl CommunityFollowers {
+impl GroupFollowers {
pub(crate) async fn new(
community: Community,
context: &LemmyContext,
- ) -> Result<CommunityFollowers, LemmyError> {
+ ) -> Result<GroupFollowers, LemmyError> {
let community_id = community.id;
let community_followers = blocking(context.pool(), move |conn| {
CommunityFollowerView::for_community(conn, community_id)
})
.await??;
- Ok(CommunityFollowers {
+ Ok(GroupFollowers {
id: generate_followers_url(&community.actor_id)?.into_inner(),
r#type: CollectionType::Collection,
total_items: community_followers.len() as i32,
pub(crate) mod group_moderators;
pub(crate) mod group_outbox;
pub(crate) mod person_outbox;
+
+#[cfg(test)]
+mod tests {
+ use crate::protocol::{
+ collections::{
+ group_followers::GroupFollowers,
+ group_moderators::GroupModerators,
+ group_outbox::GroupOutbox,
+ person_outbox::PersonOutbox,
+ },
+ tests::test_parse_lemmy_item,
+ };
+ use serial_test::serial;
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_lemmy_collections() {
+ test_parse_lemmy_item::<GroupFollowers>("assets/lemmy/collections/group_followers.json");
+ let outbox = test_parse_lemmy_item::<GroupOutbox>("assets/lemmy/collections/group_outbox.json");
+ assert_eq!(outbox.ordered_items.len() as i32, outbox.total_items);
+ test_parse_lemmy_item::<GroupModerators>("assets/lemmy/collections/group_moderators.json");
+ test_parse_lemmy_item::<PersonOutbox>("assets/lemmy/collections/person_outbox.json");
+ }
+}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
-pub(crate) struct UserOutbox {
+pub(crate) struct PersonOutbox {
r#type: OrderedCollectionType,
id: Url,
ordered_items: Vec<()>,
total_items: i32,
}
-impl UserOutbox {
- pub(crate) async fn new(user: Person) -> Result<UserOutbox, LemmyError> {
- Ok(UserOutbox {
+impl PersonOutbox {
+ pub(crate) async fn new(user: Person) -> Result<PersonOutbox, LemmyError> {
+ Ok(PersonOutbox {
r#type: OrderedCollectionType::OrderedCollection,
id: generate_outbox_url(&user.actor_id)?.into_inner(),
ordered_items: vec![],
pub(crate) kind: ImageType,
pub(crate) url: Url,
}
+
+#[cfg(test)]
+pub(crate) mod tests {
+ use crate::objects::tests::file_to_json_object;
+ use assert_json_diff::assert_json_include;
+ use serde::{de::DeserializeOwned, Serialize};
+ use std::collections::HashMap;
+
+ pub(crate) fn test_parse_lemmy_item<T: Serialize + DeserializeOwned>(path: &str) -> T {
+ let parsed = file_to_json_object::<T>(path);
+
+ // ensure that no field is ignored when parsing
+ let raw = file_to_json_object::<HashMap<String, serde_json::Value>>(path);
+ assert_json_include!(actual: &parsed, expected: raw);
+ parsed
+ }
+}
pub(crate) mod group;
pub(crate) mod note;
pub(crate) mod page;
+pub(crate) mod person;
pub(crate) mod tombstone;
+
+#[cfg(test)]
+mod tests {
+ use crate::protocol::{
+ objects::{chat_message::ChatMessage, group::Group, note::Note, page::Page, person::Person},
+ tests::test_parse_lemmy_item,
+ };
+ use serial_test::serial;
+
+ #[actix_rt::test]
+ #[serial]
+ async fn test_parse_lemmy_object() {
+ test_parse_lemmy_item::<Person>("assets/lemmy/objects/person.json");
+ test_parse_lemmy_item::<Group>("assets/lemmy/objects/group.json");
+ test_parse_lemmy_item::<Page>("assets/lemmy/objects/page.json");
+ test_parse_lemmy_item::<Note>("assets/lemmy/objects/note.json");
+ test_parse_lemmy_item::<ChatMessage>("assets/lemmy/objects/chat_message.json");
+ }
+}
--- /dev/null
+use crate::protocol::{ImageObject, Source};
+use activitystreams::{actor::Endpoints, unparsed::Unparsed, url::Url};
+use chrono::{DateTime, FixedOffset};
+use lemmy_apub_lib::signatures::PublicKey;
+use serde::{Deserialize, Serialize};
+use serde_with::skip_serializing_none;
+
+#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)]
+pub enum UserTypes {
+ Person,
+ Service,
+}
+
+#[skip_serializing_none]
+#[derive(Clone, Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Person {
+ #[serde(rename = "type")]
+ pub(crate) kind: UserTypes,
+ pub(crate) id: Url,
+ /// username, set at account creation and can never be changed
+ pub(crate) preferred_username: String,
+ /// displayname (can be changed at any time)
+ pub(crate) name: Option<String>,
+ pub(crate) summary: Option<String>,
+ pub(crate) source: Option<Source>,
+ /// user avatar
+ pub(crate) icon: Option<ImageObject>,
+ /// user banner
+ pub(crate) image: Option<ImageObject>,
+ pub(crate) matrix_user_id: Option<String>,
+ pub(crate) inbox: Url,
+ /// mandatory field in activitypub, currently empty in lemmy
+ pub(crate) outbox: Url,
+ pub(crate) endpoints: Endpoints<Url>,
+ pub(crate) public_key: PublicKey,
+ pub(crate) published: Option<DateTime<FixedOffset>>,
+ pub(crate) updated: Option<DateTime<FixedOffset>>,
+ #[serde(flatten)]
+ pub(crate) unparsed: Unparsed,
+}
use crate::{newtypes::DbUrl, source::activity::*, traits::Crud};
-use diesel::{dsl::*, result::Error, sql_types::Text, *};
+use diesel::{dsl::*, result::Error, *};
use serde::Serialize;
-use serde_json::Value;
use std::{
fmt::Debug,
io::{Error as IoError, ErrorKind},
use crate::schema::activity::dsl::*;
diesel::delete(activity.filter(published.lt(now - 6.months()))).execute(conn)
}
-
- pub fn read_community_outbox(
- conn: &PgConnection,
- community_actor_id: &DbUrl,
- ) -> Result<Vec<Value>, Error> {
- use crate::schema::activity::dsl::*;
- let res: Vec<Value> = activity
- .select(data)
- .filter(
- sql("activity.data ->> 'type' = 'Announce'")
- .sql(" AND activity.data -> 'object' ->> 'type' = 'Create'")
- .sql(" AND activity.data -> 'object' -> 'object' ->> 'type' = 'Page'")
- .sql(" AND activity.data ->> 'actor' = ")
- .bind::<Text, _>(community_actor_id)
- .sql(" ORDER BY activity.published DESC"),
- )
- .limit(20)
- .get_results(conn)?;
- Ok(res)
- }
}
#[cfg(test)]
- ./volumes/pictrs_alpha:/mnt
lemmy-alpha-ui:
- image: dessalines/lemmy-ui:dev
+ image: dessalines/lemmy-ui:0.13.3
environment:
- LEMMY_INTERNAL_HOST=lemmy-alpha:8541
- LEMMY_EXTERNAL_HOST=localhost:8541
- ./volumes/postgres_alpha:/var/lib/postgresql/data
lemmy-beta-ui:
- image: dessalines/lemmy-ui:dev
+ image: dessalines/lemmy-ui:0.13.3
environment:
- LEMMY_INTERNAL_HOST=lemmy-beta:8551
- LEMMY_EXTERNAL_HOST=localhost:8551