From 55e03c4eb4dfeb79c5603289e541279fd39036b0 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Sun, 29 Nov 2020 13:09:14 +0100 Subject: [PATCH 1/3] Rewrite federation docs --- docs/src/SUMMARY.md | 42 ++++++++++--------- docs/src/{ => about}/about.md | 0 .../{about_features.md => about/features.md} | 0 docs/src/{about_goals.md => about/goals.md} | 16 ------- docs/src/{about_guide.md => about/guide.md} | 2 +- .../{about_ranking.md => about/ranking.md} | 0 .../{ => administration}/administration.md | 2 +- .../backup_and_restore.md} | 0 .../configuration.md} | 0 .../install_ansible.md} | 2 +- .../install_docker.md} | 2 +- docs/src/{ => contributing}/contributing.md | 0 .../docker_development.md} | 2 +- .../federation_development.md} | 6 +-- .../local_development.md} | 2 +- .../tests.md} | 4 +- .../theming.md} | 0 .../websocket_http_api.md} | 0 .../administration.md} | 3 +- docs/src/federation/federation.md | 14 +++++++ .../lemmy_protocol.md} | 4 +- .../overview.md} | 2 +- docs/src/federation/resources.md | 22 ++++++++++ 23 files changed, 75 insertions(+), 50 deletions(-) rename docs/src/{ => about}/about.md (100%) rename docs/src/{about_features.md => about/features.md} (100%) rename docs/src/{about_goals.md => about/goals.md} (69%) rename docs/src/{about_guide.md => about/guide.md} (96%) rename docs/src/{about_ranking.md => about/ranking.md} (100%) rename docs/src/{ => administration}/administration.md (73%) rename docs/src/{administration_backup_and_restore.md => administration/backup_and_restore.md} (100%) rename docs/src/{administration_configuration.md => administration/configuration.md} (100%) rename docs/src/{administration_install_ansible.md => administration/install_ansible.md} (78%) rename docs/src/{administration_install_docker.md => administration/install_docker.md} (91%) rename docs/src/{ => contributing}/contributing.md (100%) rename docs/src/{contributing_docker_development.md => contributing/docker_development.md} (91%) rename docs/src/{contributing_federation_development.md => contributing/federation_development.md} (90%) rename docs/src/{contributing_local_development.md => contributing/local_development.md} (97%) rename docs/src/{contributing_tests.md => contributing/tests.md} (51%) rename docs/src/{contributing_theming.md => contributing/theming.md} (100%) rename docs/src/{contributing_websocket_http_api.md => contributing/websocket_http_api.md} (100%) rename docs/src/{administration_federation.md => federation/administration.md} (96%) create mode 100644 docs/src/federation/federation.md rename docs/src/{contributing_apub_api_outline.md => federation/lemmy_protocol.md} (98%) rename docs/src/{contributing_federation_overview.md => federation/overview.md} (99%) create mode 100644 docs/src/federation/resources.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index e00f5ced6..93f6c42d0 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -1,23 +1,25 @@ # Summary -- [About](about.md) - - [Features](about_features.md) - - [Goals](about_goals.md) - - [Post and Comment Ranking](about_ranking.md) - - [Guide](about_guide.md) -- [Administration](administration.md) - - [Install with Docker](administration_install_docker.md) - - [Install with Ansible](administration_install_ansible.md) - - [Configuration](administration_configuration.md) - - [Backup and Restore](administration_backup_and_restore.md) - - [Federation](administration_federation.md) -- [Contributing](contributing.md) - - [Docker Development](contributing_docker_development.md) - - [Local Development](contributing_local_development.md) - - [Tests](contributing_tests.md) - - [Federation Development](contributing_federation_development.md) - - [Websocket/HTTP API](contributing_websocket_http_api.md) - - [Federation Overview](contributing_federation_overview.md) - - [ActivityPub API Outline](contributing_apub_api_outline.md) - - [Theming Guide](contributing_theming.md) +- [About](about/about.md) + - [Features](about/features.md) + - [Goals](about/goals.md) + - [Post and Comment Ranking](about/ranking.md) + - [Guide](about/guide.md) +- [Administration](administration/administration.md) + - [Install with Docker](administration/install_docker.md) + - [Install with Ansible](administration/install_ansible.md) + - [Configuration](administration/configuration.md) + - [Backup and Restore](administration/backup_and_restore.md) +- [Federation](federation/federation.md) + - [Federation Overview](federation/overview.md) + - [Administration](federation/administration.md) + - [Resources](federation/resources.md) + - [Lemmy Protocol](federation/lemmy_protocol.md) +- [Contributing](contributing/contributing.md) + - [Docker Development](contributing/docker_development.md) + - [Local Development](contributing/local_development.md) + - [Theming Guide](contributing/theming.md) + - [Tests](contributing/tests.md) + - [Websocket/HTTP API](contributing/websocket_http_api.md) + - [Federation Development](contributing/federation_development.md) - [Lemmy Council](lemmy_council.md) diff --git a/docs/src/about.md b/docs/src/about/about.md similarity index 100% rename from docs/src/about.md rename to docs/src/about/about.md diff --git a/docs/src/about_features.md b/docs/src/about/features.md similarity index 100% rename from docs/src/about_features.md rename to docs/src/about/features.md diff --git a/docs/src/about_goals.md b/docs/src/about/goals.md similarity index 69% rename from docs/src/about_goals.md rename to docs/src/about/goals.md index e0427481c..e7d8e8dc6 100644 --- a/docs/src/about_goals.md +++ b/docs/src/about/goals.md @@ -36,19 +36,3 @@ - [Rust docker build](https://shaneutt.com/blog/rust-fast-small-docker-image-builds/) - [Zurb mentions](https://github.com/zurb/tribute) - [TippyJS](https://github.com/atomiks/tippyjs) - -## Activitypub guides - -- https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/ -- https://raw.githubusercontent.com/w3c/activitypub/gh-pages/activitypub-tutorial.txt -- https://github.com/tOkeshu/activitypub-example -- https://blog.joinmastodon.org/2018/07/how-to-make-friends-and-verify-requests/ -- Use the [activitypub crate.](https://docs.rs/activitypub/0.1.4/activitypub/) -- https://docs.rs/activitypub/0.1.4/activitypub/ -- [Activitypub vocab.](https://www.w3.org/TR/activitystreams-vocabulary/) -- [Activitypub main](https://www.w3.org/TR/activitypub/) -- [Federation.md](https://github.com/dariusk/gathio/blob/7fc93dbe9d4d99457a0e85c6c532112f415b7af2/FEDERATION.md) -- [Activitypub implementers guide](https://socialhub.activitypub.rocks/t/draft-guide-for-new-activitypub-implementers/479) -- [Data storage questions](https://socialhub.activitypub.rocks/t/data-storage-questions/579/3) -- [Activitypub as it has been understood](https://flak.tedunangst.com/post/ActivityPub-as-it-has-been-understood) -- [Asonix http signatures in rust](https://git.asonix.dog/Aardwolf/http-signature-normalization) diff --git a/docs/src/about_guide.md b/docs/src/about/guide.md similarity index 96% rename from docs/src/about_guide.md rename to docs/src/about/guide.md index d9f8adb0d..59244b1e8 100644 --- a/docs/src/about_guide.md +++ b/docs/src/about/guide.md @@ -17,7 +17,7 @@ Hot | Trending sort based on the score, and the post creation time. New | Newest items. Top | The highest scoring items in the given time frame. -For more detail, check the [Post and Comment Ranking details](about_ranking.md). +For more detail, check the [Post and Comment Ranking details](ranking.md). ## Markdown Guide diff --git a/docs/src/about_ranking.md b/docs/src/about/ranking.md similarity index 100% rename from docs/src/about_ranking.md rename to docs/src/about/ranking.md diff --git a/docs/src/administration.md b/docs/src/administration/administration.md similarity index 73% rename from docs/src/administration.md rename to docs/src/administration/administration.md index 690b71596..3211859bf 100644 --- a/docs/src/administration.md +++ b/docs/src/administration/administration.md @@ -4,7 +4,7 @@ Information for Lemmy instance admins, and those who want to run a server. ## Install -Lemmy has two primary install methods, [docker](administration_install_docker.md), and [ansible](administration_install_ansible.md). Ansible simplifies deploying to a remote server, while docker is best for local testing. +Lemmy has two primary install methods, [docker](install_docker.md), and [ansible](install_ansible.md). Ansible simplifies deploying to a remote server, while docker is best for local testing. ### Manual install diff --git a/docs/src/administration_backup_and_restore.md b/docs/src/administration/backup_and_restore.md similarity index 100% rename from docs/src/administration_backup_and_restore.md rename to docs/src/administration/backup_and_restore.md diff --git a/docs/src/administration_configuration.md b/docs/src/administration/configuration.md similarity index 100% rename from docs/src/administration_configuration.md rename to docs/src/administration/configuration.md diff --git a/docs/src/administration_install_ansible.md b/docs/src/administration/install_ansible.md similarity index 78% rename from docs/src/administration_install_ansible.md rename to docs/src/administration/install_ansible.md index 849957ad1..ea04f53d0 100644 --- a/docs/src/administration_install_ansible.md +++ b/docs/src/administration/install_ansible.md @@ -1,6 +1,6 @@ # Ansible Installation -This is the same as the [Docker installation](administration_install_docker.md), except that Ansible handles all of it automatically. It also does some extra things like setting up TLS and email for your Lemmy instance. +This is the same as the [Docker installation](install_docker.md), except that Ansible handles all of it automatically. It also does some extra things like setting up TLS and email for your Lemmy instance. First, you need to [install Ansible on your local computer](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) (e.g. using `sudo apt install ansible`) or the equivalent for you platform. diff --git a/docs/src/administration_install_docker.md b/docs/src/administration/install_docker.md similarity index 91% rename from docs/src/administration_install_docker.md rename to docs/src/administration/install_docker.md index 490fe1c01..4796fe528 100644 --- a/docs/src/administration_install_docker.md +++ b/docs/src/administration/install_docker.md @@ -27,7 +27,7 @@ Open up your `docker-compose.yml`, and make sure `LEMMY_EXTERNAL_HOST` for `lemm If you'd like a different database password, you should also change it in the `docker-compose.yml` **before** your first run. -After this, have a look at the [config file](administration_configuration.md) named `lemmy.hjson`, and adjust it, in particular the hostname, and possibly the db password. Then run: +After this, have a look at the [config file](configuration.md) named `lemmy.hjson`, and adjust it, in particular the hostname, and possibly the db password. Then run: `docker-compose up -d` diff --git a/docs/src/contributing.md b/docs/src/contributing/contributing.md similarity index 100% rename from docs/src/contributing.md rename to docs/src/contributing/contributing.md diff --git a/docs/src/contributing_docker_development.md b/docs/src/contributing/docker_development.md similarity index 91% rename from docs/src/contributing_docker_development.md rename to docs/src/contributing/docker_development.md index 3272efe24..ee035dd2b 100644 --- a/docs/src/contributing_docker_development.md +++ b/docs/src/contributing/docker_development.md @@ -29,4 +29,4 @@ To speed up the Docker compile, add the following to `/etc/docker/daemon.json` a ``` If the build is still too slow, you will have to use a -[local build](contributing_local_development.md) instead. +[local build](local_development.md) instead. diff --git a/docs/src/contributing_federation_development.md b/docs/src/contributing/federation_development.md similarity index 90% rename from docs/src/contributing_federation_development.md rename to docs/src/contributing/federation_development.md index 0c6fd9c40..fd625d60d 100644 --- a/docs/src/contributing_federation_development.md +++ b/docs/src/contributing/federation_development.md @@ -2,7 +2,7 @@ ## Running locally -Install the dependencies as described in [Docker development](contributing_docker_development.md). Then run the following +Install the dependencies as described in [Docker development](docker_development.md). Then run the following ```bash cd docker/federation @@ -34,8 +34,8 @@ Firefox containers are a good way to test them interacting. Note that federation is currently in alpha. **Only use it for testing**, not on any production server, and be aware that turning on federation may break your instance. -Follow the normal installation instructions, either with [Ansible](administration_install_ansible.md) or -[manually](administration_install_docker.md). Then replace the line `image: dessalines/lemmy:v0.x.x` in +Follow the normal installation instructions, either with [Ansible](../administration/install_ansible.md) or +[manually](../administration/install_docker.md). Then replace the line `image: dessalines/lemmy:v0.x.x` in `/lemmy/docker-compose.yml` with `image: dessalines/lemmy:federation`. Also add the following in `/lemmy/lemmy.hjson`: diff --git a/docs/src/contributing_local_development.md b/docs/src/contributing/local_development.md similarity index 97% rename from docs/src/contributing_local_development.md rename to docs/src/contributing/local_development.md index ccf1f51ee..114a54584 100644 --- a/docs/src/contributing_local_development.md +++ b/docs/src/contributing/local_development.md @@ -85,4 +85,4 @@ and go to [localhost:1234](http://localhost:1234). Front end saves should rebuil Note that this setup doesn't include image uploads or link previews (provided by pict-rs and iframely respectively). If you want to test those, you should use the -[Docker development](contributing_docker_development.md). +[Docker development](docker_development.md). diff --git a/docs/src/contributing_tests.md b/docs/src/contributing/tests.md similarity index 51% rename from docs/src/contributing_tests.md rename to docs/src/contributing/tests.md index 494cf5cd9..e4cfa65a9 100644 --- a/docs/src/contributing_tests.md +++ b/docs/src/contributing/tests.md @@ -2,7 +2,7 @@ #### Rust -After installing [local development dependencies](contributing_local_development.md), run the +After installing [local development dependencies](local_development.md), run the following commands: ```bash @@ -12,7 +12,7 @@ psql -U lemmy -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" ### Federation -Install the [Docker development dependencies](contributing_docker_development.md), and execute: +Install the [Docker development dependencies](docker_development.md), and execute: ``` cd docker/federation diff --git a/docs/src/contributing_theming.md b/docs/src/contributing/theming.md similarity index 100% rename from docs/src/contributing_theming.md rename to docs/src/contributing/theming.md diff --git a/docs/src/contributing_websocket_http_api.md b/docs/src/contributing/websocket_http_api.md similarity index 100% rename from docs/src/contributing_websocket_http_api.md rename to docs/src/contributing/websocket_http_api.md diff --git a/docs/src/administration_federation.md b/docs/src/federation/administration.md similarity index 96% rename from docs/src/administration_federation.md rename to docs/src/federation/administration.md index c7044ac24..fc24216c8 100644 --- a/docs/src/administration_federation.md +++ b/docs/src/federation/administration.md @@ -1,4 +1,4 @@ -# Federation +# Federation Administration Note: ActivityPub federation is still under development. We recommend that you only enable it on test instances for now. @@ -11,6 +11,7 @@ Federation does not start automatically, but needs to be triggered manually thro - `https://lemmy.ml/c/programming` (Community) - `https://lemmy.ml/u/nutomic` (User) - `https://lemmy.ml/post/123` (Post) +- `https://lemmy.ml/comment/321` (Comment) For an overview of how federation in Lemmy works on a technical level, check out our [Federation Overview](contributing_federation_overview.md). diff --git a/docs/src/federation/federation.md b/docs/src/federation/federation.md new file mode 100644 index 000000000..28e304d5a --- /dev/null +++ b/docs/src/federation/federation.md @@ -0,0 +1,14 @@ +# Federation + +Lemmy uses the ActivityPub protocol (a W3C standard) to enable federation between different servers (often called instances). This is very similar to the way email works. For example, if you use gmail.com, then you can't just send mails to other gmail.com users, but also to yahoo.com, yandex.ru and so on. Email uses the SMTP protocol to achieve this, so you can think of ActivityPub as "SMTP for social media". The amount of different actions possible on social media (post, comment, like, share, etc) means that ActivityPub is much more complicated than SMTP. + +As with email, ActivityPub federation happens only between servers. So if you are registered on `enterprise.lemmy.ml`, you only connect to the API of `enterprise.lemmy.ml`, while the server takes care of sending and receiving data from other instances (eg `voyager.lemmy.ml`). The great advantage of this approach is that the average user doesn't have to do anything to use federation. In fact if you are using Lemmy, you are likely already using it. One way to confirm is by going to a community or user profile. If you are on `enterprise.lemmy.ml` and you see a user like `@nutomic@voyager.lemmy.ml`, or a community like `!main@ds9.lemmy.ml`, then those are federated, meaning they use a different instance from yours. + +One way you can take advantage of federation is by opening a different instance, like `ds9.lemmy.ml`, and browsing it. If you see an interesting community, post or user that you want to interact with, just copy its URL and paste it into the search of your own instance. Your instance will connect to the other one (assuming the allowlist/blocklist allows it), and directly display the remote content to you, so that you can follow a community or comment on a post. Here are some examples of working searches: + +- `!main@lemmy.ml` (Community) +- `@nutomic@lemmy.ml` (User) +- `https://lemmy.ml/c/programming` (Community) +- `https://lemmy.ml/u/nutomic` (User) +- `https://lemmy.ml/post/123` (Post) +- `https://lemmy.ml/comment/321` (Comment) \ No newline at end of file diff --git a/docs/src/contributing_apub_api_outline.md b/docs/src/federation/lemmy_protocol.md similarity index 98% rename from docs/src/contributing_apub_api_outline.md rename to docs/src/federation/lemmy_protocol.md index 92cdf9c0e..75dfe2634 100644 --- a/docs/src/contributing_apub_api_outline.md +++ b/docs/src/federation/lemmy_protocol.md @@ -1,4 +1,6 @@ -# Activitypub API outline +# Lemmy Federation Protocol + +The Lemmy Protocol (or Lemmy Federation Protocol) is a strict subset of the [ActivityPub Protocol](https://www.w3.org/TR/activitypub/). Any deviation from the ActivityPub protocol is a bug in Lemmy or in this documentation (or both). This document is targeted at developers who are familiar with the ActivityPub and ActivityStreams protocols. It gives a detailed outline of the actors, objects and activities used by Lemmy. diff --git a/docs/src/contributing_federation_overview.md b/docs/src/federation/overview.md similarity index 99% rename from docs/src/contributing_federation_overview.md rename to docs/src/federation/overview.md index abfac4552..949984b8a 100644 --- a/docs/src/contributing_federation_overview.md +++ b/docs/src/federation/overview.md @@ -1,4 +1,4 @@ -# Federation +# Federation Overview This document is for anyone who wants to know how Lemmy federation works, without being overly technical. It is meant provide a high-level overview of ActivityPub federation in Lemmy. If you are implementing ActivityPub yourself and want to be compatible with Lemmy, read our [ActivityPub API outline](contributing_apub_api_outline.md). diff --git a/docs/src/federation/resources.md b/docs/src/federation/resources.md new file mode 100644 index 000000000..0f14691c9 --- /dev/null +++ b/docs/src/federation/resources.md @@ -0,0 +1,22 @@ +# ActivityPub Resources + +## Official Documents + +- [ActivityPub standard](https://www.w3.org/TR/activitypub/) +- [Activitypub vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/) + +## Explanations + +- [ActivityPub - one protocol to rule them all?](https://schub.io/blog/2018/02/01/activitypub-one-protocol-to-rule-them-all.html) +- [A highly opinionated guide to learning about ActivityPub](https://tinysubversions.com/notes/reading-activitypub/) +- [Activitypub implementers guide](https://socialhub.activitypub.rocks/t/draft-guide-for-new-activitypub-implementers/479) +- [Mastodon Blog: How to implement a basic ActivityPub server](https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/) +- [Mastodon Blog: Implementing an ActivityPub inbox](https://blog.joinmastodon.org/2018/07/how-to-make-friends-and-verify-requests/) +- [Data storage questions](https://socialhub.activitypub.rocks/t/data-storage-questions/579) +- [Activitypub as it has been understood](https://flak.tedunangst.com/post/ActivityPub-as-it-has-been-understood) + +## Examples and Libraries + +- [ActivityPub example server](https://github.com/tOkeshu/activitypub-example) +- [ActivityStreams crate](https://docs.rs/activitystreams/) +- [HTTP Signatures crate](https://git.asonix.dog/Aardwolf/http-signature-normalization) \ No newline at end of file From 9cc1cfc973b6b9a3075369003eead19cf686d868 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Tue, 8 Dec 2020 17:38:48 +0000 Subject: [PATCH 2/3] Apub local object handling (#1297) * Limit visibility of some traits and methods * WIP: alternative way to handle non-local object parsing * finish this * cleanup * Move check for locked post into Comment::from_apub() * Mark user as updated after fetching * Should set last_refreshed_at, not updated * Add ApubObject trait in DB, with method read_from_apub_id() * Create shared, generic implementation for `FromApub`, prefer local data * Check for community ban when parsing post/comment (fixes #1287) * Fix tests (changes in get_object_from_apub() prevented `Update` from working) * Support parsing `like.object` either as URL or object * Send out like.object as URL, instead of full object (fixes #1283) * add todo --- docs/src/contributing_apub_api_outline.md | 4 +- lemmy_api/src/community.rs | 3 +- lemmy_apub/src/activities/receive/comment.rs | 94 +++----------- .../src/activities/receive/comment_undo.rs | 40 ++---- .../src/activities/receive/community.rs | 6 +- lemmy_apub/src/activities/receive/post.rs | 61 ++------- .../src/activities/receive/post_undo.rs | 40 ++---- .../src/activities/receive/private_message.rs | 37 +----- lemmy_apub/src/activities/send/comment.rs | 14 +-- lemmy_apub/src/activities/send/post.rs | 14 +-- .../src/activities/send/private_message.rs | 2 +- lemmy_apub/src/activities/send/user.rs | 5 +- lemmy_apub/src/activity_queue.rs | 8 +- lemmy_apub/src/extensions/signatures.rs | 5 +- lemmy_apub/src/fetcher.rs | 101 +++++---------- lemmy_apub/src/http/comment.rs | 2 +- lemmy_apub/src/http/community.rs | 2 +- lemmy_apub/src/http/post.rs | 2 +- lemmy_apub/src/http/user.rs | 7 +- lemmy_apub/src/inbox/community_inbox.rs | 7 +- lemmy_apub/src/inbox/mod.rs | 6 +- lemmy_apub/src/inbox/receive_for_community.rs | 96 +++++++++++---- lemmy_apub/src/inbox/shared_inbox.rs | 7 +- lemmy_apub/src/inbox/user_inbox.rs | 3 +- lemmy_apub/src/lib.rs | 31 +---- lemmy_apub/src/objects/comment.rs | 44 ++++++- lemmy_apub/src/objects/community.rs | 24 +++- lemmy_apub/src/objects/mod.rs | 116 ++++++++++++++++-- lemmy_apub/src/objects/post.rs | 24 +++- lemmy_apub/src/objects/private_message.rs | 22 +++- lemmy_apub/src/objects/user.rs | 43 ++++++- lemmy_db/src/comment.rs | 33 ++--- lemmy_db/src/community.rs | 37 +++--- lemmy_db/src/lib.rs | 9 ++ lemmy_db/src/post.rs | 81 ++++++------ lemmy_db/src/private_message.rs | 45 +++---- lemmy_db/src/user.rs | 37 +++--- 37 files changed, 580 insertions(+), 532 deletions(-) diff --git a/docs/src/contributing_apub_api_outline.md b/docs/src/contributing_apub_api_outline.md index 92cdf9c0e..74280bd5f 100644 --- a/docs/src/contributing_apub_api_outline.md +++ b/docs/src/contributing_apub_api_outline.md @@ -438,7 +438,7 @@ Sent to: Community "cc": [ "https://ds9.lemmy.ml/c/main/" ], - "object": ... + "object": "https://enterprise.lemmy.ml/p/123" } ``` @@ -465,7 +465,7 @@ Sent to: Community "cc": [ "https://ds9.lemmy.ml/c/main/" ], - "object": ... + "object": "https://enterprise.lemmy.ml/p/123" } ``` diff --git a/lemmy_api/src/community.rs b/lemmy_api/src/community.rs index 762420202..d7de0e6bd 100644 --- a/lemmy_api/src/community.rs +++ b/lemmy_api/src/community.rs @@ -20,6 +20,7 @@ use lemmy_db::{ post::Post, site::*, user_view::*, + ApubObject, Bannable, Crud, Followable, @@ -129,7 +130,7 @@ impl Perform for CreateCommunity { let actor_id = make_apub_endpoint(EndpointType::Community, &data.name).to_string(); let actor_id_cloned = actor_id.to_owned(); let community_dupe = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, &actor_id_cloned) + Community::read_from_apub_id(conn, &actor_id_cloned) }) .await?; if community_dupe.is_ok() { diff --git a/lemmy_apub/src/activities/receive/comment.rs b/lemmy_apub/src/activities/receive/comment.rs index bf8de1ebd..ff0fb8199 100644 --- a/lemmy_apub/src/activities/receive/comment.rs +++ b/lemmy_apub/src/activities/receive/comment.rs @@ -1,20 +1,13 @@ -use crate::{ - activities::receive::get_actor_as_user, - fetcher::get_or_fetch_and_insert_comment, - ActorType, - FromApub, - NoteExt, -}; +use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, NoteExt}; use activitystreams::{ activity::{ActorAndObjectRefExt, Create, Dislike, Like, Remove, Update}, base::ExtendsExt, }; -use anyhow::{anyhow, Context}; +use anyhow::Context; use lemmy_db::{ - comment::{Comment, CommentForm, CommentLike, CommentLikeForm}, + comment::{Comment, CommentLike, CommentLikeForm}, comment_view::CommentView, post::Post, - Crud, Likeable, }; use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs}; @@ -30,36 +23,22 @@ pub(crate) async fn receive_create_comment( let note = NoteExt::from_any_base(create.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let comment = - CommentForm::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?; + let comment = Comment::from_apub(¬e, context, user.actor_id()?, request_counter).await?; let post_id = comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - if post.locked { - return Err(anyhow!("Post is locked").into()); - } - - let inserted_comment = - blocking(context.pool(), move |conn| Comment::upsert(conn, &comment)).await??; // Note: // Although mentions could be gotten from the post tags (they are included there), or the ccs, // Its much easier to scrape them from the comment body, since the API has to do that // anyway. - let mentions = scrape_text_for_mentions(&inserted_comment.content); - let recipient_ids = send_local_notifs( - mentions, - inserted_comment.clone(), - &user, - post, - context.pool(), - true, - ) - .await?; + let mentions = scrape_text_for_mentions(&comment.content); + let recipient_ids = + send_local_notifs(mentions, comment.clone(), &user, post, context.pool(), true).await?; // Refetch the view let comment_view = blocking(context.pool(), move |conn| { - CommentView::read(conn, inserted_comment.id, None) + CommentView::read(conn, comment.id, None) }) .await??; @@ -87,36 +66,19 @@ pub(crate) async fn receive_update_comment( .context(location_info!())?; let user = get_actor_as_user(&update, context, request_counter).await?; - let comment = - CommentForm::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?; + let comment = Comment::from_apub(¬e, context, user.actor_id()?, request_counter).await?; - let original_comment_id = - get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter) - .await? - .id; - - let updated_comment = blocking(context.pool(), move |conn| { - Comment::update(conn, original_comment_id, &comment) - }) - .await??; - - let post_id = updated_comment.post_id; + let comment_id = comment.id; + let post_id = comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - let mentions = scrape_text_for_mentions(&updated_comment.content); - let recipient_ids = send_local_notifs( - mentions, - updated_comment, - &user, - post, - context.pool(), - false, - ) - .await?; + let mentions = scrape_text_for_mentions(&comment.content); + let recipient_ids = + send_local_notifs(mentions, comment, &user, post, context.pool(), false).await?; // Refetch the view let comment_view = blocking(context.pool(), move |conn| { - CommentView::read(conn, original_comment_id, None) + CommentView::read(conn, comment_id, None) }) .await??; @@ -137,19 +99,13 @@ pub(crate) async fn receive_update_comment( pub(crate) async fn receive_like_comment( like: Like, + comment: Comment, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let note = NoteExt::from_any_base(like.object().to_owned().one().context(location_info!())?)? - .context(location_info!())?; let user = get_actor_as_user(&like, context, request_counter).await?; - let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?; - - let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter) - .await? - .id; - + let comment_id = comment.id; let like_form = CommentLikeForm { comment_id, post_id: comment.post_id, @@ -188,25 +144,13 @@ pub(crate) async fn receive_like_comment( pub(crate) async fn receive_dislike_comment( dislike: Dislike, + comment: Comment, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let note = NoteExt::from_any_base( - dislike - .object() - .to_owned() - .one() - .context(location_info!())?, - )? - .context(location_info!())?; let user = get_actor_as_user(&dislike, context, request_counter).await?; - let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?; - - let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter) - .await? - .id; - + let comment_id = comment.id; let like_form = CommentLikeForm { comment_id, post_id: comment.post_id, diff --git a/lemmy_apub/src/activities/receive/comment_undo.rs b/lemmy_apub/src/activities/receive/comment_undo.rs index f44604cc1..2ee8c6ea7 100644 --- a/lemmy_apub/src/activities/receive/comment_undo.rs +++ b/lemmy_apub/src/activities/receive/comment_undo.rs @@ -1,35 +1,23 @@ -use crate::{ - activities::receive::get_actor_as_user, - fetcher::get_or_fetch_and_insert_comment, - FromApub, - NoteExt, -}; -use activitystreams::{activity::*, prelude::*}; -use anyhow::Context; +use crate::activities::receive::get_actor_as_user; +use activitystreams::activity::{Dislike, Like}; use lemmy_db::{ - comment::{Comment, CommentForm, CommentLike}, + comment::{Comment, CommentLike}, comment_view::CommentView, Likeable, }; use lemmy_structs::{blocking, comment::CommentResponse}; -use lemmy_utils::{location_info, LemmyError}; +use lemmy_utils::LemmyError; use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation}; pub(crate) async fn receive_undo_like_comment( like: &Like, + comment: Comment, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(like, context, request_counter).await?; - let note = NoteExt::from_any_base(like.object().to_owned().one().context(location_info!())?)? - .context(location_info!())?; - - let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?; - - let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter) - .await? - .id; + let comment_id = comment.id; let user_id = user.id; blocking(context.pool(), move |conn| { CommentLike::remove(conn, user_id, comment_id) @@ -61,25 +49,13 @@ pub(crate) async fn receive_undo_like_comment( pub(crate) async fn receive_undo_dislike_comment( dislike: &Dislike, + comment: Comment, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(dislike, context, request_counter).await?; - let note = NoteExt::from_any_base( - dislike - .object() - .to_owned() - .one() - .context(location_info!())?, - )? - .context(location_info!())?; - - let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?; - - let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter) - .await? - .id; + let comment_id = comment.id; let user_id = user.id; blocking(context.pool(), move |conn| { CommentLike::remove(conn, user_id, comment_id) diff --git a/lemmy_apub/src/activities/receive/community.rs b/lemmy_apub/src/activities/receive/community.rs index ed43b33e3..b1866283b 100644 --- a/lemmy_apub/src/activities/receive/community.rs +++ b/lemmy_apub/src/activities/receive/community.rs @@ -4,7 +4,7 @@ use activitystreams::{ base::{AnyBase, ExtendsExt}, }; use anyhow::Context; -use lemmy_db::{community::Community, community_view::CommunityView}; +use lemmy_db::{community::Community, community_view::CommunityView, ApubObject}; use lemmy_structs::{blocking, community::CommunityResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation}; @@ -53,7 +53,7 @@ pub(crate) async fn receive_remove_community( .single_xsd_any_uri() .context(location_info!())?; let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, community_uri.as_str()) + Community::read_from_apub_id(conn, community_uri.as_str()) }) .await??; @@ -135,7 +135,7 @@ pub(crate) async fn receive_undo_remove_community( .single_xsd_any_uri() .context(location_info!())?; let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, community_uri.as_str()) + Community::read_from_apub_id(conn, community_uri.as_str()) }) .await??; diff --git a/lemmy_apub/src/activities/receive/post.rs b/lemmy_apub/src/activities/receive/post.rs index 80044237f..0bbf1eaf5 100644 --- a/lemmy_apub/src/activities/receive/post.rs +++ b/lemmy_apub/src/activities/receive/post.rs @@ -1,19 +1,12 @@ -use crate::{ - activities::receive::get_actor_as_user, - fetcher::get_or_fetch_and_insert_post, - ActorType, - FromApub, - PageExt, -}; +use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, PageExt}; use activitystreams::{ activity::{Create, Dislike, Like, Remove, Update}, prelude::*, }; use anyhow::Context; use lemmy_db::{ - post::{Post, PostForm, PostLike, PostLikeForm}, + post::{Post, PostLike, PostLikeForm}, post_view::PostView, - Crud, Likeable, }; use lemmy_structs::{blocking, post::PostResponse}; @@ -29,16 +22,12 @@ pub(crate) async fn receive_create_post( let page = PageExt::from_any_base(create.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let post = PostForm::from_apub(&page, context, Some(user.actor_id()?), request_counter).await?; - - // Using an upsert, since likes (which fetch the post), sometimes come in before the create - // resulting in double posts. - let inserted_post = blocking(context.pool(), move |conn| Post::upsert(conn, &post)).await??; + let post = Post::from_apub(&page, context, user.actor_id()?, request_counter).await?; // Refetch the view - let inserted_post_id = inserted_post.id; + let post_id = post.id; let post_view = blocking(context.pool(), move |conn| { - PostView::read(conn, inserted_post_id, None) + PostView::read(conn, post_id, None) }) .await??; @@ -62,20 +51,12 @@ pub(crate) async fn receive_update_post( let page = PageExt::from_any_base(update.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let post = PostForm::from_apub(&page, context, Some(user.actor_id()?), request_counter).await?; - - let original_post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter) - .await? - .id; - - blocking(context.pool(), move |conn| { - Post::update(conn, original_post_id, &post) - }) - .await??; + let post = Post::from_apub(&page, context, user.actor_id()?, request_counter).await?; + let post_id = post.id; // Refetch the view let post_view = blocking(context.pool(), move |conn| { - PostView::read(conn, original_post_id, None) + PostView::read(conn, post_id, None) }) .await??; @@ -92,19 +73,13 @@ pub(crate) async fn receive_update_post( pub(crate) async fn receive_like_post( like: Like, + post: Post, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(&like, context, request_counter).await?; - let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)? - .context(location_info!())?; - - let post = PostForm::from_apub(&page, context, None, request_counter).await?; - - let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter) - .await? - .id; + let post_id = post.id; let like_form = PostLikeForm { post_id, user_id: user.id, @@ -136,25 +111,13 @@ pub(crate) async fn receive_like_post( pub(crate) async fn receive_dislike_post( dislike: Dislike, + post: Post, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(&dislike, context, request_counter).await?; - let page = PageExt::from_any_base( - dislike - .object() - .to_owned() - .one() - .context(location_info!())?, - )? - .context(location_info!())?; - - let post = PostForm::from_apub(&page, context, None, request_counter).await?; - - let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter) - .await? - .id; + let post_id = post.id; let like_form = PostLikeForm { post_id, user_id: user.id, diff --git a/lemmy_apub/src/activities/receive/post_undo.rs b/lemmy_apub/src/activities/receive/post_undo.rs index 99d0ed1d9..bcbb7fee9 100644 --- a/lemmy_apub/src/activities/receive/post_undo.rs +++ b/lemmy_apub/src/activities/receive/post_undo.rs @@ -1,35 +1,23 @@ -use crate::{ - activities::receive::get_actor_as_user, - fetcher::get_or_fetch_and_insert_post, - FromApub, - PageExt, -}; -use activitystreams::{activity::*, prelude::*}; -use anyhow::Context; +use crate::activities::receive::get_actor_as_user; +use activitystreams::activity::{Dislike, Like}; use lemmy_db::{ - post::{Post, PostForm, PostLike}, + post::{Post, PostLike}, post_view::PostView, Likeable, }; use lemmy_structs::{blocking, post::PostResponse}; -use lemmy_utils::{location_info, LemmyError}; +use lemmy_utils::LemmyError; use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation}; pub(crate) async fn receive_undo_like_post( like: &Like, + post: Post, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(like, context, request_counter).await?; - let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)? - .context(location_info!())?; - - let post = PostForm::from_apub(&page, context, None, request_counter).await?; - - let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter) - .await? - .id; + let post_id = post.id; let user_id = user.id; blocking(context.pool(), move |conn| { PostLike::remove(conn, user_id, post_id) @@ -55,25 +43,13 @@ pub(crate) async fn receive_undo_like_post( pub(crate) async fn receive_undo_dislike_post( dislike: &Dislike, + post: Post, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(dislike, context, request_counter).await?; - let page = PageExt::from_any_base( - dislike - .object() - .to_owned() - .one() - .context(location_info!())?, - )? - .context(location_info!())?; - - let post = PostForm::from_apub(&page, context, None, request_counter).await?; - - let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter) - .await? - .id; + let post_id = post.id; let user_id = user.id; blocking(context.pool(), move |conn| { PostLike::remove(conn, user_id, post_id) diff --git a/lemmy_apub/src/activities/receive/private_message.rs b/lemmy_apub/src/activities/receive/private_message.rs index 8f1c95b9d..25ccc520d 100644 --- a/lemmy_apub/src/activities/receive/private_message.rs +++ b/lemmy_apub/src/activities/receive/private_message.rs @@ -3,7 +3,7 @@ use crate::{ check_is_apub_id_valid, fetcher::get_or_fetch_and_upsert_user, inbox::get_activity_to_and_cc, - FromApub, + objects::FromApub, NoteExt, }; use activitystreams::{ @@ -13,11 +13,7 @@ use activitystreams::{ public, }; use anyhow::{anyhow, Context}; -use lemmy_db::{ - private_message::{PrivateMessage, PrivateMessageForm}, - private_message_view::PrivateMessageView, - Crud, -}; +use lemmy_db::{private_message::PrivateMessage, private_message_view::PrivateMessageView}; use lemmy_structs::{blocking, user::PrivateMessageResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperation}; @@ -41,15 +37,10 @@ pub(crate) async fn receive_create_private_message( .context(location_info!())?; let private_message = - PrivateMessageForm::from_apub(¬e, context, Some(expected_domain), request_counter).await?; - - let inserted_private_message = blocking(&context.pool(), move |conn| { - PrivateMessage::create(conn, &private_message) - }) - .await??; + PrivateMessage::from_apub(¬e, context, expected_domain, request_counter).await?; let message = blocking(&context.pool(), move |conn| { - PrivateMessageView::read(conn, inserted_private_message.id) + PrivateMessageView::read(conn, private_message.id) }) .await??; @@ -82,24 +73,8 @@ pub(crate) async fn receive_update_private_message( .to_owned(); let note = NoteExt::from_any_base(object)?.context(location_info!())?; - let private_message_form = - PrivateMessageForm::from_apub(¬e, context, Some(expected_domain), request_counter).await?; - - let private_message_ap_id = private_message_form - .ap_id - .as_ref() - .context(location_info!())? - .clone(); - let private_message = blocking(&context.pool(), move |conn| { - PrivateMessage::read_from_apub_id(conn, &private_message_ap_id) - }) - .await??; - - let private_message_id = private_message.id; - blocking(&context.pool(), move |conn| { - PrivateMessage::update(conn, private_message_id, &private_message_form) - }) - .await??; + let private_message = + PrivateMessage::from_apub(¬e, context, expected_domain, request_counter).await?; let private_message_id = private_message.id; let message = blocking(&context.pool(), move |conn| { diff --git a/lemmy_apub/src/activities/send/comment.rs b/lemmy_apub/src/activities/send/comment.rs index 2aee7b6e3..744a1cddb 100644 --- a/lemmy_apub/src/activities/send/comment.rs +++ b/lemmy_apub/src/activities/send/comment.rs @@ -3,10 +3,10 @@ use crate::{ activity_queue::{send_comment_mentions, send_to_community}, extensions::context::lemmy_context, fetcher::get_or_fetch_and_upsert_user, + objects::ToApub, ActorType, ApubLikeableType, ApubObjectType, - ToApub, }; use activitystreams::{ activity::{ @@ -218,8 +218,6 @@ impl ApubObjectType for Comment { #[async_trait::async_trait(?Send)] impl ApubLikeableType for Comment { async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { - let note = self.to_apub(context.pool()).await?; - let post_id = self.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -229,7 +227,7 @@ impl ApubLikeableType for Comment { }) .await??; - let mut like = Like::new(creator.actor_id.to_owned(), note.into_any_base()?); + let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); like .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(LikeType::Like)?) @@ -241,8 +239,6 @@ impl ApubLikeableType for Comment { } async fn send_dislike(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { - let note = self.to_apub(context.pool()).await?; - let post_id = self.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -252,7 +248,7 @@ impl ApubLikeableType for Comment { }) .await??; - let mut dislike = Dislike::new(creator.actor_id.to_owned(), note.into_any_base()?); + let mut dislike = Dislike::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); dislike .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(DislikeType::Dislike)?) @@ -268,8 +264,6 @@ impl ApubLikeableType for Comment { creator: &User_, context: &LemmyContext, ) -> Result<(), LemmyError> { - let note = self.to_apub(context.pool()).await?; - let post_id = self.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -279,7 +273,7 @@ impl ApubLikeableType for Comment { }) .await??; - let mut like = Like::new(creator.actor_id.to_owned(), note.into_any_base()?); + let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); like .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(DislikeType::Dislike)?) diff --git a/lemmy_apub/src/activities/send/post.rs b/lemmy_apub/src/activities/send/post.rs index da78667f0..f6eabb048 100644 --- a/lemmy_apub/src/activities/send/post.rs +++ b/lemmy_apub/src/activities/send/post.rs @@ -2,10 +2,10 @@ use crate::{ activities::send::generate_activity_id, activity_queue::send_to_community, extensions::context::lemmy_context, + objects::ToApub, ActorType, ApubLikeableType, ApubObjectType, - ToApub, }; use activitystreams::{ activity::{ @@ -167,15 +167,13 @@ impl ApubObjectType for Post { #[async_trait::async_trait(?Send)] impl ApubLikeableType for Post { async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { - let page = self.to_apub(context.pool()).await?; - let community_id = self.community_id; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) }) .await??; - let mut like = Like::new(creator.actor_id.to_owned(), page.into_any_base()?); + let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); like .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(LikeType::Like)?) @@ -187,15 +185,13 @@ impl ApubLikeableType for Post { } async fn send_dislike(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { - let page = self.to_apub(context.pool()).await?; - let community_id = self.community_id; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) }) .await??; - let mut dislike = Dislike::new(creator.actor_id.to_owned(), page.into_any_base()?); + let mut dislike = Dislike::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); dislike .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(DislikeType::Dislike)?) @@ -211,15 +207,13 @@ impl ApubLikeableType for Post { creator: &User_, context: &LemmyContext, ) -> Result<(), LemmyError> { - let page = self.to_apub(context.pool()).await?; - let community_id = self.community_id; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) }) .await??; - let mut like = Like::new(creator.actor_id.to_owned(), page.into_any_base()?); + let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); like .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(LikeType::Like)?) diff --git a/lemmy_apub/src/activities/send/private_message.rs b/lemmy_apub/src/activities/send/private_message.rs index 23528b5c7..e8bc979a7 100644 --- a/lemmy_apub/src/activities/send/private_message.rs +++ b/lemmy_apub/src/activities/send/private_message.rs @@ -2,9 +2,9 @@ use crate::{ activities::send::generate_activity_id, activity_queue::send_activity_single_dest, extensions::context::lemmy_context, + objects::ToApub, ActorType, ApubObjectType, - ToApub, }; use activitystreams::{ activity::{ diff --git a/lemmy_apub/src/activities/send/user.rs b/lemmy_apub/src/activities/send/user.rs index a94f241da..8c539c4b0 100644 --- a/lemmy_apub/src/activities/send/user.rs +++ b/lemmy_apub/src/activities/send/user.rs @@ -16,6 +16,7 @@ use activitystreams::{ use lemmy_db::{ community::{Community, CommunityFollower, CommunityFollowerForm}, user::User_, + ApubObject, DbPool, Followable, }; @@ -46,7 +47,7 @@ impl ActorType for User_ { ) -> Result<(), LemmyError> { let follow_actor_id = follow_actor_id.to_string(); let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, &follow_actor_id) + Community::read_from_apub_id(conn, &follow_actor_id) }) .await??; @@ -77,7 +78,7 @@ impl ActorType for User_ { ) -> Result<(), LemmyError> { let follow_actor_id = follow_actor_id.to_string(); let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, &follow_actor_id) + Community::read_from_apub_id(conn, &follow_actor_id) }) .await??; diff --git a/lemmy_apub/src/activity_queue.rs b/lemmy_apub/src/activity_queue.rs index 5e4f113b5..467802794 100644 --- a/lemmy_apub/src/activity_queue.rs +++ b/lemmy_apub/src/activity_queue.rs @@ -33,7 +33,7 @@ use url::Url; /// * `activity` the apub activity to be sent /// * `creator` the local actor which created the activity /// * `inbox` the inbox url where the activity should be delivered to -pub async fn send_activity_single_dest( +pub(crate) async fn send_activity_single_dest( activity: T, creator: &dyn ActorType, inbox: Url, @@ -71,7 +71,7 @@ where /// * `community` the sending community /// * `sender_shared_inbox` in case of an announce, this should be the shared inbox of the inner /// activities creator, as receiving a known activity will cause an error -pub async fn send_to_community_followers( +pub(crate) async fn send_to_community_followers( activity: T, community: &Community, context: &LemmyContext, @@ -116,7 +116,7 @@ where /// * `creator` the creator of the activity /// * `community` the destination community /// -pub async fn send_to_community( +pub(crate) async fn send_to_community( activity: T, creator: &User_, community: &Community, @@ -160,7 +160,7 @@ where /// * `creator` user who created the comment /// * `mentions` list of inboxes of users which are mentioned in the comment /// * `activity` either a `Create/Note` or `Update/Note` -pub async fn send_comment_mentions( +pub(crate) async fn send_comment_mentions( creator: &User_, mentions: Vec, activity: T, diff --git a/lemmy_apub/src/extensions/signatures.rs b/lemmy_apub/src/extensions/signatures.rs index 6ff61df45..67fe4b1cd 100644 --- a/lemmy_apub/src/extensions/signatures.rs +++ b/lemmy_apub/src/extensions/signatures.rs @@ -65,7 +65,10 @@ pub async fn sign_and_send( } /// Verifies the HTTP signature on an incoming inbox request. -pub fn verify_signature(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyError> { +pub(crate) fn verify_signature( + request: &HttpRequest, + actor: &dyn ActorType, +) -> Result<(), LemmyError> { let public_key = actor.public_key().context(location_info!())?; let verified = CONFIG2 .begin_verify( diff --git a/lemmy_apub/src/fetcher.rs b/lemmy_apub/src/fetcher.rs index ec44bce17..ad977f5b1 100644 --- a/lemmy_apub/src/fetcher.rs +++ b/lemmy_apub/src/fetcher.rs @@ -1,7 +1,7 @@ use crate::{ check_is_apub_id_valid, + objects::FromApub, ActorType, - FromApub, GroupExt, NoteExt, PageExt, @@ -13,16 +13,16 @@ use anyhow::{anyhow, Context}; use chrono::NaiveDateTime; use diesel::result::Error::NotFound; use lemmy_db::{ - comment::{Comment, CommentForm}, + comment::Comment, comment_view::CommentView, - community::{Community, CommunityForm, CommunityModerator, CommunityModeratorForm}, + community::{Community, CommunityModerator, CommunityModeratorForm}, community_view::CommunityView, naive_now, - post::{Post, PostForm}, + post::Post, post_view::PostView, - user::{UserForm, User_}, + user::User_, user_view::UserView, - Crud, + ApubObject, Joinable, SearchType, }; @@ -184,22 +184,16 @@ pub async fn search_by_apub_id( response } SearchAcceptedObjects::Page(p) => { - let post_form = PostForm::from_apub(&p, context, Some(query_url), recursion_counter).await?; + let p = Post::from_apub(&p, context, query_url, recursion_counter).await?; - let p = blocking(context.pool(), move |conn| Post::upsert(conn, &post_form)).await??; response.posts = vec![blocking(context.pool(), move |conn| PostView::read(conn, p.id, None)).await??]; response } SearchAcceptedObjects::Comment(c) => { - let comment_form = - CommentForm::from_apub(&c, context, Some(query_url), recursion_counter).await?; + let c = Comment::from_apub(&c, context, query_url, recursion_counter).await?; - let c = blocking(context.pool(), move |conn| { - Comment::upsert(conn, &comment_form) - }) - .await??; response.comments = vec![ blocking(context.pool(), move |conn| { CommentView::read(conn, c.id, None) @@ -243,7 +237,7 @@ pub(crate) async fn get_or_fetch_and_upsert_user( ) -> Result { let apub_id_owned = apub_id.to_owned(); let user = blocking(context.pool(), move |conn| { - User_::read_from_actor_id(conn, apub_id_owned.as_ref()) + User_::read_from_apub_id(conn, apub_id_owned.as_ref()) }) .await?; @@ -258,15 +252,13 @@ pub(crate) async fn get_or_fetch_and_upsert_user( return Ok(u); } - let mut uf = UserForm::from_apub( - &person?, - context, - Some(apub_id.to_owned()), - recursion_counter, - ) - .await?; - uf.last_refreshed_at = Some(naive_now()); - let user = blocking(context.pool(), move |conn| User_::update(conn, u.id, &uf)).await??; + let user = User_::from_apub(&person?, context, apub_id.to_owned(), recursion_counter).await?; + + let user_id = user.id; + blocking(context.pool(), move |conn| { + User_::mark_as_updated(conn, user_id) + }) + .await??; Ok(user) } @@ -276,14 +268,7 @@ pub(crate) async fn get_or_fetch_and_upsert_user( let person = fetch_remote_object::(context.client(), apub_id, recursion_counter).await?; - let uf = UserForm::from_apub( - &person, - context, - Some(apub_id.to_owned()), - recursion_counter, - ) - .await?; - let user = blocking(context.pool(), move |conn| User_::upsert(conn, &uf)).await??; + let user = User_::from_apub(&person, context, apub_id.to_owned(), recursion_counter).await?; Ok(user) } @@ -318,7 +303,7 @@ pub(crate) async fn get_or_fetch_and_upsert_community( ) -> Result { let apub_id_owned = apub_id.to_owned(); let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, apub_id_owned.as_str()) + Community::read_from_apub_id(conn, apub_id_owned.as_str()) }) .await?; @@ -354,9 +339,8 @@ async fn fetch_remote_community( } let group = group?; - let cf = - CommunityForm::from_apub(&group, context, Some(apub_id.to_owned()), recursion_counter).await?; - let community = blocking(context.pool(), move |conn| Community::upsert(conn, &cf)).await??; + let community = + Community::from_apub(&group, context, apub_id.to_owned(), recursion_counter).await?; // Also add the community moderators too let attributed_to = group.inner.attributed_to().context(location_info!())?; @@ -406,23 +390,13 @@ async fn fetch_remote_community( } for o in outbox_items { let page = PageExt::from_any_base(o)?.context(location_info!())?; + let page_id = page.id_unchecked().context(location_info!())?; - // The post creator may be from a blocked instance, - // if it errors, then continue - let post = match PostForm::from_apub(&page, context, None, recursion_counter).await { - Ok(post) => post, - Err(_) => continue, - }; - let post_ap_id = post.ap_id.as_ref().context(location_info!())?.clone(); - // Check whether the post already exists in the local db - let existing = blocking(context.pool(), move |conn| { - Post::read_from_apub_id(conn, &post_ap_id) - }) - .await?; - match existing { - Ok(e) => blocking(context.pool(), move |conn| Post::update(conn, e.id, &post)).await??, - Err(_) => blocking(context.pool(), move |conn| Post::upsert(conn, &post)).await??, - }; + // The post creator may be from a blocked instance, if it errors, then skip it + if check_is_apub_id_valid(page_id).is_err() { + continue; + } + Post::from_apub(&page, context, page_id.to_owned(), recursion_counter).await?; // TODO: we need to send a websocket update here } @@ -448,17 +422,9 @@ pub(crate) async fn get_or_fetch_and_insert_post( Ok(p) => Ok(p), Err(NotFound {}) => { debug!("Fetching and creating remote post: {}", post_ap_id); - let post = + let page = fetch_remote_object::(context.client(), post_ap_id, recursion_counter).await?; - let post_form = PostForm::from_apub( - &post, - context, - Some(post_ap_id.to_owned()), - recursion_counter, - ) - .await?; - - let post = blocking(context.pool(), move |conn| Post::upsert(conn, &post_form)).await??; + let post = Post::from_apub(&page, context, post_ap_id.to_owned(), recursion_counter).await?; Ok(post) } @@ -490,25 +456,20 @@ pub(crate) async fn get_or_fetch_and_insert_comment( ); let comment = fetch_remote_object::(context.client(), comment_ap_id, recursion_counter).await?; - let comment_form = CommentForm::from_apub( + let comment = Comment::from_apub( &comment, context, - Some(comment_ap_id.to_owned()), + comment_ap_id.to_owned(), recursion_counter, ) .await?; - let post_id = comment_form.post_id; + let post_id = comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; if post.locked { return Err(anyhow!("Post is locked").into()); } - let comment = blocking(context.pool(), move |conn| { - Comment::upsert(conn, &comment_form) - }) - .await??; - Ok(comment) } Err(e) => Err(e.into()), diff --git a/lemmy_apub/src/http/comment.rs b/lemmy_apub/src/http/comment.rs index 936cd9813..bb3d13ace 100644 --- a/lemmy_apub/src/http/comment.rs +++ b/lemmy_apub/src/http/comment.rs @@ -1,6 +1,6 @@ use crate::{ http::{create_apub_response, create_apub_tombstone_response}, - ToApub, + objects::ToApub, }; use actix_web::{body::Body, web, web::Path, HttpResponse}; use diesel::result::Error::NotFound; diff --git a/lemmy_apub/src/http/community.rs b/lemmy_apub/src/http/community.rs index 0e2f2802e..0a90571ff 100644 --- a/lemmy_apub/src/http/community.rs +++ b/lemmy_apub/src/http/community.rs @@ -1,8 +1,8 @@ use crate::{ extensions::context::lemmy_context, http::{create_apub_response, create_apub_tombstone_response}, + objects::ToApub, ActorType, - ToApub, }; use activitystreams::{ base::{AnyBase, BaseExt, ExtendsExt}, diff --git a/lemmy_apub/src/http/post.rs b/lemmy_apub/src/http/post.rs index 7f4bb447c..1d25ed958 100644 --- a/lemmy_apub/src/http/post.rs +++ b/lemmy_apub/src/http/post.rs @@ -1,6 +1,6 @@ use crate::{ http::{create_apub_response, create_apub_tombstone_response}, - ToApub, + objects::ToApub, }; use actix_web::{body::Body, web, HttpResponse}; use diesel::result::Error::NotFound; diff --git a/lemmy_apub/src/http/user.rs b/lemmy_apub/src/http/user.rs index 0f2e1a71c..1e546d953 100644 --- a/lemmy_apub/src/http/user.rs +++ b/lemmy_apub/src/http/user.rs @@ -1,4 +1,9 @@ -use crate::{extensions::context::lemmy_context, http::create_apub_response, ActorType, ToApub}; +use crate::{ + extensions::context::lemmy_context, + http::create_apub_response, + objects::ToApub, + ActorType, +}; use activitystreams::{ base::BaseExt, collection::{CollectionExt, OrderedCollection}, diff --git a/lemmy_apub/src/inbox/community_inbox.rs b/lemmy_apub/src/inbox/community_inbox.rs index 7c144a00d..4bdad2fad 100644 --- a/lemmy_apub/src/inbox/community_inbox.rs +++ b/lemmy_apub/src/inbox/community_inbox.rs @@ -30,6 +30,7 @@ use lemmy_db::{ community::{Community, CommunityFollower, CommunityFollowerForm}, community_view::CommunityUserBanView, user::User_, + ApubObject, DbPool, Followable, }; @@ -118,7 +119,7 @@ pub(crate) async fn community_receive_message( // unconditionally. let actor_id = actor.actor_id_str(); let user = blocking(&context.pool(), move |conn| { - User_::read_from_actor_id(&conn, &actor_id) + User_::read_from_apub_id(&conn, &actor_id) }) .await??; check_community_or_site_ban(&user, &to_community, context.pool()).await?; @@ -242,7 +243,7 @@ async fn handle_undo_follow( verify_activity_domains_valid(&follow, &user_url, false)?; let user = blocking(&context.pool(), move |conn| { - User_::read_from_actor_id(&conn, user_url.as_str()) + User_::read_from_apub_id(&conn, user_url.as_str()) }) .await??; let community_follower_form = CommunityFollowerForm { @@ -260,7 +261,7 @@ async fn handle_undo_follow( Ok(()) } -async fn check_community_or_site_ban( +pub(crate) async fn check_community_or_site_ban( user: &User_, community: &Community, pool: &DbPool, diff --git a/lemmy_apub/src/inbox/mod.rs b/lemmy_apub/src/inbox/mod.rs index ce6c7eded..e04fdd0ff 100644 --- a/lemmy_apub/src/inbox/mod.rs +++ b/lemmy_apub/src/inbox/mod.rs @@ -12,7 +12,7 @@ use activitystreams::{ }; use actix_web::HttpRequest; use anyhow::{anyhow, Context}; -use lemmy_db::{activity::Activity, community::Community, user::User_, DbPool}; +use lemmy_db::{activity::Activity, community::Community, user::User_, ApubObject, DbPool}; use lemmy_structs::blocking; use lemmy_utils::{location_info, settings::Settings, LemmyError}; use lemmy_websocket::LemmyContext; @@ -119,7 +119,7 @@ pub(crate) async fn is_addressed_to_local_user( ) -> Result { for url in to_and_cc { let url = url.to_string(); - let user = blocking(&pool, move |conn| User_::read_from_actor_id(&conn, &url)).await?; + let user = blocking(&pool, move |conn| User_::read_from_apub_id(&conn, &url)).await?; if let Ok(u) = user { if u.local { return Ok(true); @@ -141,7 +141,7 @@ pub(crate) async fn is_addressed_to_community_followers( if url.ends_with("/followers") { let community_url = url.replace("/followers", ""); let community = blocking(&pool, move |conn| { - Community::read_from_actor_id(&conn, &community_url) + Community::read_from_apub_id(&conn, &community_url) }) .await??; if !community.local { diff --git a/lemmy_apub/src/inbox/receive_for_community.rs b/lemmy_apub/src/inbox/receive_for_community.rs index b6dfa1e42..eaad6b1cc 100644 --- a/lemmy_apub/src/inbox/receive_for_community.rs +++ b/lemmy_apub/src/inbox/receive_for_community.rs @@ -31,6 +31,7 @@ use crate::{ receive_unhandled_activity, verify_activity_domains_valid, }, + fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post}, inbox::is_addressed_to_public, }; use activitystreams::{ @@ -40,7 +41,7 @@ use activitystreams::{ }; use anyhow::Context; use diesel::result::Error::NotFound; -use lemmy_db::{comment::Comment, post::Post, site::Site, Crud}; +use lemmy_db::{comment::Comment, post::Post, site::Site, ApubObject, Crud}; use lemmy_structs::blocking; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; @@ -96,10 +97,12 @@ pub(in crate::inbox) async fn receive_like_for_community( verify_activity_domains_valid(&like, &expected_domain, false)?; is_addressed_to_public(&like)?; - match like.object().as_single_kind_str() { - Some("Page") => receive_like_post(like, context, request_counter).await, - Some("Note") => receive_like_comment(like, context, request_counter).await, - _ => receive_unhandled_activity(like), + let object_id = get_like_object_id(&like)?; + match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { + PostOrComment::Post(post) => receive_like_post(like, post, context, request_counter).await, + PostOrComment::Comment(comment) => { + receive_like_comment(like, comment, context, request_counter).await + } } } @@ -122,10 +125,14 @@ pub(in crate::inbox) async fn receive_dislike_for_community( verify_activity_domains_valid(&dislike, &expected_domain, false)?; is_addressed_to_public(&dislike)?; - match dislike.object().as_single_kind_str() { - Some("Page") => receive_dislike_post(dislike, context, request_counter).await, - Some("Note") => receive_dislike_comment(dislike, context, request_counter).await, - _ => receive_unhandled_activity(dislike), + let object_id = get_like_object_id(&dislike)?; + match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { + PostOrComment::Post(post) => { + receive_dislike_post(dislike, post, context, request_counter).await + } + PostOrComment::Comment(comment) => { + receive_dislike_comment(dislike, comment, context, request_counter).await + } } } @@ -275,14 +282,14 @@ pub(in crate::inbox) async fn receive_undo_like_for_community( verify_activity_domains_valid(&like, &expected_domain, false)?; is_addressed_to_public(&like)?; - let type_ = like - .object() - .as_single_kind_str() - .context(location_info!())?; - match type_ { - "Note" => receive_undo_like_comment(&like, context, request_counter).await, - "Page" => receive_undo_like_post(&like, context, request_counter).await, - _ => receive_unhandled_activity(like), + let object_id = get_like_object_id(&like)?; + match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { + PostOrComment::Post(post) => { + receive_undo_like_post(&like, post, context, request_counter).await + } + PostOrComment::Comment(comment) => { + receive_undo_like_comment(&like, comment, context, request_counter).await + } } } @@ -298,14 +305,14 @@ pub(in crate::inbox) async fn receive_undo_dislike_for_community( verify_activity_domains_valid(&dislike, &expected_domain, false)?; is_addressed_to_public(&dislike)?; - let type_ = dislike - .object() - .as_single_kind_str() - .context(location_info!())?; - match type_ { - "Note" => receive_undo_dislike_comment(&dislike, context, request_counter).await, - "Page" => receive_undo_dislike_post(&dislike, context, request_counter).await, - _ => receive_unhandled_activity(dislike), + let object_id = get_like_object_id(&dislike)?; + match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { + PostOrComment::Post(post) => { + receive_undo_dislike_post(&dislike, post, context, request_counter).await + } + PostOrComment::Comment(comment) => { + receive_undo_dislike_comment(&dislike, comment, context, request_counter).await + } } } @@ -341,3 +348,42 @@ async fn find_post_or_comment_by_id( return Err(NotFound.into()); } + +async fn fetch_post_or_comment_by_id( + apub_id: &Url, + context: &LemmyContext, + request_counter: &mut i32, +) -> Result { + if let Ok(post) = get_or_fetch_and_insert_post(apub_id, context, request_counter).await { + return Ok(PostOrComment::Post(post)); + } + + if let Ok(comment) = get_or_fetch_and_insert_comment(apub_id, context, request_counter).await { + return Ok(PostOrComment::Comment(comment)); + } + + return Err(NotFound.into()); +} + +fn get_like_object_id(like_or_dislike: &Activity) -> Result +where + Activity: ActorAndObjectRefExt, +{ + // TODO: For backwards compatibility with older Lemmy versions where like.object contains a full + // post/comment. This can be removed after some time, using + // `activity.oject().as_single_xsd_any_uri()` instead. + let object = like_or_dislike.object(); + if let Some(xsd_uri) = object.as_single_xsd_any_uri() { + Ok(xsd_uri.to_owned()) + } else { + Ok( + object + .to_owned() + .one() + .context(location_info!())? + .id() + .context(location_info!())? + .to_owned(), + ) + } +} diff --git a/lemmy_apub/src/inbox/shared_inbox.rs b/lemmy_apub/src/inbox/shared_inbox.rs index 2875696e2..826038bf0 100644 --- a/lemmy_apub/src/inbox/shared_inbox.rs +++ b/lemmy_apub/src/inbox/shared_inbox.rs @@ -15,7 +15,7 @@ use crate::{ use activitystreams::{activity::ActorAndObject, prelude::*}; use actix_web::{web, HttpRequest, HttpResponse}; use anyhow::Context; -use lemmy_db::{community::Community, DbPool}; +use lemmy_db::{community::Community, ApubObject, DbPool}; use lemmy_structs::blocking; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; @@ -137,10 +137,7 @@ async fn extract_local_community_from_destinations( ) -> Result, LemmyError> { for url in to_and_cc { let url = url.to_string(); - let community = blocking(&pool, move |conn| { - Community::read_from_actor_id(&conn, &url) - }) - .await?; + let community = blocking(&pool, move |conn| Community::read_from_apub_id(&conn, &url)).await?; if let Ok(c) = community { if c.local { return Ok(Some(c)); diff --git a/lemmy_apub/src/inbox/user_inbox.rs b/lemmy_apub/src/inbox/user_inbox.rs index 2f847a5cd..81b9f1853 100644 --- a/lemmy_apub/src/inbox/user_inbox.rs +++ b/lemmy_apub/src/inbox/user_inbox.rs @@ -52,6 +52,7 @@ use lemmy_db::{ community::{Community, CommunityFollower}, private_message::PrivateMessage, user::User_, + ApubObject, Followable, }; use lemmy_structs::blocking; @@ -377,7 +378,7 @@ async fn find_community_or_private_message_by_id( ) -> Result { let ap_id = apub_id.to_string(); let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, &ap_id) + Community::read_from_apub_id(conn, &ap_id) }) .await?; if let Ok(c) = community { diff --git a/lemmy_apub/src/lib.rs b/lemmy_apub/src/lib.rs index 2e3f7bfc6..9b933b6e0 100644 --- a/lemmy_apub/src/lib.rs +++ b/lemmy_apub/src/lib.rs @@ -18,7 +18,7 @@ use activitystreams::{ activity::Follow, actor::{ApActor, Group, Person}, base::AnyBase, - object::{ApObject, Note, Page, Tombstone}, + object::{ApObject, Note, Page}, }; use activitystreams_ext::{Ext1, Ext2}; use anyhow::{anyhow, Context}; @@ -109,33 +109,6 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> { } } -/// Trait for converting an object or actor into the respective ActivityPub type. -#[async_trait::async_trait(?Send)] -pub trait ToApub { - type ApubType; - async fn to_apub(&self, pool: &DbPool) -> Result; - fn to_tombstone(&self) -> Result; -} - -#[async_trait::async_trait(?Send)] -pub trait FromApub { - type ApubType; - /// Converts an object from ActivityPub type to Lemmy internal type. - /// - /// * `apub` The object to read from - /// * `context` LemmyContext which holds DB pool, HTTP client etc - /// * `expected_domain` If present, ensure that the domains of this and of the apub object ID are - /// identical - async fn from_apub( - apub: &Self::ApubType, - context: &LemmyContext, - expected_domain: Option, - request_counter: &mut i32, - ) -> Result - where - Self: Sized; -} - /// Common functions for ActivityPub objects, which are implemented by most (but not all) objects /// and actors in Lemmy. #[async_trait::async_trait(?Send)] @@ -248,7 +221,7 @@ pub trait ActorType { /// Store a sent or received activity in the database, for logging purposes. These records are not /// persistent. -pub async fn insert_activity( +pub(crate) async fn insert_activity( ap_id: &Url, activity: T, local: bool, diff --git a/lemmy_apub/src/objects/comment.rs b/lemmy_apub/src/objects/comment.rs index 277a55d06..56d75a404 100644 --- a/lemmy_apub/src/objects/comment.rs +++ b/lemmy_apub/src/objects/comment.rs @@ -7,19 +7,22 @@ use crate::{ }, objects::{ check_object_domain, + check_object_for_community_or_site_ban, create_tombstone, + get_object_from_apub, get_source_markdown_value, set_content_and_source, + FromApub, + FromApubToForm, + ToApub, }, - FromApub, NoteExt, - ToApub, }; use activitystreams::{ object::{kind::NoteType, ApObject, Note, Tombstone}, prelude::*, }; -use anyhow::Context; +use anyhow::{anyhow, Context}; use lemmy_db::{ comment::{Comment, CommentForm}, community::Community, @@ -87,16 +90,45 @@ impl ToApub for Comment { } #[async_trait::async_trait(?Send)] -impl FromApub for CommentForm { +impl FromApub for Comment { type ApubType = NoteExt; - /// Converts a `Note` to `CommentForm`. + /// Converts a `Note` to `Comment`. /// /// If the parent community, post and comment(s) are not known locally, these are also fetched. async fn from_apub( note: &NoteExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, + request_counter: &mut i32, + ) -> Result { + check_object_for_community_or_site_ban(note, context, request_counter).await?; + + let comment: Comment = + get_object_from_apub(note, context, expected_domain, request_counter).await?; + + let post_id = comment.post_id; + let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; + if post.locked { + // This is not very efficient because a comment gets inserted just to be deleted right + // afterwards, but it seems to be the easiest way to implement it. + blocking(context.pool(), move |conn| { + Comment::delete(conn, comment.id) + }) + .await??; + return Err(anyhow!("Post is locked").into()); + } else { + Ok(comment) + } + } +} + +#[async_trait::async_trait(?Send)] +impl FromApubToForm for CommentForm { + async fn from_apub( + note: &NoteExt, + context: &LemmyContext, + expected_domain: Url, request_counter: &mut i32, ) -> Result { let creator_actor_id = ¬e diff --git a/lemmy_apub/src/objects/community.rs b/lemmy_apub/src/objects/community.rs index 2b383ba5b..594a5b5ee 100644 --- a/lemmy_apub/src/objects/community.rs +++ b/lemmy_apub/src/objects/community.rs @@ -4,13 +4,15 @@ use crate::{ objects::{ check_object_domain, create_tombstone, + get_object_from_apub, get_source_markdown_value, set_content_and_source, + FromApub, + FromApubToForm, + ToApub, }, ActorType, - FromApub, GroupExt, - ToApub, }; use activitystreams::{ actor::{kind::GroupType, ApActor, Endpoints, Group}, @@ -106,14 +108,28 @@ impl ToApub for Community { create_tombstone(self.deleted, &self.actor_id, self.updated, GroupType::Group) } } + #[async_trait::async_trait(?Send)] -impl FromApub for CommunityForm { +impl FromApub for Community { type ApubType = GroupExt; + /// Converts a `Group` to `Community`. async fn from_apub( group: &GroupExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, + request_counter: &mut i32, + ) -> Result { + get_object_from_apub(group, context, expected_domain, request_counter).await + } +} + +#[async_trait::async_trait(?Send)] +impl FromApubToForm for CommunityForm { + async fn from_apub( + group: &GroupExt, + context: &LemmyContext, + expected_domain: Url, request_counter: &mut i32, ) -> Result { let creator_and_moderator_uris = group.inner.attributed_to().context(location_info!())?; diff --git a/lemmy_apub/src/objects/mod.rs b/lemmy_apub/src/objects/mod.rs index a162c165b..898c50f31 100644 --- a/lemmy_apub/src/objects/mod.rs +++ b/lemmy_apub/src/objects/mod.rs @@ -1,4 +1,8 @@ -use crate::check_is_apub_id_valid; +use crate::{ + check_is_apub_id_valid, + fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user}, + inbox::community_inbox::check_community_or_site_ban, +}; use activitystreams::{ base::{AsBase, BaseExt, ExtendsExt}, markers::Base, @@ -7,7 +11,10 @@ use activitystreams::{ }; use anyhow::{anyhow, Context}; use chrono::NaiveDateTime; -use lemmy_utils::{location_info, utils::convert_datetime, LemmyError}; +use lemmy_db::{ApubObject, Crud, DbPool}; +use lemmy_structs::blocking; +use lemmy_utils::{location_info, settings::Settings, utils::convert_datetime, LemmyError}; +use lemmy_websocket::LemmyContext; use url::Url; pub(crate) mod comment; @@ -16,6 +23,44 @@ pub(crate) mod post; pub(crate) mod private_message; pub(crate) mod user; +/// Trait for converting an object or actor into the respective ActivityPub type. +#[async_trait::async_trait(?Send)] +pub(crate) trait ToApub { + type ApubType; + async fn to_apub(&self, pool: &DbPool) -> Result; + fn to_tombstone(&self) -> Result; +} + +#[async_trait::async_trait(?Send)] +pub(crate) trait FromApub { + type ApubType; + /// Converts an object from ActivityPub type to Lemmy internal type. + /// + /// * `apub` The object to read from + /// * `context` LemmyContext which holds DB pool, HTTP client etc + /// * `expected_domain` Domain where the object was received from + async fn from_apub( + apub: &Self::ApubType, + context: &LemmyContext, + expected_domain: Url, + request_counter: &mut i32, + ) -> Result + where + Self: Sized; +} + +#[async_trait::async_trait(?Send)] +pub(in crate::objects) trait FromApubToForm { + async fn from_apub( + apub: &ApubType, + context: &LemmyContext, + expected_domain: Url, + request_counter: &mut i32, + ) -> Result + where + Self: Sized; +} + /// Updated is actually the deletion time fn create_tombstone( deleted: bool, @@ -43,17 +88,13 @@ where pub(in crate::objects) fn check_object_domain( apub: &T, - expected_domain: Option, + expected_domain: Url, ) -> Result where T: Base + AsBase, { - let object_id = if let Some(url) = expected_domain { - let domain = url.domain().context(location_info!())?; - apub.id(domain)?.context(location_info!())? - } else { - apub.id_unchecked().context(location_info!())? - }; + let domain = expected_domain.domain().context(location_info!())?; + let object_id = apub.id(domain)?.context(location_info!())?; check_is_apub_id_valid(&object_id)?; Ok(object_id.to_string()) } @@ -127,3 +168,60 @@ pub(in crate::objects) fn check_is_markdown(mime: Option<&Mime>) -> Result<(), L Ok(()) } } + +/// Converts an ActivityPub object (eg `Note`) to a database object (eg `Comment`). If an object +/// with the same ActivityPub ID already exists in the database, it is returned directly. Otherwise +/// the apub object is parsed, inserted and returned. +pub(in crate::objects) async fn get_object_from_apub( + from: &From, + context: &LemmyContext, + expected_domain: Url, + request_counter: &mut i32, +) -> Result +where + From: BaseExt, + To: ApubObject + Crud + Send + 'static, + ToForm: FromApubToForm + Send + 'static, +{ + let object_id = from.id_unchecked().context(location_info!())?.to_owned(); + let domain = object_id.domain().context(location_info!())?; + + // if its a local object, return it directly from the database + if Settings::get().hostname == domain { + let object = blocking(context.pool(), move |conn| { + To::read_from_apub_id(conn, object_id.as_str()) + }) + .await??; + Ok(object) + } + // otherwise parse and insert, assuring that it comes from the right domain + else { + let to_form = ToForm::from_apub(&from, context, expected_domain, request_counter).await?; + + let to = blocking(context.pool(), move |conn| To::upsert(conn, &to_form)).await??; + Ok(to) + } +} + +pub(in crate::objects) async fn check_object_for_community_or_site_ban( + object: &T, + context: &LemmyContext, + request_counter: &mut i32, +) -> Result<(), LemmyError> +where + T: ObjectExt, +{ + let user_id = object + .attributed_to() + .context(location_info!())? + .as_single_xsd_any_uri() + .context(location_info!())?; + let user = get_or_fetch_and_upsert_user(user_id, context, request_counter).await?; + let community_id = object + .to() + .context(location_info!())? + .as_single_xsd_any_uri() + .context(location_info!())?; + let community = get_or_fetch_and_upsert_community(community_id, context, request_counter).await?; + check_community_or_site_ban(&user, &community, context.pool()).await +} diff --git a/lemmy_apub/src/objects/post.rs b/lemmy_apub/src/objects/post.rs index a058d8b7c..d34098c5b 100644 --- a/lemmy_apub/src/objects/post.rs +++ b/lemmy_apub/src/objects/post.rs @@ -3,13 +3,16 @@ use crate::{ fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user}, objects::{ check_object_domain, + check_object_for_community_or_site_ban, create_tombstone, + get_object_from_apub, get_source_markdown_value, set_content_and_source, + FromApub, + FromApubToForm, + ToApub, }, - FromApub, PageExt, - ToApub, }; use activitystreams::{ object::{kind::PageType, ApObject, Image, Page, Tombstone}, @@ -98,7 +101,7 @@ impl ToApub for Post { } #[async_trait::async_trait(?Send)] -impl FromApub for PostForm { +impl FromApub for Post { type ApubType = PageExt; /// Converts a `PageExt` to `PostForm`. @@ -107,7 +110,20 @@ impl FromApub for PostForm { async fn from_apub( page: &PageExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, + request_counter: &mut i32, + ) -> Result { + check_object_for_community_or_site_ban(page, context, request_counter).await?; + get_object_from_apub(page, context, expected_domain, request_counter).await + } +} + +#[async_trait::async_trait(?Send)] +impl FromApubToForm for PostForm { + async fn from_apub( + page: &PageExt, + context: &LemmyContext, + expected_domain: Url, request_counter: &mut i32, ) -> Result { let ext = &page.ext_one; diff --git a/lemmy_apub/src/objects/private_message.rs b/lemmy_apub/src/objects/private_message.rs index 4e9af0943..ec8b55e7e 100644 --- a/lemmy_apub/src/objects/private_message.rs +++ b/lemmy_apub/src/objects/private_message.rs @@ -5,12 +5,14 @@ use crate::{ objects::{ check_object_domain, create_tombstone, + get_object_from_apub, get_source_markdown_value, set_content_and_source, + FromApub, + FromApubToForm, + ToApub, }, - FromApub, NoteExt, - ToApub, }; use activitystreams::{ object::{kind::NoteType, ApObject, Note, Tombstone}, @@ -63,13 +65,25 @@ impl ToApub for PrivateMessage { } #[async_trait::async_trait(?Send)] -impl FromApub for PrivateMessageForm { +impl FromApub for PrivateMessage { type ApubType = NoteExt; async fn from_apub( note: &NoteExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, + request_counter: &mut i32, + ) -> Result { + get_object_from_apub(note, context, expected_domain, request_counter).await + } +} + +#[async_trait::async_trait(?Send)] +impl FromApubToForm for PrivateMessageForm { + async fn from_apub( + note: &NoteExt, + context: &LemmyContext, + expected_domain: Url, request_counter: &mut i32, ) -> Result { let creator_actor_id = note diff --git a/lemmy_apub/src/objects/user.rs b/lemmy_apub/src/objects/user.rs index ddf33656c..18490796a 100644 --- a/lemmy_apub/src/objects/user.rs +++ b/lemmy_apub/src/objects/user.rs @@ -1,10 +1,15 @@ use crate::{ extensions::context::lemmy_context, - objects::{check_object_domain, get_source_markdown_value, set_content_and_source}, + objects::{ + check_object_domain, + get_source_markdown_value, + set_content_and_source, + FromApub, + FromApubToForm, + ToApub, + }, ActorType, - FromApub, PersonExt, - ToApub, }; use activitystreams::{ actor::{ApActor, Endpoints, Person}, @@ -16,10 +21,13 @@ use anyhow::Context; use lemmy_db::{ naive_now, user::{UserForm, User_}, + ApubObject, DbPool, }; +use lemmy_structs::blocking; use lemmy_utils::{ location_info, + settings::Settings, utils::{check_slurs, check_slurs_opt, convert_datetime}, LemmyError, }; @@ -81,13 +89,38 @@ impl ToApub for User_ { } #[async_trait::async_trait(?Send)] -impl FromApub for UserForm { +impl FromApub for User_ { type ApubType = PersonExt; + async fn from_apub( + person: &PersonExt, + context: &LemmyContext, + expected_domain: Url, + request_counter: &mut i32, + ) -> Result { + let user_id = person.id_unchecked().context(location_info!())?.to_owned(); + let domain = user_id.domain().context(location_info!())?; + if domain == Settings::get().hostname { + let user = blocking(context.pool(), move |conn| { + User_::read_from_apub_id(conn, user_id.as_str()) + }) + .await??; + Ok(user) + } else { + let user_form = + UserForm::from_apub(person, context, expected_domain, request_counter).await?; + let user = blocking(context.pool(), move |conn| User_::upsert(conn, &user_form)).await??; + Ok(user) + } + } +} + +#[async_trait::async_trait(?Send)] +impl FromApubToForm for UserForm { async fn from_apub( person: &PersonExt, _context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, _request_counter: &mut i32, ) -> Result { let avatar = match person.icon() { diff --git a/lemmy_db/src/comment.rs b/lemmy_db/src/comment.rs index 9b0928257..f54ddd10f 100644 --- a/lemmy_db/src/comment.rs +++ b/lemmy_db/src/comment.rs @@ -2,6 +2,7 @@ use super::post::Post; use crate::{ naive_now, schema::{comment, comment_like, comment_saved}, + ApubObject, Crud, Likeable, Saveable, @@ -86,6 +87,23 @@ impl Crud for Comment { } } +impl ApubObject for Comment { + fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { + use crate::schema::comment::dsl::*; + comment.filter(ap_id.eq(object_id)).first::(conn) + } + + fn upsert(conn: &PgConnection, comment_form: &CommentForm) -> Result { + use crate::schema::comment::dsl::*; + insert_into(comment) + .values(comment_form) + .on_conflict(ap_id) + .do_update() + .set(comment_form) + .get_result::(conn) + } +} + impl Comment { pub fn update_ap_id( conn: &PgConnection, @@ -99,11 +117,6 @@ impl Comment { .get_result::(conn) } - pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { - use crate::schema::comment::dsl::*; - comment.filter(ap_id.eq(object_id)).first::(conn) - } - pub fn permadelete_for_creator( conn: &PgConnection, for_creator_id: i32, @@ -168,16 +181,6 @@ impl Comment { .set((content.eq(new_content), updated.eq(naive_now()))) .get_result::(conn) } - - pub fn upsert(conn: &PgConnection, comment_form: &CommentForm) -> Result { - use crate::schema::comment::dsl::*; - insert_into(comment) - .values(comment_form) - .on_conflict(ap_id) - .do_update() - .set(comment_form) - .get_result::(conn) - } } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Clone)] diff --git a/lemmy_db/src/community.rs b/lemmy_db/src/community.rs index 5f76d5143..be40da349 100644 --- a/lemmy_db/src/community.rs +++ b/lemmy_db/src/community.rs @@ -1,6 +1,7 @@ use crate::{ naive_now, schema::{community, community_follower, community_moderator, community_user_ban}, + ApubObject, Bannable, Crud, Followable, @@ -83,6 +84,25 @@ impl Crud for Community { } } +impl ApubObject for Community { + fn read_from_apub_id(conn: &PgConnection, for_actor_id: &str) -> Result { + use crate::schema::community::dsl::*; + community + .filter(actor_id.eq(for_actor_id)) + .first::(conn) + } + + fn upsert(conn: &PgConnection, community_form: &CommunityForm) -> Result { + use crate::schema::community::dsl::*; + insert_into(community) + .values(community_form) + .on_conflict(actor_id) + .do_update() + .set(community_form) + .get_result::(conn) + } +} + impl Community { pub fn read_from_name(conn: &PgConnection, community_name: &str) -> Result { use crate::schema::community::dsl::*; @@ -92,13 +112,6 @@ impl Community { .first::(conn) } - pub fn read_from_actor_id(conn: &PgConnection, for_actor_id: &str) -> Result { - use crate::schema::community::dsl::*; - community - .filter(actor_id.eq(for_actor_id)) - .first::(conn) - } - pub fn update_deleted( conn: &PgConnection, community_id: i32, @@ -165,16 +178,6 @@ impl Community { .unwrap_or_default() .contains(&user_id) } - - pub fn upsert(conn: &PgConnection, community_form: &CommunityForm) -> Result { - use crate::schema::community::dsl::*; - insert_into(community) - .values(community_form) - .on_conflict(actor_id) - .do_update() - .set(community_form) - .get_result::(conn) - } } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] diff --git a/lemmy_db/src/lib.rs b/lemmy_db/src/lib.rs index bad646d14..0ca4826a1 100644 --- a/lemmy_db/src/lib.rs +++ b/lemmy_db/src/lib.rs @@ -124,6 +124,15 @@ pub trait Reportable { Self: Sized; } +pub trait ApubObject { + fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result + where + Self: Sized; + fn upsert(conn: &PgConnection, user_form: &T) -> Result + where + Self: Sized; +} + pub trait MaybeOptional { fn get_optional(self) -> Option; } diff --git a/lemmy_db/src/post.rs b/lemmy_db/src/post.rs index 787d5e6c4..530f475b4 100644 --- a/lemmy_db/src/post.rs +++ b/lemmy_db/src/post.rs @@ -1,6 +1,7 @@ use crate::{ naive_now, schema::{post, post_like, post_read, post_saved}, + ApubObject, Crud, Likeable, Readable, @@ -62,6 +63,47 @@ impl PostForm { } } +impl Crud for Post { + fn read(conn: &PgConnection, post_id: i32) -> Result { + use crate::schema::post::dsl::*; + post.find(post_id).first::(conn) + } + + fn delete(conn: &PgConnection, post_id: i32) -> Result { + use crate::schema::post::dsl::*; + diesel::delete(post.find(post_id)).execute(conn) + } + + fn create(conn: &PgConnection, new_post: &PostForm) -> Result { + use crate::schema::post::dsl::*; + insert_into(post).values(new_post).get_result::(conn) + } + + fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result { + use crate::schema::post::dsl::*; + diesel::update(post.find(post_id)) + .set(new_post) + .get_result::(conn) + } +} + +impl ApubObject for Post { + fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { + use crate::schema::post::dsl::*; + post.filter(ap_id.eq(object_id)).first::(conn) + } + + fn upsert(conn: &PgConnection, post_form: &PostForm) -> Result { + use crate::schema::post::dsl::*; + insert_into(post) + .values(post_form) + .on_conflict(ap_id) + .do_update() + .set(post_form) + .get_result::(conn) + } +} + impl Post { pub fn read(conn: &PgConnection, post_id: i32) -> Result { use crate::schema::post::dsl::*; @@ -81,11 +123,6 @@ impl Post { .load::(conn) } - pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { - use crate::schema::post::dsl::*; - post.filter(ap_id.eq(object_id)).first::(conn) - } - pub fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: String) -> Result { use crate::schema::post::dsl::*; @@ -177,40 +214,6 @@ impl Post { pub fn is_post_creator(user_id: i32, post_creator_id: i32) -> bool { user_id == post_creator_id } - - pub fn upsert(conn: &PgConnection, post_form: &PostForm) -> Result { - use crate::schema::post::dsl::*; - insert_into(post) - .values(post_form) - .on_conflict(ap_id) - .do_update() - .set(post_form) - .get_result::(conn) - } -} - -impl Crud for Post { - fn read(conn: &PgConnection, post_id: i32) -> Result { - use crate::schema::post::dsl::*; - post.find(post_id).first::(conn) - } - - fn delete(conn: &PgConnection, post_id: i32) -> Result { - use crate::schema::post::dsl::*; - diesel::delete(post.find(post_id)).execute(conn) - } - - fn create(conn: &PgConnection, new_post: &PostForm) -> Result { - use crate::schema::post::dsl::*; - insert_into(post).values(new_post).get_result::(conn) - } - - fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result { - use crate::schema::post::dsl::*; - diesel::update(post.find(post_id)) - .set(new_post) - .get_result::(conn) - } } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] diff --git a/lemmy_db/src/private_message.rs b/lemmy_db/src/private_message.rs index 503a26abf..0e1aef108 100644 --- a/lemmy_db/src/private_message.rs +++ b/lemmy_db/src/private_message.rs @@ -1,4 +1,4 @@ -use crate::{naive_now, schema::private_message, Crud}; +use crate::{naive_now, schema::private_message, ApubObject, Crud}; use diesel::{dsl::*, result::Error, *}; #[derive(Queryable, Identifiable, PartialEq, Debug)] @@ -55,6 +55,28 @@ impl Crud for PrivateMessage { } } +impl ApubObject for PrivateMessage { + fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result + where + Self: Sized, + { + use crate::schema::private_message::dsl::*; + private_message + .filter(ap_id.eq(object_id)) + .first::(conn) + } + + fn upsert(conn: &PgConnection, private_message_form: &PrivateMessageForm) -> Result { + use crate::schema::private_message::dsl::*; + insert_into(private_message) + .values(private_message_form) + .on_conflict(ap_id) + .do_update() + .set(private_message_form) + .get_result::(conn) + } +} + impl PrivateMessage { pub fn update_ap_id( conn: &PgConnection, @@ -68,13 +90,6 @@ impl PrivateMessage { .get_result::(conn) } - pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { - use crate::schema::private_message::dsl::*; - private_message - .filter(ap_id.eq(object_id)) - .first::(conn) - } - pub fn update_content( conn: &PgConnection, private_message_id: i32, @@ -118,20 +133,6 @@ impl PrivateMessage { .set(read.eq(true)) .get_results::(conn) } - - // TODO use this - pub fn upsert( - conn: &PgConnection, - private_message_form: &PrivateMessageForm, - ) -> Result { - use crate::schema::private_message::dsl::*; - insert_into(private_message) - .values(private_message_form) - .on_conflict(ap_id) - .do_update() - .set(private_message_form) - .get_result::(conn) - } } #[cfg(test)] diff --git a/lemmy_db/src/user.rs b/lemmy_db/src/user.rs index 2c4c67ea2..d8e833e6e 100644 --- a/lemmy_db/src/user.rs +++ b/lemmy_db/src/user.rs @@ -2,6 +2,7 @@ use crate::{ is_email_regex, naive_now, schema::{user_, user_::dsl::*}, + ApubObject, Crud, }; use bcrypt::{hash, DEFAULT_COST}; @@ -89,6 +90,25 @@ impl Crud for User_ { } } +impl ApubObject for User_ { + fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { + use crate::schema::user_::dsl::*; + user_ + .filter(deleted.eq(false)) + .filter(actor_id.eq(object_id)) + .first::(conn) + } + + fn upsert(conn: &PgConnection, user_form: &UserForm) -> Result { + insert_into(user_) + .values(user_form) + .on_conflict(actor_id) + .do_update() + .set(user_form) + .get_result::(conn) + } +} + impl User_ { pub fn register(conn: &PgConnection, form: &UserForm) -> Result { let mut edited_user = form.clone(); @@ -135,14 +155,6 @@ impl User_ { .get_result::(conn) } - pub fn read_from_actor_id(conn: &PgConnection, object_id: &str) -> Result { - use crate::schema::user_::dsl::*; - user_ - .filter(deleted.eq(false)) - .filter(actor_id.eq(object_id)) - .first::(conn) - } - pub fn find_by_email_or_username( conn: &PgConnection, username_or_email: &str, @@ -179,12 +191,9 @@ impl User_ { ) } - pub fn upsert(conn: &PgConnection, user_form: &UserForm) -> Result { - insert_into(user_) - .values(user_form) - .on_conflict(actor_id) - .do_update() - .set(user_form) + pub fn mark_as_updated(conn: &PgConnection, user_id: i32) -> Result { + diesel::update(user_.find(user_id)) + .set((last_refreshed_at.eq(naive_now()),)) .get_result::(conn) } From 08ab85a9d5cf98b7f5435982aa74ab924b99eb0b Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Mon, 7 Dec 2020 13:40:39 +0100 Subject: [PATCH 3/3] Remove logging to find bug (yerbamate.ml/LemmyNet/lemmy/pulls/146) --- Cargo.lock | 94 +++++++++++++++------------------- Cargo.toml | 4 +- lemmy_api/Cargo.toml | 4 +- lemmy_apub/Cargo.toml | 4 +- lemmy_apub/src/objects/post.rs | 11 ---- lemmy_db/Cargo.toml | 2 +- lemmy_structs/Cargo.toml | 2 +- lemmy_utils/Cargo.toml | 4 +- lemmy_websocket/Cargo.toml | 4 +- 9 files changed, 54 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8213956d5..3e76e5b42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ checksum = "5e9fedbe571e267d9b93d071bdc4493f944022c6cce717ebb27d352026fc81c4" dependencies = [ "chrono", "mime", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "thiserror", "url", @@ -21,7 +21,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb8e19a0810cc25df3535061a08b7d8f8a734d309ea4411c57a9767e4a2ffa0e" dependencies = [ "activitystreams", - "serde 1.0.117", + "serde 1.0.118", "serde_json", ] @@ -148,7 +148,7 @@ dependencies = [ "pin-project 1.0.2", "rand", "regex", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "serde_urlencoded", "sha-1 0.9.2", @@ -176,7 +176,7 @@ dependencies = [ "http", "log", "regex", - "serde 1.0.117", + "serde 1.0.118", ] [[package]] @@ -320,7 +320,7 @@ dependencies = [ "pin-project 1.0.2", "regex", "rustls", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "serde_urlencoded", "socket2", @@ -399,9 +399,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" +checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4" [[package]] name = "arrayvec" @@ -466,7 +466,7 @@ dependencies = [ "percent-encoding", "rand", "rustls", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "serde_urlencoded", ] @@ -496,7 +496,7 @@ dependencies = [ "log", "num_cpus", "rand", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "thiserror", "tokio 0.2.23", @@ -515,7 +515,7 @@ dependencies = [ "async-trait", "chrono", "log", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "thiserror", "tokio 0.2.23", @@ -745,7 +745,7 @@ dependencies = [ "libc", "num-integer", "num-traits 0.2.14", - "serde 1.0.117", + "serde 1.0.118", "time 0.1.44", "winapi 0.3.9", ] @@ -759,15 +759,6 @@ dependencies = [ "generic-array 0.14.4", ] -[[package]] -name = "cloudabi" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" -dependencies = [ - "bitflags", -] - [[package]] name = "color_quant" version = "1.1.0" @@ -800,7 +791,7 @@ checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3" dependencies = [ "lazy_static", "nom 5.1.2", - "serde 1.0.117", + "serde 1.0.118", "serde-hjson", ] @@ -1686,7 +1677,7 @@ dependencies = [ "base64 0.12.3", "pem", "ring", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "simple_asn1", ] @@ -1745,7 +1736,7 @@ dependencies = [ "openssl", "rand", "reqwest", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "sha2", "strum", @@ -1789,7 +1780,7 @@ dependencies = [ "percent-encoding", "rand", "reqwest", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "sha2", "strum", @@ -1811,7 +1802,7 @@ dependencies = [ "lemmy_utils", "log", "regex", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "sha2", "strum", @@ -1862,7 +1853,7 @@ dependencies = [ "openssl", "reqwest", "rss", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "sha2", "strum", @@ -1880,7 +1871,7 @@ dependencies = [ "lemmy_db", "lemmy_utils", "log", - "serde 1.0.117", + "serde 1.0.118", "serde_json", ] @@ -1903,7 +1894,7 @@ dependencies = [ "rand", "regex", "reqwest", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "thiserror", "url", @@ -1925,7 +1916,7 @@ dependencies = [ "log", "rand", "reqwest", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "strum", "strum_macros", @@ -1950,7 +1941,7 @@ dependencies = [ "r2d2", "rand", "regex", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "uuid", ] @@ -1970,9 +1961,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" [[package]] name = "linked-hash-map" @@ -2367,12 +2358,11 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" +checksum = "d7c6d9b8427445284a09c55be860a15855ab580a417ccad9da88f5a06787ced0" dependencies = [ - "cfg-if 0.1.10", - "cloudabi", + "cfg-if 1.0.0", "instant", "libc", "redox_syscall", @@ -2723,7 +2713,7 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite 0.2.0", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "serde_urlencoded", "tokio 0.2.23", @@ -2907,9 +2897,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" [[package]] name = "serde" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" dependencies = [ "serde_derive", ] @@ -2929,9 +2919,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", @@ -2947,7 +2937,7 @@ dependencies = [ "indexmap", "itoa", "ryu", - "serde 1.0.117", + "serde 1.0.118", ] [[package]] @@ -2968,7 +2958,7 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde 1.0.117", + "serde 1.0.118", ] [[package]] @@ -3049,9 +3039,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85" +checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" [[package]] name = "socket2" @@ -3108,7 +3098,7 @@ checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" dependencies = [ "proc-macro2", "quote", - "serde 1.0.117", + "serde 1.0.118", "serde_derive", "syn", ] @@ -3122,7 +3112,7 @@ dependencies = [ "base-x", "proc-macro2", "quote", - "serde 1.0.117", + "serde 1.0.118", "serde_derive", "serde_json", "sha1", @@ -3161,9 +3151,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.53" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8833e20724c24de12bbaba5ad230ea61c3eafb05b881c7c9d3cfe8638b187e68" +checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" dependencies = [ "proc-macro2", "quote", @@ -3558,7 +3548,7 @@ dependencies = [ "idna", "matches", "percent-encoding", - "serde 1.0.117", + "serde 1.0.118", ] [[package]] @@ -3568,7 +3558,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" dependencies = [ "rand", - "serde 1.0.117", + "serde 1.0.118", ] [[package]] @@ -3650,7 +3640,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" dependencies = [ "cfg-if 1.0.0", - "serde 1.0.117", + "serde 1.0.118", "serde_json", "wasm-bindgen-macro", ] diff --git a/Cargo.toml b/Cargo.toml index 42378726d..019d0db3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ lemmy_websocket = { path = "./lemmy_websocket" } diesel = "1.4.5" diesel_migrations = "1.4.0" chrono = { version = "0.4.19", features = ["serde"] } -serde = { version = "1.0.117", features = ["derive"] } +serde = { version = "1.0.118", features = ["derive"] } actix = "0.10.0" actix-web = { version = "3.3.2", default-features = false, features = ["rustls"] } actix-files = { version = "0.4.1", default-features = false } @@ -44,7 +44,7 @@ openssl = "0.10.30" http-signature-normalization-actix = { version = "0.4.1", default-features = false, features = ["sha-2"] } tokio = "0.3.5" sha2 = "0.9.2" -anyhow = "1.0.34" +anyhow = "1.0.35" reqwest = { version = "0.10.9", features = ["json"] } activitystreams = "0.7.0-alpha.8" actix-rt = { version = "1.1.1", default-features = false } diff --git a/lemmy_api/Cargo.toml b/lemmy_api/Cargo.toml index 1a39df414..4d32db2fb 100644 --- a/lemmy_api/Cargo.toml +++ b/lemmy_api/Cargo.toml @@ -19,7 +19,7 @@ diesel = "1.4.5" bcrypt = "0.9.0" chrono = { version = "0.4.19", features = ["serde"] } serde_json = { version = "1.0.60", features = ["preserve_order"] } -serde = { version = "1.0.117", features = ["derive"] } +serde = { version = "1.0.118", features = ["derive"] } actix = "0.10.0" actix-web = { version = "3.3.2", default-features = false } actix-rt = { version = "1.1.1", default-features = false } @@ -42,7 +42,7 @@ uuid = { version = "0.8.1", features = ["serde", "v4"] } sha2 = "0.9.2" async-trait = "0.1.42" captcha = "0.0.8" -anyhow = "1.0.34" +anyhow = "1.0.35" thiserror = "1.0.22" background-jobs = "0.8.0" reqwest = { version = "0.10.9", features = ["json"] } diff --git a/lemmy_apub/Cargo.toml b/lemmy_apub/Cargo.toml index 8b78c77c0..fd4395c44 100644 --- a/lemmy_apub/Cargo.toml +++ b/lemmy_apub/Cargo.toml @@ -19,7 +19,7 @@ activitystreams-ext = "0.1.0-alpha.2" bcrypt = "0.9.0" chrono = { version = "0.4.19", features = ["serde"] } serde_json = { version = "1.0.60", features = ["preserve_order"] } -serde = { version = "1.0.117", features = ["derive"] } +serde = { version = "1.0.118", features = ["derive"] } actix = "0.10.0" actix-web = { version = "3.3.2", default-features = false } actix-rt = { version = "1.1.1", default-features = false } @@ -42,7 +42,7 @@ itertools = "0.9.0" uuid = { version = "0.8.1", features = ["serde", "v4"] } sha2 = "0.9.2" async-trait = "0.1.42" -anyhow = "1.0.34" +anyhow = "1.0.35" thiserror = "1.0.22" background-jobs = "0.8.0" reqwest = { version = "0.10.9", features = ["json"] } diff --git a/lemmy_apub/src/objects/post.rs b/lemmy_apub/src/objects/post.rs index d34098c5b..39b749972 100644 --- a/lemmy_apub/src/objects/post.rs +++ b/lemmy_apub/src/objects/post.rs @@ -20,7 +20,6 @@ use activitystreams::{ }; use activitystreams_ext::Ext1; use anyhow::Context; -use backtrace::Backtrace; use lemmy_db::{ community::Community, post::{Post, PostForm}, @@ -36,7 +35,6 @@ use lemmy_utils::{ LemmyError, }; use lemmy_websocket::LemmyContext; -use log::error; use url::Url; #[async_trait::async_trait(?Send)] @@ -148,15 +146,6 @@ impl FromApubToForm for PostForm { let community = get_or_fetch_and_upsert_community(community_actor_id, context, request_counter).await?; - if community.local && creator.local { - let page_id = page.id_unchecked().context(location_info!())?; - let bt = Backtrace::new(); - error!( - "Lemmy is parsing a local post as remote, page id: {}, stack trace: {:?}", - page_id, bt - ); - } - let thumbnail_url = match &page.inner.image() { Some(any_image) => Image::from_any_base( any_image diff --git a/lemmy_db/Cargo.toml b/lemmy_db/Cargo.toml index 1d13a88bc..11b27fcd7 100644 --- a/lemmy_db/Cargo.toml +++ b/lemmy_db/Cargo.toml @@ -11,7 +11,7 @@ path = "src/lib.rs" lemmy_utils = { path = "../lemmy_utils" } diesel = { version = "1.4.5", features = ["postgres","chrono","r2d2","64-column-tables","serde_json"] } chrono = { version = "0.4.19", features = ["serde"] } -serde = { version = "1.0.117", features = ["derive"] } +serde = { version = "1.0.118", features = ["derive"] } serde_json = { version = "1.0.60", features = ["preserve_order"] } strum = "0.20.0" strum_macros = "0.20.1" diff --git a/lemmy_structs/Cargo.toml b/lemmy_structs/Cargo.toml index d11f4a688..e14623064 100644 --- a/lemmy_structs/Cargo.toml +++ b/lemmy_structs/Cargo.toml @@ -11,7 +11,7 @@ path = "src/lib.rs" [dependencies] lemmy_db = { path = "../lemmy_db" } lemmy_utils = { path = "../lemmy_utils" } -serde = { version = "1.0.117", features = ["derive"] } +serde = { version = "1.0.118", features = ["derive"] } log = "0.4.11" diesel = "1.4.5" actix-web = "3.3.2" diff --git a/lemmy_utils/Cargo.toml b/lemmy_utils/Cargo.toml index 2a1021100..ae3d246bc 100644 --- a/lemmy_utils/Cargo.toml +++ b/lemmy_utils/Cargo.toml @@ -16,7 +16,7 @@ log = "0.4.11" itertools = "0.9.0" rand = "0.7.3" percent-encoding = "2.1.0" -serde = { version = "1.0.117", features = ["derive"] } +serde = { version = "1.0.118", features = ["derive"] } serde_json = { version = "1.0.60", features = ["preserve_order"] } thiserror = "1.0.22" comrak = { version = "0.9.0", default-features = false } @@ -25,5 +25,5 @@ openssl = "0.10.30" url = { version = "2.2.0", features = ["serde"] } actix-web = { version = "3.3.2", default-features = false, features = ["rustls"] } actix-rt = { version = "1.1.1", default-features = false } -anyhow = "1.0.34" +anyhow = "1.0.35" reqwest = { version = "0.10.9", features = ["json"] } diff --git a/lemmy_websocket/Cargo.toml b/lemmy_websocket/Cargo.toml index 46a671299..a7b710bcb 100644 --- a/lemmy_websocket/Cargo.toml +++ b/lemmy_websocket/Cargo.toml @@ -16,10 +16,10 @@ lemmy_rate_limit = { path = "../lemmy_rate_limit" } reqwest = { version = "0.10.9", features = ["json"] } log = "0.4.11" rand = "0.7.3" -serde = { version = "1.0.117", features = ["derive"] } +serde = { version = "1.0.118", features = ["derive"] } serde_json = { version = "1.0.60", features = ["preserve_order"] } actix = "0.10.0" -anyhow = "1.0.34" +anyhow = "1.0.35" diesel = "1.4.5" background-jobs = "0.8.0" tokio = "0.3.5"