diff --git a/crates/apub_receive/src/activities_new/community/block_user.rs b/crates/apub_receive/src/activities_new/community/block_user.rs new file mode 100644 index 00000000..60943219 --- /dev/null +++ b/crates/apub_receive/src/activities_new/community/block_user.rs @@ -0,0 +1,76 @@ +use crate::{activities_new::verify_mod_action, inbox::new_inbox_routing::Activity}; +use activitystreams::activity::kind::BlockType; +use lemmy_api_common::blocking; +use lemmy_apub::{ + check_is_apub_id_valid, + fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person}, +}; +use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity}; +use lemmy_db_queries::{Bannable, Followable}; +use lemmy_db_schema::source::community::{ + CommunityFollower, + CommunityFollowerForm, + CommunityPersonBan, + CommunityPersonBanForm, +}; +use lemmy_utils::LemmyError; +use lemmy_websocket::LemmyContext; +use url::Url; + +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct BlockUserFromCommunity { + actor: Url, + to: PublicUrl, + pub(in crate::activities_new::community) object: Url, + cc: [Url; 1], + #[serde(rename = "type")] + kind: BlockType, +} + +#[async_trait::async_trait(?Send)] +impl VerifyActivity for Activity { + async fn verify(&self, context: &LemmyContext) -> Result<(), LemmyError> { + verify_domains_match(&self.inner.actor, self.id_unchecked())?; + check_is_apub_id_valid(&self.inner.actor, false)?; + verify_mod_action(self.inner.actor.clone(), self.inner.cc[0].clone(), context).await + } +} + +#[async_trait::async_trait(?Send)] +impl ReceiveActivity for Activity { + async fn receive( + &self, + context: &LemmyContext, + request_counter: &mut i32, + ) -> Result<(), LemmyError> { + let community = + get_or_fetch_and_upsert_community(&self.inner.cc[0], context, request_counter).await?; + let blocked_user = + get_or_fetch_and_upsert_person(&self.inner.object, context, request_counter).await?; + + let community_user_ban_form = CommunityPersonBanForm { + community_id: community.id, + person_id: blocked_user.id, + }; + + blocking(context.pool(), move |conn: &'_ _| { + CommunityPersonBan::ban(conn, &community_user_ban_form) + }) + .await??; + + // Also unsubscribe them from the community, if they are subscribed + let community_follower_form = CommunityFollowerForm { + community_id: community.id, + person_id: blocked_user.id, + pending: false, + }; + blocking(context.pool(), move |conn: &'_ _| { + CommunityFollower::unfollow(conn, &community_follower_form) + }) + .await? + .ok(); + + Ok(()) + } +} diff --git a/crates/apub_receive/src/activities_new/community/mod.rs b/crates/apub_receive/src/activities_new/community/mod.rs index 951a29e7..7950cde9 100644 --- a/crates/apub_receive/src/activities_new/community/mod.rs +++ b/crates/apub_receive/src/activities_new/community/mod.rs @@ -10,8 +10,10 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext}; use url::Url; +pub mod block_user; pub mod delete; pub mod remove; +pub mod undo_block_user; pub mod undo_delete; pub mod undo_remove; pub mod update; @@ -38,6 +40,7 @@ async fn send_websocket_message, + cc: [Url; 1], + #[serde(rename = "type")] + kind: BlockType, +} + +#[async_trait::async_trait(?Send)] +impl VerifyActivity for Activity { + async fn verify(&self, context: &LemmyContext) -> Result<(), LemmyError> { + verify_domains_match(&self.inner.actor, self.id_unchecked())?; + check_is_apub_id_valid(&self.inner.actor, false)?; + verify_mod_action(self.inner.actor.clone(), self.inner.cc[0].clone(), context).await?; + self.inner.object.verify(context).await + } +} + +#[async_trait::async_trait(?Send)] +impl ReceiveActivity for Activity { + async fn receive( + &self, + context: &LemmyContext, + request_counter: &mut i32, + ) -> Result<(), LemmyError> { + let community = + get_or_fetch_and_upsert_community(&self.inner.cc[0], context, request_counter).await?; + let blocked_user = + get_or_fetch_and_upsert_person(&self.inner.object.inner.object, context, request_counter) + .await?; + + let community_user_ban_form = CommunityPersonBanForm { + community_id: community.id, + person_id: blocked_user.id, + }; + + blocking(context.pool(), move |conn: &'_ _| { + CommunityPersonBan::unban(conn, &community_user_ban_form) + }) + .await??; + + Ok(()) + } +} diff --git a/crates/apub_receive/src/inbox/community_inbox.rs b/crates/apub_receive/src/inbox/community_inbox.rs index 4d9a12bb..3996cb8f 100644 --- a/crates/apub_receive/src/inbox/community_inbox.rs +++ b/crates/apub_receive/src/inbox/community_inbox.rs @@ -3,18 +3,10 @@ use crate::inbox::{ get_activity_id, inbox_verify_http_signature, is_activity_already_known, - receive_for_community::{ - receive_add_for_community, - receive_block_user_for_community, - receive_remove_for_community, - receive_undo_for_community, - }, + receive_for_community::receive_add_for_community, verify_is_addressed_to_public, }; -use activitystreams::{ - activity::{kind::FollowType, ActorAndObject}, - prelude::*, -}; +use activitystreams::{activity::ActorAndObject, prelude::*}; use actix_web::{web, HttpRequest, HttpResponse}; use anyhow::{anyhow, Context}; use lemmy_api_common::blocking; @@ -32,7 +24,6 @@ use lemmy_websocket::LemmyContext; use log::info; use serde::{Deserialize, Serialize}; use std::fmt::Debug; -use url::Url; /// Allowed activities for community inbox. #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)] @@ -122,20 +113,10 @@ pub(crate) async fn community_receive_message( ); let any_base = activity.clone().into_any_base()?; - let actor_url = actor.actor_id(); let activity_kind = activity.kind().context(location_info!())?; let do_announce = match activity_kind { CommunityValidTypes::Follow => todo!(), - CommunityValidTypes::Undo => { - Box::pin(handle_undo( - context, - activity.clone(), - actor_url, - &to_community, - request_counter, - )) - .await? - } + CommunityValidTypes::Undo => todo!(), CommunityValidTypes::Create => todo!(), CommunityValidTypes::Update => todo!(), CommunityValidTypes::Like => todo!(), @@ -151,26 +132,8 @@ pub(crate) async fn community_receive_message( .await?; true } - CommunityValidTypes::Remove => { - Box::pin(receive_remove_for_community( - context, - any_base.clone(), - None, - request_counter, - )) - .await?; - true - } - CommunityValidTypes::Block => { - Box::pin(receive_block_user_for_community( - context, - any_base.clone(), - None, - request_counter, - )) - .await?; - true - } + CommunityValidTypes::Remove => todo!(), + CommunityValidTypes::Block => todo!(), }; if do_announce { @@ -195,22 +158,3 @@ pub(crate) async fn community_receive_message( Ok(HttpResponse::Ok().finish()) } - -async fn handle_undo( - context: &LemmyContext, - activity: CommunityAcceptedActivities, - actor_url: Url, - _to_community: &Community, - request_counter: &mut i32, -) -> Result { - let inner_kind = activity - .object() - .is_single_kind(&FollowType::Follow.to_string()); - let any_base = activity.into_any_base()?; - if inner_kind { - todo!() - } else { - receive_undo_for_community(context, any_base, None, &actor_url, request_counter).await?; - Ok(true) - } -} diff --git a/crates/apub_receive/src/inbox/new_inbox_routing.rs b/crates/apub_receive/src/inbox/new_inbox_routing.rs index 3542f331..83bfec1f 100644 --- a/crates/apub_receive/src/inbox/new_inbox_routing.rs +++ b/crates/apub_receive/src/inbox/new_inbox_routing.rs @@ -68,9 +68,8 @@ impl Activity { } } -// TODO: this is probably wrong, it contains all activities #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] -pub enum PersonAcceptedActivitiesNew { +pub enum SharedInboxActivities { FollowCommunity(FollowCommunity), AcceptFollowCommunity(AcceptFollowCommunity), UndoFollowCommunity(UndoFollowCommunity), @@ -107,14 +106,14 @@ pub enum PersonAcceptedActivitiesNew { // todo: can probably get rid of these? #[async_trait::async_trait(?Send)] -impl VerifyActivity for PersonAcceptedActivitiesNew { +impl VerifyActivity for SharedInboxActivities { async fn verify(&self, context: &LemmyContext) -> Result<(), LemmyError> { self.verify(context).await } } #[async_trait::async_trait(?Send)] -impl ReceiveActivity for PersonAcceptedActivitiesNew { +impl ReceiveActivity for SharedInboxActivities { async fn receive( &self, context: &LemmyContext, diff --git a/crates/apub_receive/src/inbox/person_inbox.rs b/crates/apub_receive/src/inbox/person_inbox.rs index c0ae9a55..e8111156 100644 --- a/crates/apub_receive/src/inbox/person_inbox.rs +++ b/crates/apub_receive/src/inbox/person_inbox.rs @@ -4,13 +4,8 @@ use crate::{ is_activity_already_known, is_addressed_to_community_followers, is_addressed_to_local_person, - new_inbox_routing::{Activity, PersonAcceptedActivitiesNew}, - receive_for_community::{ - receive_add_for_community, - receive_block_user_for_community, - receive_remove_for_community, - receive_undo_for_community, - }, + new_inbox_routing::{Activity, SharedInboxActivities}, + receive_for_community::receive_add_for_community, verify_is_addressed_to_public, }, }; @@ -51,7 +46,7 @@ pub type PersonAcceptedActivities = ActorAndObject; /// Handler for all incoming activities to person inboxes. pub async fn person_inbox( _request: HttpRequest, - input: web::Json>, + input: web::Json>, _path: web::Path, context: web::Data, ) -> Result { @@ -217,26 +212,12 @@ pub async fn receive_announce( Some(Like) => todo!(), Some(Dislike) => todo!(), Some(Delete) => todo!(), - Some(Remove) => { - receive_remove_for_community(context, inner_activity, Some(announce), request_counter).await - } - Some(Undo) => { - receive_undo_for_community( - context, - inner_activity, - Some(announce), - &inner_id, - request_counter, - ) - .await - } + Some(Remove) => todo!(), + Some(Undo) => todo!(), Some(Add) => { receive_add_for_community(context, inner_activity, Some(announce), request_counter).await } - Some(Block) => { - receive_block_user_for_community(context, inner_activity, Some(announce), request_counter) - .await - } + Some(Block) => todo!(), _ => receive_unhandled_activity(inner_activity), } } diff --git a/crates/apub_receive/src/inbox/receive_for_community.rs b/crates/apub_receive/src/inbox/receive_for_community.rs index 67f262ad..c635e235 100644 --- a/crates/apub_receive/src/inbox/receive_for_community.rs +++ b/crates/apub_receive/src/inbox/receive_for_community.rs @@ -1,9 +1,9 @@ use crate::{ - activities::receive::{receive_unhandled_activity, verify_activity_domains_valid}, + activities::receive::verify_activity_domains_valid, inbox::verify_is_addressed_to_public, }; use activitystreams::{ - activity::{ActorAndObjectRef, Add, Announce, Block, OptTargetRef, Remove, Undo}, + activity::{ActorAndObjectRef, Add, Announce, OptTargetRef}, base::AnyBase, object::AsObject, prelude::*, @@ -15,24 +15,10 @@ use lemmy_apub::{ generate_moderators_url, CommunityType, }; -use lemmy_db_queries::{ - source::community::CommunityModerator_, - ApubObject, - Bannable, - Followable, - Joinable, -}; +use lemmy_db_queries::{source::community::CommunityModerator_, ApubObject, Joinable}; use lemmy_db_schema::{ source::{ - community::{ - Community, - CommunityFollower, - CommunityFollowerForm, - CommunityModerator, - CommunityModeratorForm, - CommunityPersonBan, - CommunityPersonBanForm, - }, + community::{Community, CommunityModerator, CommunityModeratorForm}, person::Person, }, DbUrl, @@ -41,7 +27,6 @@ use lemmy_db_views_actor::community_view::CommunityView; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; use strum_macros::EnumString; -use url::Url; #[derive(EnumString)] enum PageOrNote { @@ -57,48 +42,6 @@ enum ObjectTypes { Person, } -/// This file is for post/comment activities received by the community, and for post/comment -/// activities announced by the community and received by the person. - -/// A post or comment being removed by a mod/admin -pub(in crate::inbox) async fn receive_remove_for_community( - context: &LemmyContext, - remove_any_base: AnyBase, - announce: Option, - request_counter: &mut i32, -) -> Result<(), LemmyError> { - let remove = Remove::from_any_base(remove_any_base.to_owned())?.context(location_info!())?; - let community = extract_community_from_cc(&remove, context).await?; - - verify_mod_activity(&remove, announce, &community, context).await?; - verify_is_addressed_to_public(&remove)?; - - if remove.target().is_some() { - let remove_mod = remove - .object() - .as_single_xsd_any_uri() - .context(location_info!())?; - let remove_mod = get_or_fetch_and_upsert_person(&remove_mod, context, request_counter).await?; - let form = CommunityModeratorForm { - community_id: community.id, - person_id: remove_mod.id, - }; - blocking(context.pool(), move |conn| { - CommunityModerator::leave(conn, &form) - }) - .await??; - community - .send_announce( - remove_any_base, - remove.object().clone().single_xsd_any_uri(), - context, - ) - .await?; - // TODO: send websocket notification about removed mod - } - Ok(()) -} - #[derive(EnumString)] enum UndoableActivities { Delete, @@ -108,42 +51,6 @@ enum UndoableActivities { Block, } -/// A post/comment action being reverted (either a delete, remove, upvote or downvote) -pub(in crate::inbox) async fn receive_undo_for_community( - context: &LemmyContext, - activity: AnyBase, - announce: Option, - expected_domain: &Url, - request_counter: &mut i32, -) -> Result<(), LemmyError> { - let undo = Undo::from_any_base(activity)?.context(location_info!())?; - verify_activity_domains_valid(&undo, &expected_domain.to_owned(), true)?; - verify_is_addressed_to_public(&undo)?; - - use UndoableActivities::*; - match undo - .object() - .as_single_kind_str() - .and_then(|s| s.parse().ok()) - { - Some(Delete) => todo!(), - Some(Remove) => todo!(), - Some(Like) => todo!(), - Some(Dislike) => todo!(), - Some(Block) => { - receive_undo_block_user_for_community( - context, - undo, - announce, - expected_domain, - request_counter, - ) - .await - } - _ => receive_unhandled_activity(undo), - } -} - /// Add a new mod to the community (can only be done by an existing mod). pub(in crate::inbox) async fn receive_add_for_community( context: &LemmyContext, @@ -194,85 +101,6 @@ pub(in crate::inbox) async fn receive_add_for_community( Ok(()) } -pub(crate) async fn receive_block_user_for_community( - context: &LemmyContext, - block_any_base: AnyBase, - announce: Option, - request_counter: &mut i32, -) -> Result<(), LemmyError> { - let block = Block::from_any_base(block_any_base.to_owned())?.context(location_info!())?; - let community = extract_community_from_cc(&block, context).await?; - - verify_mod_activity(&block, announce, &community, context).await?; - verify_is_addressed_to_public(&block)?; - - let blocked_user = block - .object() - .as_single_xsd_any_uri() - .context(location_info!())?; - let blocked_user = - get_or_fetch_and_upsert_person(&blocked_user, context, request_counter).await?; - - let community_user_ban_form = CommunityPersonBanForm { - community_id: community.id, - person_id: blocked_user.id, - }; - - blocking(context.pool(), move |conn: &'_ _| { - CommunityPersonBan::ban(conn, &community_user_ban_form) - }) - .await??; - - // Also unsubscribe them from the community, if they are subscribed - let community_follower_form = CommunityFollowerForm { - community_id: community.id, - person_id: blocked_user.id, - pending: false, - }; - blocking(context.pool(), move |conn: &'_ _| { - CommunityFollower::unfollow(conn, &community_follower_form) - }) - .await? - .ok(); - - Ok(()) -} - -pub(crate) async fn receive_undo_block_user_for_community( - context: &LemmyContext, - undo: Undo, - announce: Option, - expected_domain: &Url, - request_counter: &mut i32, -) -> Result<(), LemmyError> { - let object = undo.object().clone().one().context(location_info!())?; - let block = Block::from_any_base(object)?.context(location_info!())?; - let community = extract_community_from_cc(&block, context).await?; - - verify_activity_domains_valid(&block, &expected_domain, false)?; - verify_is_addressed_to_public(&block)?; - verify_undo_remove_actor_instance(&undo, &block, &announce, context).await?; - - let blocked_user = block - .object() - .as_single_xsd_any_uri() - .context(location_info!())?; - let blocked_user = - get_or_fetch_and_upsert_person(&blocked_user, context, request_counter).await?; - - let community_user_ban_form = CommunityPersonBanForm { - community_id: community.id, - person_id: blocked_user.id, - }; - - blocking(context.pool(), move |conn: &'_ _| { - CommunityPersonBan::unban(conn, &community_user_ban_form) - }) - .await??; - - Ok(()) -} - /// Searches the activity's cc field for a Community ID, and returns the community. async fn extract_community_from_cc( activity: &T, @@ -384,21 +212,3 @@ where } Ok(()) } - -pub(crate) async fn verify_undo_remove_actor_instance( - undo: &Undo, - inner: &T, - announce: &Option, - context: &LemmyContext, -) -> Result<(), LemmyError> -where - T: ActorAndObjectRef + BaseExt + AsObject, -{ - if announce.is_none() { - let community = extract_community_from_cc(undo, context).await?; - verify_mod_activity(undo, announce.to_owned(), &community, context).await?; - verify_mod_activity(inner, announce.to_owned(), &community, context).await?; - } - - Ok(()) -}