Breaking apub changes (#1859)
* Remove CommentInReplyToMigration * Remove compat for RemovePostCommentOrCommunity * Remove PublicUrlMigration * Change type of pm to ChatMessage from Pleroma, make pm.to array * Use person.summary instead of person.content for pleroma compat * Also change group.content to summary * Rewrite apub object test json to serve as nice examples * Also add test case for parsing pleroma private message
This commit is contained in:
parent
23731cd49c
commit
149a4e0de8
30 changed files with 287 additions and 385 deletions
|
@ -389,7 +389,6 @@ test('Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedde
|
||||||
|
|
||||||
test('Report a comment', async () => {
|
test('Report a comment', async () => {
|
||||||
let betaCommunity = (await resolveBetaCommunity(beta)).community;
|
let betaCommunity = (await resolveBetaCommunity(beta)).community;
|
||||||
console.log(betaCommunity);
|
|
||||||
let postRes = (await createPost(beta, betaCommunity.community.id)).post_view.post;
|
let postRes = (await createPost(beta, betaCommunity.community.id)).post_view.post;
|
||||||
expect(postRes).toBeDefined();
|
expect(postRes).toBeDefined();
|
||||||
let commentRes = (await createComment(beta, postRes.id)).comment_view.comment;
|
let commentRes = (await createComment(beta, postRes.id)).comment_view.comment;
|
||||||
|
|
|
@ -358,7 +358,6 @@ test('Enforce community ban for federated user', async () => {
|
||||||
|
|
||||||
test('Report a post', async () => {
|
test('Report a post', async () => {
|
||||||
let betaCommunity = (await resolveBetaCommunity(beta)).community;
|
let betaCommunity = (await resolveBetaCommunity(beta)).community;
|
||||||
console.log(betaCommunity);
|
|
||||||
let postRes = await createPost(beta, betaCommunity.community.id);
|
let postRes = await createPost(beta, betaCommunity.community.id);
|
||||||
expect(postRes.post_view.post).toBeDefined();
|
expect(postRes.post_view.post).toBeDefined();
|
||||||
|
|
||||||
|
|
|
@ -18,19 +18,17 @@
|
||||||
},
|
},
|
||||||
"https://w3id.org/security/v1"
|
"https://w3id.org/security/v1"
|
||||||
],
|
],
|
||||||
"attributedTo": "https://lemmy.ml/u/nutomic",
|
"id": "https://enterprise.lemmy.ml/comment/38741",
|
||||||
"content": "While I very much get and respect the general sentiment, I think from the perspective of a Central European non-English person in a country with a significant number of, also non-English speaking Nazis, the current approach of filtering slurs based on an English regex is fatally flawed. You can happily use Lemmy to create a hostile far right community where everyone is easily able to use whatever hurtful slurs they want as long as they are not the few specifically blocked English ones. \n\nOn the other hand you create a situation where people feel the need to question the choice of software of their community because they read about censorship or whatever to be used in Lemmy and might stay away and move to other software even though the would maybe never be affected by the slur-filter as the number is not so large and the overlap with other languages not very big.\n\nSo I would argue that this specific implementation of a slur-filter just doesn't achieve what it aims to achieve and should be fundamentally rethought, maybe as configurable per instance.",
|
"type": "Note",
|
||||||
"id": "https://lemmy.ml/comment/38741",
|
"attributedTo": "https://enterprise.lemmy.ml/u/picard",
|
||||||
"inReplyTo": [
|
"to": ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
"https://lemmy.ml/post/55143"
|
"inReplyTo": "https://enterprise.lemmy.ml/post/55143",
|
||||||
],
|
"content": "first comment!",
|
||||||
"mediaType": "text/html",
|
"mediaType": "text/html",
|
||||||
"published": "2021-03-01T13:42:43.966208+00:00",
|
|
||||||
"source": {
|
"source": {
|
||||||
"content": "While I very much get and respect the general sentiment, I think from the perspective of a Central European non-English person in a country with a significant number of, also non-English speaking Nazis, the current approach of filtering slurs based on an English regex is fatally flawed. You can happily use Lemmy to create a hostile far right community where everyone is easily able to use whatever hurtful slurs they want as long as they are not the few specifically blocked English ones. \n\nOn the other hand you create a situation where people feel the need to question the choice of software of their community because they read about censorship or whatever to be used in Lemmy and might stay away and move to other software even though the would maybe never be affected by the slur-filter as the number is not so large and the overlap with other languages not very big.\n\nSo I would argue that this specific implementation of a slur-filter just doesn't achieve what it aims to achieve and should be fundamentally rethought, maybe as configurable per instance.",
|
"content": "first comment!",
|
||||||
"mediaType": "text/markdown"
|
"mediaType": "text/markdown"
|
||||||
},
|
},
|
||||||
"to": ["https://www.w3.org/ns/activitystreams#Public"],
|
"published": "2021-03-01T13:42:43.966208+00:00",
|
||||||
"type": "Note",
|
|
||||||
"updated": "2021-03-01T13:43:03.955787+00:00"
|
"updated": "2021-03-01T13:43:03.955787+00:00"
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,33 +18,36 @@
|
||||||
},
|
},
|
||||||
"https://w3id.org/security/v1"
|
"https://w3id.org/security/v1"
|
||||||
],
|
],
|
||||||
"content": "<p>Lemmy Announcements</p>\n<hr />\n<p>Feel free to announce new communities here.</p>\n<p>Other than that, this is <em>reserved for admin use only</em>.</p>\n",
|
"id": "https://enterprise.lemmy.ml/c/tenforward",
|
||||||
"endpoints": {
|
"type": "Group",
|
||||||
"sharedInbox": "https://lemmy.ml/inbox"
|
"preferredUsername": "main",
|
||||||
|
"name": "Ten Forward",
|
||||||
|
"summary": "<p>Lounge and recreation facility</p>\n<hr />\n<p>Welcome to the <a href=\"https://memory-alpha.fandom.com/wiki/USS_Enterprise_(NCC-1701-D)\">Enterprise</a>!.</p>\n",
|
||||||
|
"source": {
|
||||||
|
"content": "Lounge and recreation facility\n\n---\n\nWelcome to the [Enterprise](https://memory-alpha.fandom.com/wiki/USS_Enterprise_(NCC-1701-D))!.",
|
||||||
|
"mediaType": "text/markdown"
|
||||||
},
|
},
|
||||||
"followers": "https://lemmy.ml/c/announcements/followers",
|
"sensitive": false,
|
||||||
"icon": {
|
"icon": {
|
||||||
"type": "Image",
|
"type": "Image",
|
||||||
"url": "https://lemmy.ml/pictrs/image/waqyZwLAy4.webp"
|
"url": "https://enterprise.lemmy.ml/pictrs/image/waqyZwLAy4.webp"
|
||||||
},
|
},
|
||||||
"id": "https://lemmy.ml/c/announcements",
|
"image": {
|
||||||
"inbox": "https://lemmy.ml/c/announcements/inbox",
|
"type": "Image",
|
||||||
"mediaType": "text/html",
|
"url": "https://enterprise.lemmy.ml/pictrs/image/Wt8zoMcCmE.jpg"
|
||||||
"moderators": "https://lemmy.ml/c/announcements/moderators",
|
},
|
||||||
"name": "Announcements",
|
"inbox": "https://enterprise.lemmy.ml/c/tenforward/inbox",
|
||||||
"outbox": "https://lemmy.ml/c/announcements/outbox",
|
"followers": "https://enterprise.lemmy.ml/c/tenforward/followers",
|
||||||
"preferredUsername": "announcements",
|
"moderators": "https://enterprise.lemmy.ml/c/tenforward/moderators",
|
||||||
|
"endpoints": {
|
||||||
|
"sharedInbox": "https://enterprise.lemmy.ml/inbox"
|
||||||
|
},
|
||||||
|
"outbox": "https://enterprise.lemmy.ml/c/tenforward/outbox",
|
||||||
"publicKey": {
|
"publicKey": {
|
||||||
"id": "https://lemmy.ml/c/announcements#main-key",
|
"id": "https://enterprise.lemmy.ml/c/tenforward#main-key",
|
||||||
"owner": "https://lemmy.ml/c/announcements",
|
"owner": "https://enterprise.lemmy.ml/c/tenforward",
|
||||||
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzRjKTNtvDCmugplwEh+g\nx1bhKm6BHUZfXfpscgMMm7tXFswSDzUQirMgfkxa9ubfr1PDFKffA2vQ9x6CyuO/\n70xTafdOHyV1tSqzgKz0ZvFZ/VCOo6qy1mYWVkrtBm/fKzM+87MdkKYB/zI4VyEJ\nLfLQgjwxBAEYUH3CBG71U0gO0TwbimWNN0vqlfp0QfThNe1WYObF88ZVzMLgFbr7\nRHBItZjlZ/d8foPDidlIR3l2dJjy0EsD8F9JM340jtX7LXqFmU4j1AQKNHTDLnUF\nwYVhzuQGNJ504l5LZkFG54XfIFT7dx2QwuuM9bSnfPv/98RYrq1Si6tCkxEt1cVe\n4wIDAQAB\n-----END PUBLIC KEY-----\n"
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzRjKTNtvDCmugplwEh+g\nx1bhKm6BHUZfXfpscgMMm7tXFswSDzUQirMgfkxa9ubfr1PDFKffA2vQ9x6CyuO/\n70xTafdOHyV1tSqzgKz0ZvFZ/VCOo6qy1mYWVkrtBm/fKzM+87MdkKYB/zI4VyEJ\nLfLQgjwxBAEYUH3CBG71U0gO0TwbimWNN0vqlfp0QfThNe1WYObF88ZVzMLgFbr7\nRHBItZjlZ/d8foPDidlIR3l2dJjy0EsD8F9JM340jtX7LXqFmU4j1AQKNHTDLnUF\nwYVhzuQGNJ504l5LZkFG54XfIFT7dx2QwuuM9bSnfPv/98RYrq1Si6tCkxEt1cVe\n4wIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||||
},
|
},
|
||||||
"published": "2019-06-02T16:43:50.799554+00:00",
|
"published": "2019-06-02T16:43:50.799554+00:00",
|
||||||
"sensitive": false,
|
|
||||||
"source": {
|
|
||||||
"content": "Lemmy Announcements\n\n---\n\nFeel free to announce new communities here.\n\nOther than that, this is *reserved for admin use only*.",
|
|
||||||
"mediaType": "text/markdown"
|
|
||||||
},
|
|
||||||
"type": "Group",
|
|
||||||
"updated": "2021-03-10T17:18:10.498868+00:00"
|
"updated": "2021-03-10T17:18:10.498868+00:00"
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,29 +18,33 @@
|
||||||
},
|
},
|
||||||
"https://w3id.org/security/v1"
|
"https://w3id.org/security/v1"
|
||||||
],
|
],
|
||||||
"content": "<p>Lemmy maintainer. Interested in politics, video games, and many other things.</p>\n",
|
"id": "https://enterprise.lemmy.ml/u/picard",
|
||||||
"endpoints": {
|
"type": "Person",
|
||||||
"sharedInbox": "https://lemmy.ml/inbox"
|
"preferredUsername": "picard",
|
||||||
|
"name": "Jean-Luc Picard",
|
||||||
|
"summary": "<p>Captain of the starship <strong>Enterprise</strong>.</p>\n",
|
||||||
|
"source": {
|
||||||
|
"content": "Captain of the starship **Enterprise**.",
|
||||||
|
"mediaType": "text/markdown"
|
||||||
},
|
},
|
||||||
"icon": {
|
"icon": {
|
||||||
"type": "Image",
|
"type": "Image",
|
||||||
"url": "https://lemmy.ml/pictrs/image/ed9ej7.jpg"
|
"url": "https://enterprise.lemmy.ml/pictrs/image/ed9ej7.jpg"
|
||||||
},
|
},
|
||||||
"id": "https://lemmy.ml/u/nutomic",
|
"image": {
|
||||||
"inbox": "https://lemmy.ml/u/nutomic/inbox",
|
"type": "Image",
|
||||||
"mediaType": "text/html",
|
"url": "https://enterprise.lemmy.ml/pictrs/image/XenaYI5hTn.png"
|
||||||
"outbox": "https://lemmy.ml/u/nutomic/outbox",
|
},
|
||||||
"preferredUsername": "nutomic",
|
"inbox": "https://enterprise.lemmy.ml/u/picard/inbox",
|
||||||
"publicKey": {
|
"outbox": "https://enterprise.lemmy.ml/u/picard/outbox",
|
||||||
"id": "https://lemmy.ml/u/nutomic#main-key",
|
"endpoints": {
|
||||||
"owner": "https://lemmy.ml/u/nutomic",
|
"sharedInbox": "https://enterprise.lemmy.ml/inbox"
|
||||||
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lP99/s5Vv+XbPdkeqIJ\nwoD4GFnHmBnBHdEKChEUWfWj1TtioC/rGNoXFQeXQA3Amhy4nxSceiDnUgwkkuQY\nv0MtIW58NzgknEavtllxL+LSds5pg3gANaDIk8UiWTkqXTg0GnlJMpCK1Chen0l/\nszL6DEvUyTSuS5ZYDXFgewF89Pe7U0S15V5U2Harv7AgJYDyxmUL0D1pGuUCRqcE\nl5MTHJjrXeNnH1w2g8aly8YlO/Cr0L51rFg/lBF23vni7ZLv8HbmWh6YpaAf1R8h\nE45zKR7OHqymdjzrg1ITBwovefpwMkVgnJ+Wdr4HPnFlBSkXPoZeM11+Z8L0anzA\nXwIDAQAB\n-----END PUBLIC KEY-----\n"
|
|
||||||
},
|
},
|
||||||
"published": "2020-01-17T01:38:22.348392+00:00",
|
"published": "2020-01-17T01:38:22.348392+00:00",
|
||||||
"source": {
|
"updated": "2021-08-13T00:11:15.941990+00:00",
|
||||||
"content": "Lemmy maintainer. Interested in politics, video games, and many other things.",
|
"publicKey": {
|
||||||
"mediaType": "text/markdown"
|
"id": "https://enterprise.lemmy.ml/u/picard#main-key",
|
||||||
},
|
"owner": "https://enterprise.lemmy.ml/u/picard",
|
||||||
"type": "Person",
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lP99/s5Vv+XbPdkeqIJ\nwoD4GFnHmBnBHdEKChEUWfWj1TtioC/rGNoXFQeXQA3Amhy4nxSceiDnUgwkkuQY\nv0MtIW58NzgknEavtllxL+LSds5pg3gANaDIk8UiWTkqXTg0GnlJMpCK1Chen0l/\nszL6DEvUyTSuS5ZYDXFgewF89Pe7U0S15V5U2Harv7AgJYDyxmUL0D1pGuUCRqcE\nl5MTHJjrXeNnH1w2g8aly8YlO/Cr0L51rFg/lBF23vni7ZLv8HbmWh6YpaAf1R8h\nE45zKR7OHqymdjzrg1ITBwovefpwMkVgnJ+Wdr4HPnFlBSkXPoZeM11+Z8L0anzA\nXwIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||||
"updated": "2021-08-13T00:11:15.941990+00:00"
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,22 +18,22 @@
|
||||||
},
|
},
|
||||||
"https://w3id.org/security/v1"
|
"https://w3id.org/security/v1"
|
||||||
],
|
],
|
||||||
"attributedTo": "https://lemmy.ml/u/nutomic",
|
"id": "https://enterprise.lemmy.ml/post/55143",
|
||||||
"commentsEnabled": true,
|
"type": "Page",
|
||||||
"content": "<p>Recently there have been some discussions about the political stances of the Lemmy developers and site admins. To clear up some misconceptions: Lemmy is run by a team of people with different ideologies, including anti-capitalist, communist, anarchist, and others. While @dessalines and I are communists, we take decisions collectively, and don't demand that anyone adopt our views or convert to our ideologies. We wouldn't devote so much time to building a federated site otherwise.</p>\n<p>What's important to us is that you follow the site rules and <a href=\"https://join.lemmy.ml/docs/en/code_of_conduct.html\">Code of Conduct</a>. Meaning primarily, no-bigotry, and being respectful towards others. As long as that is the case, we can get along perfectly fine.</p>\n<p>In general we are open for constructive feedback, so please contact any member of the admin team if you have an idea how to improve Lemmy.</p>\n<h2>Slur Filter</h2>\n<p>We also noticed a consistent criticism of the built-in slur filter in Lemmy. Not so much on lemmy.ml itself, but whenever Lemmy is recommended elsewhere, a few usual suspects keep bringing it up. To these people we say the following: we are using the slur filter as a tool to keep a friendly atmosphere, and prevent racists, sexists and other bigots from using Lemmy. Its existence alone has lead many of them to not make an account, or run an instance: a clear net positive.</p>\n<p>You can see for yourself the words which are blocked (content warning, <a href=\"https://github.com/LemmyNet/lemmy/blob/main/crates/utils/src/utils.rs#L10\">link here</a>). Note that it doesn't include any simple swear words, but only slurs which are used to insult and attack other people. If you want to use any of these words, then please stay on one of the many platforms that permit them. Lemmy is not for you, and we don't want you here.</p>\n<p>We are fully aware that the slur filter is not perfect. It is made for American English, and can give false positives in other languages or dialects. We are totally willing to fix such problems on a case by case basis, simply open an issue in our <a href=\"https://github.com/LemmyNet/lemmy/issues\">repo </a>with a description of the problem.</p>\n",
|
"attributedTo": "https://enterprise.lemmy.ml/u/picard",
|
||||||
"id": "https://lemmy.ml/post/55143",
|
|
||||||
"mediaType": "text/html",
|
|
||||||
"name": "Statement on Politics of Lemmy.ml",
|
|
||||||
"published": "2021-02-26T12:35:34.292626+00:00",
|
|
||||||
"sensitive": false,
|
|
||||||
"source": {
|
|
||||||
"content": "Recently there have been some discussions about the political stances of the Lemmy developers and site admins. To clear up some misconceptions: Lemmy is run by a team of people with different ideologies, including anti-capitalist, communist, anarchist, and others. While @dessalines and I are communists, we take decisions collectively, and don't demand that anyone adopt our views or convert to our ideologies. We wouldn't devote so much time to building a federated site otherwise.\n\nWhat's important to us is that you follow the site rules and [Code of Conduct](https://join.lemmy.ml/docs/en/code_of_conduct.html). Meaning primarily, no-bigotry, and being respectful towards others. As long as that is the case, we can get along perfectly fine.\n\nIn general we are open for constructive feedback, so please contact any member of the admin team if you have an idea how to improve Lemmy. \n\n## Slur Filter\n\nWe also noticed a consistent criticism of the built-in slur filter in Lemmy. Not so much on lemmy.ml itself, but whenever Lemmy is recommended elsewhere, a few usual suspects keep bringing it up. To these people we say the following: we are using the slur filter as a tool to keep a friendly atmosphere, and prevent racists, sexists and other bigots from using Lemmy. Its existence alone has lead many of them to not make an account, or run an instance: a clear net positive.\n\nYou can see for yourself the words which are blocked (content warning, [link here](https://github.com/LemmyNet/lemmy/blob/main/crates/utils/src/utils.rs#L10)). Note that it doesn't include any simple swear words, but only slurs which are used to insult and attack other people. If you want to use any of these words, then please stay on one of the many platforms that permit them. Lemmy is not for you, and we don't want you here.\n\nWe are fully aware that the slur filter is not perfect. It is made for American English, and can give false positives in other languages or dialects. We are totally willing to fix such problems on a case by case basis, simply open an issue in our [repo ](https://github.com/LemmyNet/lemmy/issues)with a description of the problem.",
|
|
||||||
"mediaType": "text/markdown"
|
|
||||||
},
|
|
||||||
"stickied": true,
|
|
||||||
"to": [
|
"to": [
|
||||||
"https://lemmy.ml/c/announcements",
|
"https://enterprise.lemmy.ml/c/tenforward",
|
||||||
"https://www.w3.org/ns/activitystreams#Public"
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
],
|
],
|
||||||
"type": "Page"
|
"name": "Post title",
|
||||||
|
"content": "<p>This is a post in the /c/tenforward community</p>\n",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"source": {
|
||||||
|
"content": "This is a post in the /c/tenforward community",
|
||||||
|
"mediaType": "text/markdown"
|
||||||
|
},
|
||||||
|
"sensitive": false,
|
||||||
|
"commentsEnabled": true,
|
||||||
|
"stickied": true,
|
||||||
|
"published": "2021-02-26T12:35:34.292626+00:00"
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,15 +18,17 @@
|
||||||
},
|
},
|
||||||
"https://w3id.org/security/v1"
|
"https://w3id.org/security/v1"
|
||||||
],
|
],
|
||||||
"attributedTo": "https://lemmy.ml/u/nutomic",
|
"id": "https://enterprise.lemmy.ml/private_message/1621",
|
||||||
"content": "test",
|
"type": "ChatMessage",
|
||||||
"id": "https://lemmy.ml/private_message/1621",
|
"attributedTo": "https://enterprise.lemmy.ml/u/picard",
|
||||||
|
"to": [
|
||||||
|
"https://queer.hacktivis.me/users/lanodan"
|
||||||
|
],
|
||||||
|
"content": "Hello hello, testing",
|
||||||
"mediaType": "text/html",
|
"mediaType": "text/html",
|
||||||
"published": "2021-10-21T10:13:14.597721+00:00",
|
|
||||||
"source": {
|
"source": {
|
||||||
"content": "test",
|
"content": "Hello hello, testing",
|
||||||
"mediaType": "text/markdown"
|
"mediaType": "text/markdown"
|
||||||
},
|
},
|
||||||
"to": "https://queer.hacktivis.me/users/lanodan",
|
"published": "2021-10-21T10:13:14.597721+00:00"
|
||||||
"type": "Note"
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"context": "https://queer.hacktivis.me/contexts/34cba3d2-2f35-4169-aeff-56af9bfeb753",
|
"context": "https://queer.hacktivis.me/contexts/34cba3d2-2f35-4169-aeff-56af9bfeb753",
|
||||||
"conversation": "https://queer.hacktivis.me/contexts/34cba3d2-2f35-4169-aeff-56af9bfeb753",
|
"conversation": "https://queer.hacktivis.me/contexts/34cba3d2-2f35-4169-aeff-56af9bfeb753",
|
||||||
"id": "https://queer.hacktivis.me/objects/8d4973f4-53de-49cd-8c27-df160e16a9c2",
|
"id": "https://queer.hacktivis.me/objects/8d4973f4-53de-49cd-8c27-df160e16a9c2",
|
||||||
"inReplyTo": "https://lemmy.ml/post/55143",
|
"inReplyTo": "https://enterprise.lemmy.ml/post/55143",
|
||||||
"published": "2021-10-07T18:06:52.555500Z",
|
"published": "2021-10-07T18:06:52.555500Z",
|
||||||
"sensitive": null,
|
"sensitive": null,
|
||||||
"source": "@popolon@pleroma.popolon.org Have what?",
|
"source": "@popolon@pleroma.popolon.org Have what?",
|
||||||
|
|
17
crates/apub/assets/pleroma-private-message.json
Normal file
17
crates/apub/assets/pleroma-private-message.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://queer.hacktivis.me/schemas/litepub-0.1.jsonld",
|
||||||
|
{
|
||||||
|
"@language": "und"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"attributedTo": "https://queer.hacktivis.me/users/lanodan",
|
||||||
|
"content": "Hi!",
|
||||||
|
"id": "https://queer.hacktivis.me/objects/2",
|
||||||
|
"published": "2020-02-12T14:08:20Z",
|
||||||
|
"to": [
|
||||||
|
"https://enterprise.lemmy.ml/u/picard"
|
||||||
|
],
|
||||||
|
"type": "ChatMessage"
|
||||||
|
}
|
|
@ -11,7 +11,6 @@ use crate::{
|
||||||
},
|
},
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{
|
objects::{
|
||||||
comment::{ApubComment, Note},
|
comment::{ApubComment, Note},
|
||||||
community::ApubCommunity,
|
community::ApubCommunity,
|
||||||
|
@ -23,6 +22,7 @@ use lemmy_api_common::{blocking, check_post_deleted_or_removed};
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType, FromApub, ToApub},
|
traits::{ActivityFields, ActivityHandler, ActorType, FromApub, ToApub},
|
||||||
|
values::PublicUrl,
|
||||||
verify::verify_domains_match,
|
verify::verify_domains_match,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -38,7 +38,7 @@ use url::Url;
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CreateOrUpdateComment {
|
pub struct CreateOrUpdateComment {
|
||||||
actor: ObjectId<ApubPerson>,
|
actor: ObjectId<ApubPerson>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
object: Note,
|
object: Note,
|
||||||
cc: Vec<Url>,
|
cc: Vec<Url>,
|
||||||
tag: Vec<Mention>,
|
tag: Vec<Mention>,
|
||||||
|
@ -76,7 +76,7 @@ impl CreateOrUpdateComment {
|
||||||
|
|
||||||
let create_or_update = CreateOrUpdateComment {
|
let create_or_update = CreateOrUpdateComment {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object: comment.to_apub(context.pool()).await?,
|
object: comment.to_apub(context.pool()).await?,
|
||||||
cc: maa.ccs,
|
cc: maa.ccs,
|
||||||
tag: maa.tags,
|
tag: maa.tags,
|
||||||
|
|
|
@ -10,7 +10,6 @@ use crate::{
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
generate_moderators_url,
|
generate_moderators_url,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
|
@ -23,6 +22,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType},
|
traits::{ActivityFields, ActivityHandler, ActorType},
|
||||||
|
values::PublicUrl,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::community::{CommunityModerator, CommunityModeratorForm},
|
source::community::{CommunityModerator, CommunityModeratorForm},
|
||||||
|
@ -37,7 +37,7 @@ use url::Url;
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AddMod {
|
pub struct AddMod {
|
||||||
actor: ObjectId<ApubPerson>,
|
actor: ObjectId<ApubPerson>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
object: ObjectId<ApubPerson>,
|
object: ObjectId<ApubPerson>,
|
||||||
target: Url,
|
target: Url,
|
||||||
cc: [ObjectId<ApubCommunity>; 1],
|
cc: [ObjectId<ApubCommunity>; 1],
|
||||||
|
@ -63,7 +63,7 @@ impl AddMod {
|
||||||
)?;
|
)?;
|
||||||
let add = AddMod {
|
let add = AddMod {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object: ObjectId::new(added_mod.actor_id()),
|
object: ObjectId::new(added_mod.actor_id()),
|
||||||
target: generate_moderators_url(&community.actor_id)?.into(),
|
target: generate_moderators_url(&community.actor_id)?.into(),
|
||||||
cc: [ObjectId::new(community.actor_id())],
|
cc: [ObjectId::new(community.actor_id())],
|
||||||
|
|
|
@ -12,7 +12,6 @@ use crate::{
|
||||||
deletion::{delete::Delete, undo_delete::UndoDelete},
|
deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
post::create_or_update::CreateOrUpdatePost,
|
post::create_or_update::CreateOrUpdatePost,
|
||||||
undo_remove::UndoRemovePostCommentOrCommunity,
|
|
||||||
verify_activity,
|
verify_activity,
|
||||||
verify_community,
|
verify_community,
|
||||||
voting::{undo_vote::UndoVote, vote::Vote},
|
voting::{undo_vote::UndoVote, vote::Vote},
|
||||||
|
@ -21,7 +20,6 @@ use crate::{
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
http::is_activity_already_known,
|
http::is_activity_already_known,
|
||||||
insert_activity,
|
insert_activity,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::community::ApubCommunity,
|
objects::community::ApubCommunity,
|
||||||
send_lemmy_activity,
|
send_lemmy_activity,
|
||||||
CommunityType,
|
CommunityType,
|
||||||
|
@ -35,6 +33,7 @@ use activitystreams::{
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType},
|
traits::{ActivityFields, ActivityHandler, ActorType},
|
||||||
|
values::PublicUrl,
|
||||||
};
|
};
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
|
@ -51,7 +50,6 @@ pub enum AnnouncableActivities {
|
||||||
UndoVote(UndoVote),
|
UndoVote(UndoVote),
|
||||||
Delete(Delete),
|
Delete(Delete),
|
||||||
UndoDelete(UndoDelete),
|
UndoDelete(UndoDelete),
|
||||||
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
|
|
||||||
UpdateCommunity(Box<UpdateCommunity>),
|
UpdateCommunity(Box<UpdateCommunity>),
|
||||||
BlockUserFromCommunity(BlockUserFromCommunity),
|
BlockUserFromCommunity(BlockUserFromCommunity),
|
||||||
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
|
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
|
||||||
|
@ -63,7 +61,7 @@ pub enum AnnouncableActivities {
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AnnounceActivity {
|
pub struct AnnounceActivity {
|
||||||
actor: ObjectId<ApubCommunity>,
|
actor: ObjectId<ApubCommunity>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
object: AnnouncableActivities,
|
object: AnnouncableActivities,
|
||||||
cc: Vec<Url>,
|
cc: Vec<Url>,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -84,7 +82,7 @@ impl AnnounceActivity {
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let announce = AnnounceActivity {
|
let announce = AnnounceActivity {
|
||||||
actor: ObjectId::new(community.actor_id()),
|
actor: ObjectId::new(community.actor_id()),
|
||||||
to: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object,
|
object,
|
||||||
cc: vec![community.followers_url()],
|
cc: vec![community.followers_url()],
|
||||||
kind: AnnounceType::Announce,
|
kind: AnnounceType::Announce,
|
||||||
|
|
|
@ -8,7 +8,6 @@ use crate::{
|
||||||
},
|
},
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
|
@ -21,6 +20,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType},
|
traits::{ActivityFields, ActivityHandler, ActorType},
|
||||||
|
values::PublicUrl,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::community::{
|
source::community::{
|
||||||
|
@ -40,7 +40,7 @@ use url::Url;
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct BlockUserFromCommunity {
|
pub struct BlockUserFromCommunity {
|
||||||
actor: ObjectId<ApubPerson>,
|
actor: ObjectId<ApubPerson>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
pub(in crate::activities::community) object: ObjectId<ApubPerson>,
|
pub(in crate::activities::community) object: ObjectId<ApubPerson>,
|
||||||
cc: [ObjectId<ApubCommunity>; 1],
|
cc: [ObjectId<ApubCommunity>; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -61,7 +61,7 @@ impl BlockUserFromCommunity {
|
||||||
) -> Result<BlockUserFromCommunity, LemmyError> {
|
) -> Result<BlockUserFromCommunity, LemmyError> {
|
||||||
Ok(BlockUserFromCommunity {
|
Ok(BlockUserFromCommunity {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object: ObjectId::new(target.actor_id()),
|
object: ObjectId::new(target.actor_id()),
|
||||||
cc: [ObjectId::new(community.actor_id())],
|
cc: [ObjectId::new(community.actor_id())],
|
||||||
kind: BlockType::Block,
|
kind: BlockType::Block,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
community::{announce::AnnouncableActivities, send_to_community},
|
community::{announce::AnnouncableActivities, send_to_community},
|
||||||
deletion::{delete::receive_remove_action, verify_delete_activity},
|
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
verify_activity,
|
verify_activity,
|
||||||
verify_add_remove_moderator_target,
|
verify_add_remove_moderator_target,
|
||||||
|
@ -11,7 +10,6 @@ use crate::{
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
generate_moderators_url,
|
generate_moderators_url,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
|
@ -24,6 +22,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType},
|
traits::{ActivityFields, ActivityHandler, ActorType},
|
||||||
|
values::PublicUrl,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::community::{CommunityModerator, CommunityModeratorForm},
|
source::community::{CommunityModerator, CommunityModeratorForm},
|
||||||
|
@ -38,13 +37,13 @@ use url::Url;
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RemoveMod {
|
pub struct RemoveMod {
|
||||||
actor: ObjectId<ApubPerson>,
|
actor: ObjectId<ApubPerson>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
pub(in crate::activities) object: ObjectId<ApubPerson>,
|
pub(in crate::activities) object: ObjectId<ApubPerson>,
|
||||||
cc: [ObjectId<ApubCommunity>; 1],
|
cc: [ObjectId<ApubCommunity>; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
kind: RemoveType,
|
kind: RemoveType,
|
||||||
// if target is set, this is means remove mod from community
|
// if target is set, this is means remove mod from community
|
||||||
pub(in crate::activities) target: Option<Url>,
|
pub(in crate::activities) target: Url,
|
||||||
id: Url,
|
id: Url,
|
||||||
#[serde(rename = "@context")]
|
#[serde(rename = "@context")]
|
||||||
context: OneOrMany<AnyBase>,
|
context: OneOrMany<AnyBase>,
|
||||||
|
@ -65,9 +64,9 @@ impl RemoveMod {
|
||||||
)?;
|
)?;
|
||||||
let remove = RemoveMod {
|
let remove = RemoveMod {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object: ObjectId::new(removed_mod.actor_id()),
|
object: ObjectId::new(removed_mod.actor_id()),
|
||||||
target: Some(generate_moderators_url(&community.actor_id)?.into()),
|
target: generate_moderators_url(&community.actor_id)?.into(),
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
context: lemmy_context(),
|
context: lemmy_context(),
|
||||||
cc: [ObjectId::new(community.actor_id())],
|
cc: [ObjectId::new(community.actor_id())],
|
||||||
|
@ -90,21 +89,9 @@ impl ActivityHandler for RemoveMod {
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
verify_activity(self, &context.settings())?;
|
verify_activity(self, &context.settings())?;
|
||||||
if let Some(target) = &self.target {
|
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
|
||||||
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
|
verify_mod_action(&self.actor, &self.cc[0], context, request_counter).await?;
|
||||||
verify_mod_action(&self.actor, &self.cc[0], context, request_counter).await?;
|
verify_add_remove_moderator_target(&self.target, &self.cc[0])?;
|
||||||
verify_add_remove_moderator_target(target, &self.cc[0])?;
|
|
||||||
} else {
|
|
||||||
verify_delete_activity(
|
|
||||||
self.object.inner(),
|
|
||||||
self,
|
|
||||||
&self.cc[0],
|
|
||||||
true,
|
|
||||||
context,
|
|
||||||
request_counter,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,29 +100,18 @@ impl ActivityHandler for RemoveMod {
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
if self.target.is_some() {
|
let community = self.cc[0].dereference(context, request_counter).await?;
|
||||||
let community = self.cc[0].dereference(context, request_counter).await?;
|
let remove_mod = self.object.dereference(context, request_counter).await?;
|
||||||
let remove_mod = self.object.dereference(context, request_counter).await?;
|
|
||||||
|
|
||||||
let form = CommunityModeratorForm {
|
let form = CommunityModeratorForm {
|
||||||
community_id: community.id,
|
community_id: community.id,
|
||||||
person_id: remove_mod.id,
|
person_id: remove_mod.id,
|
||||||
};
|
};
|
||||||
blocking(context.pool(), move |conn| {
|
blocking(context.pool(), move |conn| {
|
||||||
CommunityModerator::leave(conn, &form)
|
CommunityModerator::leave(conn, &form)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
// TODO: send websocket notification about removed mod
|
// TODO: send websocket notification about removed mod
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
receive_remove_action(
|
|
||||||
&self.actor,
|
|
||||||
self.object.inner(),
|
|
||||||
None,
|
|
||||||
context,
|
|
||||||
request_counter,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ use crate::{
|
||||||
},
|
},
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
|
@ -25,6 +24,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType},
|
traits::{ActivityFields, ActivityHandler, ActorType},
|
||||||
|
values::PublicUrl,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::community::{CommunityPersonBan, CommunityPersonBanForm},
|
source::community::{CommunityPersonBan, CommunityPersonBanForm},
|
||||||
|
@ -39,7 +39,7 @@ use url::Url;
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UndoBlockUserFromCommunity {
|
pub struct UndoBlockUserFromCommunity {
|
||||||
actor: ObjectId<ApubPerson>,
|
actor: ObjectId<ApubPerson>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
object: BlockUserFromCommunity,
|
object: BlockUserFromCommunity,
|
||||||
cc: [ObjectId<ApubCommunity>; 1],
|
cc: [ObjectId<ApubCommunity>; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -66,7 +66,7 @@ impl UndoBlockUserFromCommunity {
|
||||||
)?;
|
)?;
|
||||||
let undo = UndoBlockUserFromCommunity {
|
let undo = UndoBlockUserFromCommunity {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object: block,
|
object: block,
|
||||||
cc: [ObjectId::new(community.actor_id())],
|
cc: [ObjectId::new(community.actor_id())],
|
||||||
kind: UndoType::Undo,
|
kind: UndoType::Undo,
|
||||||
|
|
|
@ -8,7 +8,6 @@ use crate::{
|
||||||
},
|
},
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{
|
objects::{
|
||||||
community::{ApubCommunity, Group},
|
community::{ApubCommunity, Group},
|
||||||
person::ApubPerson,
|
person::ApubPerson,
|
||||||
|
@ -24,6 +23,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType, ToApub},
|
traits::{ActivityFields, ActivityHandler, ActorType, ToApub},
|
||||||
|
values::PublicUrl,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::community::{Community, CommunityForm},
|
source::community::{Community, CommunityForm},
|
||||||
|
@ -40,7 +40,7 @@ use url::Url;
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UpdateCommunity {
|
pub struct UpdateCommunity {
|
||||||
actor: ObjectId<ApubPerson>,
|
actor: ObjectId<ApubPerson>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
// TODO: would be nice to use a separate struct here, which only contains the fields updated here
|
// TODO: would be nice to use a separate struct here, which only contains the fields updated here
|
||||||
object: Group,
|
object: Group,
|
||||||
cc: [ObjectId<ApubCommunity>; 1],
|
cc: [ObjectId<ApubCommunity>; 1],
|
||||||
|
@ -65,7 +65,7 @@ impl UpdateCommunity {
|
||||||
)?;
|
)?;
|
||||||
let update = UpdateCommunity {
|
let update = UpdateCommunity {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object: community.to_apub(context.pool()).await?,
|
object: community.to_apub(context.pool()).await?,
|
||||||
cc: [ObjectId::new(community.actor_id())],
|
cc: [ObjectId::new(community.actor_id())],
|
||||||
kind: UpdateType::Update,
|
kind: UpdateType::Update,
|
||||||
|
|
|
@ -12,7 +12,6 @@ use crate::{
|
||||||
},
|
},
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
|
@ -26,6 +25,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType},
|
traits::{ActivityFields, ActivityHandler, ActorType},
|
||||||
|
values::PublicUrl,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
|
@ -66,7 +66,7 @@ use url::Url;
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Delete {
|
pub struct Delete {
|
||||||
actor: ObjectId<ApubPerson>,
|
actor: ObjectId<ApubPerson>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
pub(in crate::activities::deletion) object: Url,
|
pub(in crate::activities::deletion) object: Url,
|
||||||
pub(in crate::activities::deletion) cc: [ObjectId<ApubCommunity>; 1],
|
pub(in crate::activities::deletion) cc: [ObjectId<ApubCommunity>; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -144,7 +144,7 @@ impl Delete {
|
||||||
) -> Result<Delete, LemmyError> {
|
) -> Result<Delete, LemmyError> {
|
||||||
Ok(Delete {
|
Ok(Delete {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object: object_id,
|
object: object_id,
|
||||||
cc: [ObjectId::new(community.actor_id())],
|
cc: [ObjectId::new(community.actor_id())],
|
||||||
kind: DeleteType::Delete,
|
kind: DeleteType::Delete,
|
||||||
|
|
|
@ -13,7 +13,6 @@ use crate::{
|
||||||
},
|
},
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
|
@ -27,6 +26,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType},
|
traits::{ActivityFields, ActivityHandler, ActorType},
|
||||||
|
values::PublicUrl,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
|
use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
|
@ -42,7 +42,7 @@ use url::Url;
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UndoDelete {
|
pub struct UndoDelete {
|
||||||
actor: ObjectId<ApubPerson>,
|
actor: ObjectId<ApubPerson>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
object: Delete,
|
object: Delete,
|
||||||
cc: [ObjectId<ApubCommunity>; 1],
|
cc: [ObjectId<ApubCommunity>; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -117,7 +117,7 @@ impl UndoDelete {
|
||||||
)?;
|
)?;
|
||||||
let undo = UndoDelete {
|
let undo = UndoDelete {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object,
|
object,
|
||||||
cc: [ObjectId::new(community.actor_id())],
|
cc: [ObjectId::new(community.actor_id())],
|
||||||
kind: UndoType::Undo,
|
kind: UndoType::Undo,
|
||||||
|
|
|
@ -26,7 +26,6 @@ pub mod following;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
pub mod private_message;
|
pub mod private_message;
|
||||||
pub mod report;
|
pub mod report;
|
||||||
pub mod undo_remove;
|
|
||||||
pub mod voting;
|
pub mod voting;
|
||||||
|
|
||||||
#[derive(Clone, Debug, ToString, Deserialize, Serialize)]
|
#[derive(Clone, Debug, ToString, Deserialize, Serialize)]
|
||||||
|
|
|
@ -10,7 +10,6 @@ use crate::{
|
||||||
},
|
},
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{
|
objects::{
|
||||||
community::ApubCommunity,
|
community::ApubCommunity,
|
||||||
person::ApubPerson,
|
person::ApubPerson,
|
||||||
|
@ -23,6 +22,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType, FromApub, ToApub},
|
traits::{ActivityFields, ActivityHandler, ActorType, FromApub, ToApub},
|
||||||
|
values::PublicUrl,
|
||||||
verify::{verify_domains_match, verify_urls_match},
|
verify::{verify_domains_match, verify_urls_match},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{source::community::Community, traits::Crud};
|
use lemmy_db_schema::{source::community::Community, traits::Crud};
|
||||||
|
@ -35,7 +35,7 @@ use url::Url;
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CreateOrUpdatePost {
|
pub struct CreateOrUpdatePost {
|
||||||
actor: ObjectId<ApubPerson>,
|
actor: ObjectId<ApubPerson>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
object: Page,
|
object: Page,
|
||||||
cc: [ObjectId<ApubCommunity>; 1],
|
cc: [ObjectId<ApubCommunity>; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -67,7 +67,7 @@ impl CreateOrUpdatePost {
|
||||||
)?;
|
)?;
|
||||||
let create_or_update = CreateOrUpdatePost {
|
let create_or_update = CreateOrUpdatePost {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object: post.to_apub(context.pool()).await?,
|
object: post.to_apub(context.pool()).await?,
|
||||||
cc: [ObjectId::new(community.actor_id())],
|
cc: [ObjectId::new(community.actor_id())],
|
||||||
kind,
|
kind,
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
use crate::{
|
|
||||||
activities::{
|
|
||||||
community::remove_mod::RemoveMod,
|
|
||||||
deletion::{undo_delete::UndoDelete, verify_delete_activity},
|
|
||||||
verify_activity,
|
|
||||||
},
|
|
||||||
fetcher::object_id::ObjectId,
|
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
|
||||||
};
|
|
||||||
use activitystreams::{
|
|
||||||
activity::kind::UndoType,
|
|
||||||
base::AnyBase,
|
|
||||||
primitives::OneOrMany,
|
|
||||||
unparsed::Unparsed,
|
|
||||||
};
|
|
||||||
use lemmy_apub_lib::{
|
|
||||||
data::Data,
|
|
||||||
traits::{ActivityFields, ActivityHandler},
|
|
||||||
};
|
|
||||||
use lemmy_utils::LemmyError;
|
|
||||||
use lemmy_websocket::LemmyContext;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct UndoRemovePostCommentOrCommunity {
|
|
||||||
actor: ObjectId<ApubPerson>,
|
|
||||||
to: PublicUrlMigration,
|
|
||||||
// Note, there is no such thing as Undo/Remove/Mod, so we ignore that
|
|
||||||
object: RemoveMod,
|
|
||||||
cc: [ObjectId<ApubCommunity>; 1],
|
|
||||||
#[serde(rename = "type")]
|
|
||||||
kind: UndoType,
|
|
||||||
id: Url,
|
|
||||||
#[serde(rename = "@context")]
|
|
||||||
context: OneOrMany<AnyBase>,
|
|
||||||
#[serde(flatten)]
|
|
||||||
unparsed: Unparsed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
impl ActivityHandler for UndoRemovePostCommentOrCommunity {
|
|
||||||
type DataType = LemmyContext;
|
|
||||||
async fn verify(
|
|
||||||
&self,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
request_counter: &mut i32,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
verify_activity(self, &context.settings())?;
|
|
||||||
self.object.verify(context, request_counter).await?;
|
|
||||||
|
|
||||||
verify_delete_activity(
|
|
||||||
self.object.object.inner(),
|
|
||||||
self,
|
|
||||||
&self.cc[0],
|
|
||||||
true,
|
|
||||||
context,
|
|
||||||
request_counter,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn receive(
|
|
||||||
self,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
_request_counter: &mut i32,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
UndoDelete::receive_undo_remove_action(self.object.object.inner(), context).await
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,7 +12,6 @@ use crate::{
|
||||||
},
|
},
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
PostOrComment,
|
PostOrComment,
|
||||||
};
|
};
|
||||||
|
@ -26,6 +25,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType},
|
traits::{ActivityFields, ActivityHandler, ActorType},
|
||||||
|
values::PublicUrl,
|
||||||
verify::verify_urls_match,
|
verify::verify_urls_match,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{newtypes::CommunityId, source::community::Community, traits::Crud};
|
use lemmy_db_schema::{newtypes::CommunityId, source::community::Community, traits::Crud};
|
||||||
|
@ -39,7 +39,7 @@ use url::Url;
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UndoVote {
|
pub struct UndoVote {
|
||||||
actor: ObjectId<ApubPerson>,
|
actor: ObjectId<ApubPerson>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
object: Vote,
|
object: Vote,
|
||||||
cc: [ObjectId<ApubCommunity>; 1],
|
cc: [ObjectId<ApubCommunity>; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -72,7 +72,7 @@ impl UndoVote {
|
||||||
)?;
|
)?;
|
||||||
let undo_vote = UndoVote {
|
let undo_vote = UndoVote {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(actor.actor_id()),
|
||||||
to: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object,
|
object,
|
||||||
cc: [ObjectId::new(community.actor_id())],
|
cc: [ObjectId::new(community.actor_id())],
|
||||||
kind: UndoType::Undo,
|
kind: UndoType::Undo,
|
||||||
|
|
|
@ -8,7 +8,6 @@ use crate::{
|
||||||
},
|
},
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
migrations::PublicUrlMigration,
|
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
PostOrComment,
|
PostOrComment,
|
||||||
};
|
};
|
||||||
|
@ -18,6 +17,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
data::Data,
|
data::Data,
|
||||||
traits::{ActivityFields, ActivityHandler, ActorType},
|
traits::{ActivityFields, ActivityHandler, ActorType},
|
||||||
|
values::PublicUrl,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{newtypes::CommunityId, source::community::Community, traits::Crud};
|
use lemmy_db_schema::{newtypes::CommunityId, source::community::Community, traits::Crud};
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
|
@ -58,7 +58,7 @@ impl From<&VoteType> for i16 {
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Vote {
|
pub struct Vote {
|
||||||
actor: ObjectId<ApubPerson>,
|
actor: ObjectId<ApubPerson>,
|
||||||
to: PublicUrlMigration,
|
to: [PublicUrl; 1],
|
||||||
pub(in crate::activities::voting) object: ObjectId<PostOrComment>,
|
pub(in crate::activities::voting) object: ObjectId<PostOrComment>,
|
||||||
cc: [ObjectId<ApubCommunity>; 1],
|
cc: [ObjectId<ApubCommunity>; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -80,7 +80,7 @@ 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: PublicUrlMigration::create(),
|
to: [PublicUrl::Public],
|
||||||
object: ObjectId::new(object.ap_id()),
|
object: ObjectId::new(object.ap_id()),
|
||||||
cc: [ObjectId::new(community.actor_id())],
|
cc: [ObjectId::new(community.actor_id())],
|
||||||
kind: kind.clone(),
|
kind: kind.clone(),
|
||||||
|
|
|
@ -1,49 +1 @@
|
||||||
use crate::fetcher::{object_id::ObjectId, post_or_comment::PostOrComment};
|
|
||||||
use lemmy_apub_lib::values::PublicUrl;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
/// Migrate comment.in_reply_to field from containing post and parent comment ID, to only containing
|
|
||||||
/// the direct parent (whether its a post or comment). This is for compatibility with Pleroma and
|
|
||||||
/// Smithereen.
|
|
||||||
/// [https://github.com/LemmyNet/lemmy/issues/1454]
|
|
||||||
///
|
|
||||||
/// v0.12: receive both, send old (compatible with v0.11)
|
|
||||||
/// v0.13 receive both, send new (compatible with v0.12+, incompatible with v0.11)
|
|
||||||
/// v0.14: only send and receive new, remove migration (compatible with v0.13+)
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum CommentInReplyToMigration {
|
|
||||||
Old(Vec<Url>),
|
|
||||||
New(ObjectId<PostOrComment>),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Another migration we are doing is to handle all deletions and removals using Delete activity.
|
|
||||||
// This is because Remove is for removing an object from a collection, so using it that way doesn't
|
|
||||||
// really make sense. It is also a problem because we have a RemoveMod activity, which was awkward
|
|
||||||
// to handle together with removing posts etc.
|
|
||||||
//
|
|
||||||
// v0.11: send and receive mod removals as Remove
|
|
||||||
// v0.12: receive removals as Remove, send as Delete (compatible with v0.11)
|
|
||||||
// v0.13: send and receive mod removals as Delete (compatible with v0.12)
|
|
||||||
//
|
|
||||||
// For v0.13, delete [`UndoRemovePostCommentOrCommunity`], and don't handle object deletion in
|
|
||||||
// [`RemoveMod`] handler.
|
|
||||||
|
|
||||||
/// Migrate value of field `to` from single value to vec.
|
|
||||||
///
|
|
||||||
/// v0.14: send as single value, accept both
|
|
||||||
/// v0.15: send as vec, accept both
|
|
||||||
/// v0.16: send and accept only vec
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum PublicUrlMigration {
|
|
||||||
Old(PublicUrl),
|
|
||||||
New([PublicUrl; 1]),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PublicUrlMigration {
|
|
||||||
pub(crate) fn create() -> PublicUrlMigration {
|
|
||||||
PublicUrlMigration::Old(PublicUrl::Public)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ use crate::{
|
||||||
activities::{verify_is_public, verify_person_in_community},
|
activities::{verify_is_public, verify_person_in_community},
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
fetcher::object_id::ObjectId,
|
fetcher::object_id::ObjectId,
|
||||||
migrations::CommentInReplyToMigration,
|
|
||||||
objects::{create_tombstone, person::ApubPerson, post::ApubPost, Source},
|
objects::{create_tombstone, person::ApubPerson, post::ApubPost, Source},
|
||||||
PostOrComment,
|
PostOrComment,
|
||||||
};
|
};
|
||||||
|
@ -14,7 +13,7 @@ use activitystreams::{
|
||||||
public,
|
public,
|
||||||
unparsed::Unparsed,
|
unparsed::Unparsed,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::anyhow;
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
use html2md::parse_html;
|
use html2md::parse_html;
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
|
@ -35,7 +34,6 @@ use lemmy_db_schema::{
|
||||||
DbPool,
|
DbPool,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
location_info,
|
|
||||||
utils::{convert_datetime, remove_slurs},
|
utils::{convert_datetime, remove_slurs},
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
@ -61,7 +59,7 @@ pub struct Note {
|
||||||
content: String,
|
content: String,
|
||||||
media_type: Option<MediaTypeHtml>,
|
media_type: Option<MediaTypeHtml>,
|
||||||
source: SourceCompat,
|
source: SourceCompat,
|
||||||
in_reply_to: CommentInReplyToMigration,
|
in_reply_to: ObjectId<PostOrComment>,
|
||||||
published: Option<DateTime<FixedOffset>>,
|
published: Option<DateTime<FixedOffset>>,
|
||||||
updated: Option<DateTime<FixedOffset>>,
|
updated: Option<DateTime<FixedOffset>>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
@ -91,43 +89,25 @@ impl Note {
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(ApubPost, Option<CommentId>), LemmyError> {
|
) -> Result<(ApubPost, Option<CommentId>), LemmyError> {
|
||||||
match &self.in_reply_to {
|
// Fetch parent comment chain in a box, otherwise it can cause a stack overflow.
|
||||||
CommentInReplyToMigration::Old(in_reply_to) => {
|
let parent = Box::pin(
|
||||||
// This post, or the parent comment might not yet exist on this server yet, fetch them.
|
self
|
||||||
let post_id = in_reply_to.get(0).context(location_info!())?;
|
.in_reply_to
|
||||||
let post_id = ObjectId::new(post_id.clone());
|
.dereference(context, request_counter)
|
||||||
let post = Box::pin(post_id.dereference(context, request_counter)).await?;
|
.await?,
|
||||||
|
);
|
||||||
// The 2nd item, if it exists, is the parent comment apub_id
|
match parent.deref() {
|
||||||
// Nested comments will automatically get fetched recursively
|
PostOrComment::Post(p) => {
|
||||||
let parent_id: Option<CommentId> = match in_reply_to.get(1) {
|
// Workaround because I cant figure out how to get the post out of the box (and we dont
|
||||||
Some(comment_id) => {
|
// want to stackoverflow in a deep comment hierarchy).
|
||||||
let comment_id = ObjectId::<ApubComment>::new(comment_id.clone());
|
let post_id = p.id;
|
||||||
let parent_comment = Box::pin(comment_id.dereference(context, request_counter)).await?;
|
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
||||||
|
Ok((post.into(), None))
|
||||||
Some(parent_comment.id)
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((post, parent_id))
|
|
||||||
}
|
}
|
||||||
CommentInReplyToMigration::New(in_reply_to) => {
|
PostOrComment::Comment(c) => {
|
||||||
let parent = Box::pin(in_reply_to.dereference(context, request_counter).await?);
|
let post_id = c.post_id;
|
||||||
match parent.deref() {
|
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
||||||
PostOrComment::Post(p) => {
|
Ok((post.into(), Some(c.id)))
|
||||||
// Workaround because I cant figure out how to get the post out of the box (and we dont
|
|
||||||
// want to stackoverflow in a deep comment hierarchy).
|
|
||||||
let post_id = p.id;
|
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
|
||||||
Ok((post.into(), None))
|
|
||||||
}
|
|
||||||
PostOrComment::Comment(c) => {
|
|
||||||
let post_id = c.post_id;
|
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
|
||||||
Ok((post.into(), Some(c.id)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,15 +199,12 @@ impl ToApub for ApubComment {
|
||||||
let post_id = self.post_id;
|
let post_id = self.post_id;
|
||||||
let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??;
|
let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??;
|
||||||
|
|
||||||
// Add a vector containing some important info to the "in_reply_to" field
|
let in_reply_to = if let Some(comment_id) = self.parent_id {
|
||||||
// [post_ap_id, Option(parent_comment_ap_id)]
|
let parent_comment = blocking(pool, move |conn| Comment::read(conn, comment_id)).await??;
|
||||||
let mut in_reply_to_vec = vec![post.ap_id.into_inner()];
|
ObjectId::<PostOrComment>::new(parent_comment.ap_id.into_inner())
|
||||||
|
} else {
|
||||||
if let Some(parent_id) = self.parent_id {
|
ObjectId::<PostOrComment>::new(post.ap_id.into_inner())
|
||||||
let parent_comment = blocking(pool, move |conn| Comment::read(conn, parent_id)).await??;
|
};
|
||||||
|
|
||||||
in_reply_to_vec.push(parent_comment.ap_id.into_inner());
|
|
||||||
}
|
|
||||||
|
|
||||||
let note = Note {
|
let note = Note {
|
||||||
context: lemmy_context(),
|
context: lemmy_context(),
|
||||||
|
@ -241,7 +218,7 @@ impl ToApub for ApubComment {
|
||||||
content: self.content.clone(),
|
content: self.content.clone(),
|
||||||
media_type: MediaTypeMarkdown::Markdown,
|
media_type: MediaTypeMarkdown::Markdown,
|
||||||
}),
|
}),
|
||||||
in_reply_to: CommentInReplyToMigration::Old(in_reply_to_vec),
|
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),
|
||||||
unparsed: Default::default(),
|
unparsed: Default::default(),
|
||||||
|
@ -346,9 +323,9 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_fetch_lemmy_comment() {
|
async fn test_parse_lemmy_comment() {
|
||||||
let context = init_context();
|
let context = init_context();
|
||||||
let url = Url::parse("https://lemmy.ml/comment/38741").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/comment/38741").unwrap();
|
||||||
let data = prepare_comment_test(&url, &context).await;
|
let data = prepare_comment_test(&url, &context).await;
|
||||||
|
|
||||||
let json = file_to_json_object("assets/lemmy-comment.json");
|
let json = file_to_json_object("assets/lemmy-comment.json");
|
||||||
|
@ -358,7 +335,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(comment.ap_id.clone().into_inner(), url);
|
assert_eq!(comment.ap_id.clone().into_inner(), url);
|
||||||
assert_eq!(comment.content.len(), 1063);
|
assert_eq!(comment.content.len(), 14);
|
||||||
assert!(!comment.local);
|
assert!(!comment.local);
|
||||||
assert_eq!(request_counter, 0);
|
assert_eq!(request_counter, 0);
|
||||||
|
|
||||||
|
@ -371,9 +348,9 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_fetch_pleroma_comment() {
|
async fn test_parse_pleroma_comment() {
|
||||||
let context = init_context();
|
let context = init_context();
|
||||||
let url = Url::parse("https://lemmy.ml/comment/38741").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/comment/38741").unwrap();
|
||||||
let data = prepare_comment_test(&url, &context).await;
|
let data = prepare_comment_test(&url, &context).await;
|
||||||
|
|
||||||
let pleroma_url =
|
let pleroma_url =
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
fetcher::community::{fetch_community_outbox, update_community_mods},
|
fetcher::community::{fetch_community_outbox, update_community_mods},
|
||||||
generate_moderators_url,
|
generate_moderators_url,
|
||||||
generate_outbox_url,
|
generate_outbox_url,
|
||||||
objects::{create_tombstone, ImageObject, Source},
|
objects::{create_tombstone, get_summary_from_string_or_source, ImageObject, Source},
|
||||||
CommunityType,
|
CommunityType,
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
|
@ -21,7 +21,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
signatures::PublicKey,
|
signatures::PublicKey,
|
||||||
traits::{ActorType, ApubObject, FromApub, ToApub},
|
traits::{ActorType, ApubObject, FromApub, ToApub},
|
||||||
values::{MediaTypeHtml, MediaTypeMarkdown},
|
values::MediaTypeMarkdown,
|
||||||
verify::verify_domains_match,
|
verify::verify_domains_match,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -55,8 +55,7 @@ pub struct Group {
|
||||||
preferred_username: String,
|
preferred_username: String,
|
||||||
/// title (can be changed at any time)
|
/// title (can be changed at any time)
|
||||||
name: String,
|
name: String,
|
||||||
content: Option<String>,
|
summary: Option<String>,
|
||||||
media_type: Option<MediaTypeHtml>,
|
|
||||||
source: Option<Source>,
|
source: Option<Source>,
|
||||||
icon: Option<ImageObject>,
|
icon: Option<ImageObject>,
|
||||||
/// banner
|
/// banner
|
||||||
|
@ -89,7 +88,7 @@ impl Group {
|
||||||
let actor_id = Some(group.id(expected_domain)?.clone().into());
|
let actor_id = Some(group.id(expected_domain)?.clone().into());
|
||||||
let name = group.preferred_username.clone();
|
let name = group.preferred_username.clone();
|
||||||
let title = group.name.clone();
|
let title = group.name.clone();
|
||||||
let description = group.source.clone().map(|s| s.content);
|
let description = get_summary_from_string_or_source(&group.summary, &group.source);
|
||||||
let shared_inbox = group.endpoints.shared_inbox.clone().map(|s| s.into());
|
let shared_inbox = group.endpoints.shared_inbox.clone().map(|s| s.into());
|
||||||
|
|
||||||
let slur_regex = &settings.slur_regex();
|
let slur_regex = &settings.slur_regex();
|
||||||
|
@ -218,8 +217,7 @@ impl ToApub for ApubCommunity {
|
||||||
id: self.actor_id(),
|
id: self.actor_id(),
|
||||||
preferred_username: self.name.clone(),
|
preferred_username: self.name.clone(),
|
||||||
name: self.title.clone(),
|
name: self.title.clone(),
|
||||||
content: self.description.as_ref().map(|b| markdown_to_html(b)),
|
summary: self.description.as_ref().map(|b| markdown_to_html(b)),
|
||||||
media_type: self.description.as_ref().map(|_| MediaTypeHtml::Html),
|
|
||||||
source,
|
source,
|
||||||
icon,
|
icon,
|
||||||
image,
|
image,
|
||||||
|
@ -324,25 +322,26 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_fetch_lemmy_community() {
|
async fn test_parse_lemmy_community() {
|
||||||
let context = init_context();
|
let context = init_context();
|
||||||
let mut json: Group = file_to_json_object("assets/lemmy-community.json");
|
let mut json: Group = file_to_json_object("assets/lemmy-community.json");
|
||||||
let json_orig = json.clone();
|
let json_orig = json.clone();
|
||||||
// change these links so they dont fetch over the network
|
// change these links so they dont fetch over the network
|
||||||
json.moderators = Some(Url::parse("https://lemmy.ml/c/announcements/not_moderators").unwrap());
|
json.moderators =
|
||||||
json.outbox = Url::parse("https://lemmy.ml/c/announcements/not_outbox").unwrap();
|
Some(Url::parse("https://enterprise.lemmy.ml/c/tenforward/not_moderators").unwrap());
|
||||||
|
json.outbox = Url::parse("https://enterprise.lemmy.ml/c/tenforward/not_outbox").unwrap();
|
||||||
|
|
||||||
let url = Url::parse("https://lemmy.ml/c/announcements").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/c/tenforward").unwrap();
|
||||||
let mut request_counter = 0;
|
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
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(community.actor_id.clone().into_inner(), url);
|
assert_eq!(community.actor_id.clone().into_inner(), url);
|
||||||
assert_eq!(community.title, "Announcements");
|
assert_eq!(community.title, "Ten Forward");
|
||||||
assert!(community.public_key.is_some());
|
assert!(community.public_key.is_some());
|
||||||
assert!(!community.local);
|
assert!(!community.local);
|
||||||
assert_eq!(community.description.as_ref().unwrap().len(), 126);
|
assert_eq!(community.description.as_ref().unwrap().len(), 132);
|
||||||
// this makes two requests to the (intentionally) broken outbox/moderators collections
|
// this makes two requests to the (intentionally) broken outbox/moderators collections
|
||||||
assert_eq!(request_counter, 2);
|
assert_eq!(request_counter, 2);
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,10 @@ use activitystreams::{
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
|
use html2md::parse_html;
|
||||||
use lemmy_apub_lib::values::MediaTypeMarkdown;
|
use lemmy_apub_lib::values::MediaTypeMarkdown;
|
||||||
use lemmy_utils::{utils::convert_datetime, LemmyError};
|
use lemmy_utils::{utils::convert_datetime, LemmyError};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
|
@ -14,14 +16,14 @@ pub mod person;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
pub mod private_message;
|
pub mod private_message;
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Source {
|
pub struct Source {
|
||||||
content: String,
|
content: String,
|
||||||
media_type: MediaTypeMarkdown,
|
media_type: MediaTypeMarkdown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ImageObject {
|
pub struct ImageObject {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -54,6 +56,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_summary_from_string_or_source(
|
||||||
|
raw: &Option<String>,
|
||||||
|
source: &Option<Source>,
|
||||||
|
) -> Option<String> {
|
||||||
|
if let Some(source) = &source {
|
||||||
|
Some(source.content.clone())
|
||||||
|
} else {
|
||||||
|
raw.as_ref().map(|s| parse_html(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
check_is_apub_id_valid,
|
check_is_apub_id_valid,
|
||||||
context::lemmy_context,
|
context::lemmy_context,
|
||||||
generate_outbox_url,
|
generate_outbox_url,
|
||||||
objects::{ImageObject, Source},
|
objects::{get_summary_from_string_or_source, ImageObject, Source},
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
actor::Endpoints,
|
actor::Endpoints,
|
||||||
|
@ -17,7 +17,7 @@ use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
signatures::PublicKey,
|
signatures::PublicKey,
|
||||||
traits::{ActorType, ApubObject, FromApub, ToApub},
|
traits::{ActorType, ApubObject, FromApub, ToApub},
|
||||||
values::{MediaTypeHtml, MediaTypeMarkdown},
|
values::MediaTypeMarkdown,
|
||||||
verify::verify_domains_match,
|
verify::verify_domains_match,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -54,8 +54,7 @@ pub struct Person {
|
||||||
preferred_username: String,
|
preferred_username: String,
|
||||||
/// displayname (can be changed at any time)
|
/// displayname (can be changed at any time)
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
content: Option<String>,
|
summary: Option<String>,
|
||||||
media_type: Option<MediaTypeHtml>,
|
|
||||||
source: Option<Source>,
|
source: Option<Source>,
|
||||||
/// user avatar
|
/// user avatar
|
||||||
icon: Option<ImageObject>,
|
icon: Option<ImageObject>,
|
||||||
|
@ -186,8 +185,7 @@ impl ToApub for ApubPerson {
|
||||||
id: self.actor_id.to_owned().into_inner(),
|
id: self.actor_id.to_owned().into_inner(),
|
||||||
preferred_username: self.name.clone(),
|
preferred_username: self.name.clone(),
|
||||||
name: self.display_name.clone(),
|
name: self.display_name.clone(),
|
||||||
content: self.bio.as_ref().map(|b| markdown_to_html(b)),
|
summary: self.bio.as_ref().map(|b| markdown_to_html(b)),
|
||||||
media_type: self.bio.as_ref().map(|_| MediaTypeHtml::Html),
|
|
||||||
source,
|
source,
|
||||||
icon,
|
icon,
|
||||||
image,
|
image,
|
||||||
|
@ -224,7 +222,7 @@ impl FromApub for ApubPerson {
|
||||||
let actor_id = Some(person.id(expected_domain)?.clone().into());
|
let actor_id = Some(person.id(expected_domain)?.clone().into());
|
||||||
let name = person.preferred_username.clone();
|
let name = person.preferred_username.clone();
|
||||||
let display_name: Option<String> = person.name.clone();
|
let display_name: Option<String> = person.name.clone();
|
||||||
let bio = person.source.clone().map(|s| s.content);
|
let bio = get_summary_from_string_or_source(&person.summary, &person.source);
|
||||||
let shared_inbox = person.endpoints.shared_inbox.clone().map(|s| s.into());
|
let shared_inbox = person.endpoints.shared_inbox.clone().map(|s| s.into());
|
||||||
let bot_account = match person.kind {
|
let bot_account = match person.kind {
|
||||||
UserTypes::Person => false,
|
UserTypes::Person => false,
|
||||||
|
@ -277,20 +275,20 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_fetch_lemmy_person() {
|
async fn test_parse_lemmy_person() {
|
||||||
let context = init_context();
|
let context = init_context();
|
||||||
let json = file_to_json_object("assets/lemmy-person.json");
|
let json = file_to_json_object("assets/lemmy-person.json");
|
||||||
let url = Url::parse("https://lemmy.ml/u/nutomic").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/u/picard").unwrap();
|
||||||
let mut request_counter = 0;
|
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
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(person.actor_id.clone().into_inner(), url);
|
assert_eq!(person.actor_id.clone().into_inner(), url);
|
||||||
assert_eq!(person.name, "nutomic");
|
assert_eq!(person.display_name, Some("Jean-Luc Picard".to_string()));
|
||||||
assert!(person.public_key.is_some());
|
assert!(person.public_key.is_some());
|
||||||
assert!(!person.local);
|
assert!(!person.local);
|
||||||
assert!(person.bio.is_some());
|
assert_eq!(person.bio.as_ref().unwrap().len(), 39);
|
||||||
assert_eq!(request_counter, 0);
|
assert_eq!(request_counter, 0);
|
||||||
|
|
||||||
let to_apub = person.to_apub(context.pool()).await.unwrap();
|
let to_apub = person.to_apub(context.pool()).await.unwrap();
|
||||||
|
@ -301,7 +299,7 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_fetch_pleroma_person() {
|
async fn test_parse_pleroma_person() {
|
||||||
let context = init_context();
|
let context = init_context();
|
||||||
let json = file_to_json_object("assets/pleroma-person.json");
|
let json = file_to_json_object("assets/pleroma-person.json");
|
||||||
let url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
|
let url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
|
||||||
|
@ -315,8 +313,7 @@ mod tests {
|
||||||
assert!(person.public_key.is_some());
|
assert!(person.public_key.is_some());
|
||||||
assert!(!person.local);
|
assert!(!person.local);
|
||||||
assert_eq!(request_counter, 0);
|
assert_eq!(request_counter, 0);
|
||||||
// TODO: pleroma uses summary for user profile, while we use content
|
assert_eq!(person.bio.as_ref().unwrap().len(), 873);
|
||||||
//assert!(person.bio.is_some());
|
|
||||||
|
|
||||||
DbPerson::delete(&*context.pool().get().unwrap(), person.id).unwrap();
|
DbPerson::delete(&*context.pool().get().unwrap(), person.id).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,9 +290,9 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_fetch_lemmy_post() {
|
async fn test_parse_lemmy_post() {
|
||||||
let context = init_context();
|
let context = init_context();
|
||||||
let url = Url::parse("https://lemmy.ml/post/55143").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/post/55143").unwrap();
|
||||||
let community_json = file_to_json_object("assets/lemmy-community.json");
|
let community_json = file_to_json_object("assets/lemmy-community.json");
|
||||||
let community = ApubCommunity::from_apub(&community_json, &context, &url, &mut 0)
|
let community = ApubCommunity::from_apub(&community_json, &context, &url, &mut 0)
|
||||||
.await
|
.await
|
||||||
|
@ -308,9 +308,9 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(post.ap_id.clone().into_inner(), url);
|
assert_eq!(post.ap_id.clone().into_inner(), url);
|
||||||
assert_eq!(post.name, "Statement on Politics of Lemmy.ml");
|
assert_eq!(post.name, "Post title");
|
||||||
assert!(post.body.is_some());
|
assert!(post.body.is_some());
|
||||||
assert_eq!(post.body.as_ref().unwrap().len(), 2144);
|
assert_eq!(post.body.as_ref().unwrap().len(), 45);
|
||||||
assert!(!post.locked);
|
assert!(!post.locked);
|
||||||
assert!(post.stickied);
|
assert!(post.stickied);
|
||||||
assert_eq!(request_counter, 0);
|
assert_eq!(request_counter, 0);
|
||||||
|
|
|
@ -12,6 +12,7 @@ use activitystreams::{
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
|
use html2md::parse_html;
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
traits::{ApubObject, FromApub, ToApub},
|
traits::{ApubObject, FromApub, ToApub},
|
||||||
|
@ -39,19 +40,25 @@ use url::Url;
|
||||||
pub struct Note {
|
pub struct Note {
|
||||||
#[serde(rename = "@context")]
|
#[serde(rename = "@context")]
|
||||||
context: OneOrMany<AnyBase>,
|
context: OneOrMany<AnyBase>,
|
||||||
r#type: NoteType,
|
r#type: ChatMessageType,
|
||||||
id: Url,
|
id: Url,
|
||||||
pub(crate) attributed_to: ObjectId<ApubPerson>,
|
pub(crate) attributed_to: ObjectId<ApubPerson>,
|
||||||
to: ObjectId<ApubPerson>,
|
to: [ObjectId<ApubPerson>; 1],
|
||||||
content: String,
|
content: String,
|
||||||
media_type: MediaTypeHtml,
|
media_type: Option<MediaTypeHtml>,
|
||||||
source: Source,
|
source: Option<Source>,
|
||||||
published: Option<DateTime<FixedOffset>>,
|
published: Option<DateTime<FixedOffset>>,
|
||||||
updated: Option<DateTime<FixedOffset>>,
|
updated: Option<DateTime<FixedOffset>>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
unparsed: Unparsed,
|
unparsed: Unparsed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://docs.pleroma.social/backend/development/ap_extensions/#chatmessages
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
pub enum ChatMessageType {
|
||||||
|
ChatMessage,
|
||||||
|
}
|
||||||
|
|
||||||
impl Note {
|
impl Note {
|
||||||
pub(crate) fn id_unchecked(&self) -> &Url {
|
pub(crate) fn id_unchecked(&self) -> &Url {
|
||||||
&self.id
|
&self.id
|
||||||
|
@ -136,16 +143,16 @@ impl ToApub for ApubPrivateMessage {
|
||||||
|
|
||||||
let note = Note {
|
let note = Note {
|
||||||
context: lemmy_context(),
|
context: lemmy_context(),
|
||||||
r#type: NoteType::Note,
|
r#type: ChatMessageType::ChatMessage,
|
||||||
id: self.ap_id.clone().into(),
|
id: self.ap_id.clone().into(),
|
||||||
attributed_to: ObjectId::new(creator.actor_id),
|
attributed_to: ObjectId::new(creator.actor_id),
|
||||||
to: ObjectId::new(recipient.actor_id),
|
to: [ObjectId::new(recipient.actor_id)],
|
||||||
content: self.content.clone(),
|
content: self.content.clone(),
|
||||||
media_type: MediaTypeHtml::Html,
|
media_type: Some(MediaTypeHtml::Html),
|
||||||
source: Source {
|
source: Some(Source {
|
||||||
content: self.content.clone(),
|
content: self.content.clone(),
|
||||||
media_type: MediaTypeMarkdown::Markdown,
|
media_type: MediaTypeMarkdown::Markdown,
|
||||||
},
|
}),
|
||||||
published: Some(convert_datetime(self.published)),
|
published: Some(convert_datetime(self.published)),
|
||||||
updated: self.updated.map(convert_datetime),
|
updated: self.updated.map(convert_datetime),
|
||||||
unparsed: Default::default(),
|
unparsed: Default::default(),
|
||||||
|
@ -179,12 +186,17 @@ impl FromApub for ApubPrivateMessage {
|
||||||
.attributed_to
|
.attributed_to
|
||||||
.dereference(context, request_counter)
|
.dereference(context, request_counter)
|
||||||
.await?;
|
.await?;
|
||||||
let recipient = note.to.dereference(context, request_counter).await?;
|
let recipient = note.to[0].dereference(context, request_counter).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: note.source.content.clone(),
|
content,
|
||||||
published: note.published.map(|u| u.to_owned().naive_local()),
|
published: note.published.map(|u| u.to_owned().naive_local()),
|
||||||
updated: note.updated.map(|u| u.to_owned().naive_local()),
|
updated: note.updated.map(|u| u.to_owned().naive_local()),
|
||||||
deleted: None,
|
deleted: None,
|
||||||
|
@ -207,20 +219,30 @@ mod tests {
|
||||||
use assert_json_diff::assert_json_include;
|
use assert_json_diff::assert_json_include;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[actix_rt::test]
|
async fn prepare_comment_test(url: &Url, context: &LemmyContext) -> (ApubPerson, ApubPerson) {
|
||||||
#[serial]
|
|
||||||
async fn test_fetch_lemmy_pm() {
|
|
||||||
let context = init_context();
|
|
||||||
let url = Url::parse("https://lemmy.ml/private_message/1621").unwrap();
|
|
||||||
let lemmy_person = file_to_json_object("assets/lemmy-person.json");
|
let lemmy_person = file_to_json_object("assets/lemmy-person.json");
|
||||||
let person1 = ApubPerson::from_apub(&lemmy_person, &context, &url, &mut 0)
|
let person1 = ApubPerson::from_apub(&lemmy_person, context, url, &mut 0)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let pleroma_person = file_to_json_object("assets/pleroma-person.json");
|
let pleroma_person = file_to_json_object("assets/pleroma-person.json");
|
||||||
let pleroma_url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
|
let pleroma_url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
|
||||||
let person2 = ApubPerson::from_apub(&pleroma_person, &context, &pleroma_url, &mut 0)
|
let person2 = ApubPerson::from_apub(&pleroma_person, context, &pleroma_url, &mut 0)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
(person1, person2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cleanup(data: (ApubPerson, ApubPerson), context: &LemmyContext) {
|
||||||
|
Person::delete(&*context.pool().get().unwrap(), data.0.id).unwrap();
|
||||||
|
Person::delete(&*context.pool().get().unwrap(), data.1.id).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
#[serial]
|
||||||
|
async fn test_parse_lemmy_pm() {
|
||||||
|
let context = init_context();
|
||||||
|
let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621").unwrap();
|
||||||
|
let data = prepare_comment_test(&url, &context).await;
|
||||||
let json = file_to_json_object("assets/lemmy-private-message.json");
|
let json = file_to_json_object("assets/lemmy-private-message.json");
|
||||||
let mut request_counter = 0;
|
let mut request_counter = 0;
|
||||||
let pm = ApubPrivateMessage::from_apub(&json, &context, &url, &mut request_counter)
|
let pm = ApubPrivateMessage::from_apub(&json, &context, &url, &mut request_counter)
|
||||||
|
@ -228,14 +250,34 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(pm.ap_id.clone().into_inner(), url);
|
assert_eq!(pm.ap_id.clone().into_inner(), url);
|
||||||
assert_eq!(pm.content.len(), 4);
|
assert_eq!(pm.content.len(), 20);
|
||||||
assert_eq!(request_counter, 0);
|
assert_eq!(request_counter, 0);
|
||||||
|
|
||||||
let to_apub = pm.to_apub(context.pool()).await.unwrap();
|
let to_apub = pm.to_apub(context.pool()).await.unwrap();
|
||||||
assert_json_include!(actual: json, expected: to_apub);
|
assert_json_include!(actual: json, expected: to_apub);
|
||||||
|
|
||||||
PrivateMessage::delete(&*context.pool().get().unwrap(), pm.id).unwrap();
|
PrivateMessage::delete(&*context.pool().get().unwrap(), pm.id).unwrap();
|
||||||
Person::delete(&*context.pool().get().unwrap(), person1.id).unwrap();
|
cleanup(data, &context);
|
||||||
Person::delete(&*context.pool().get().unwrap(), person2.id).unwrap();
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
#[serial]
|
||||||
|
async fn test_parse_pleroma_pm() {
|
||||||
|
let context = init_context();
|
||||||
|
let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621").unwrap();
|
||||||
|
let data = prepare_comment_test(&url, &context).await;
|
||||||
|
let pleroma_url = Url::parse("https://queer.hacktivis.me/objects/2").unwrap();
|
||||||
|
let json = file_to_json_object("assets/pleroma-private-message.json");
|
||||||
|
let mut request_counter = 0;
|
||||||
|
let pm = ApubPrivateMessage::from_apub(&json, &context, &pleroma_url, &mut request_counter)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(pm.ap_id.clone().into_inner(), pleroma_url);
|
||||||
|
assert_eq!(pm.content.len(), 3);
|
||||||
|
assert_eq!(request_counter, 0);
|
||||||
|
|
||||||
|
PrivateMessage::delete(&*context.pool().get().unwrap(), pm.id).unwrap();
|
||||||
|
cleanup(data, &context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue