mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-06-02 21:49:22 +00:00
233 lines
6.6 KiB
Rust
233 lines
6.6 KiB
Rust
use crate::{
|
|
activities::receive::get_actor_as_person,
|
|
inbox::receive_for_community::verify_actor_is_community_mod,
|
|
};
|
|
use activitystreams::{
|
|
activity::{ActorAndObjectRefExt, Delete, Undo, Update},
|
|
base::ExtendsExt,
|
|
};
|
|
use anyhow::{anyhow, Context};
|
|
use lemmy_api_common::{blocking, community::CommunityResponse};
|
|
use lemmy_apub::{
|
|
get_community_from_to_or_cc,
|
|
objects::FromApubToForm,
|
|
ActorType,
|
|
CommunityType,
|
|
GroupExt,
|
|
};
|
|
use lemmy_db_queries::{source::community::Community_, Crud};
|
|
use lemmy_db_schema::source::{
|
|
community::{Community, CommunityForm},
|
|
person::Person,
|
|
};
|
|
use lemmy_db_views_actor::{
|
|
community_moderator_view::CommunityModeratorView,
|
|
community_view::CommunityView,
|
|
};
|
|
use lemmy_utils::{location_info, LemmyError};
|
|
use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperationCrud};
|
|
|
|
/// This activity is received from a remote community mod, and updates the description or other
|
|
/// fields of a local community.
|
|
pub(crate) async fn receive_remote_mod_update_community(
|
|
update: Update,
|
|
context: &LemmyContext,
|
|
request_counter: &mut i32,
|
|
) -> Result<(), LemmyError> {
|
|
let community = get_community_from_to_or_cc(&update, context, request_counter).await?;
|
|
verify_actor_is_community_mod(&update, &community, context).await?;
|
|
let group = GroupExt::from_any_base(update.object().to_owned().one().context(location_info!())?)?
|
|
.context(location_info!())?;
|
|
let updated_community = CommunityForm::from_apub(
|
|
&group,
|
|
context,
|
|
community.actor_id(),
|
|
request_counter,
|
|
false,
|
|
)
|
|
.await?;
|
|
let cf = CommunityForm {
|
|
name: updated_community.name,
|
|
title: updated_community.title,
|
|
description: updated_community.description,
|
|
nsfw: updated_community.nsfw,
|
|
// TODO: icon and banner would be hosted on the other instance, ideally we would copy it to ours
|
|
icon: updated_community.icon,
|
|
banner: updated_community.banner,
|
|
..CommunityForm::default()
|
|
};
|
|
blocking(context.pool(), move |conn| {
|
|
Community::update(conn, community.id, &cf)
|
|
})
|
|
.await??;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) async fn receive_remote_mod_delete_community(
|
|
delete: Delete,
|
|
community: Community,
|
|
context: &LemmyContext,
|
|
request_counter: &mut i32,
|
|
) -> Result<(), LemmyError> {
|
|
verify_actor_is_community_mod(&delete, &community, context).await?;
|
|
let actor = get_actor_as_person(&delete, context, request_counter).await?;
|
|
verify_is_remote_community_creator(&actor, &community, context).await?;
|
|
let community_id = community.id;
|
|
blocking(context.pool(), move |conn| {
|
|
Community::update_deleted(conn, community_id, true)
|
|
})
|
|
.await??;
|
|
community.send_delete(actor, context).await
|
|
}
|
|
|
|
pub(crate) async fn receive_delete_community(
|
|
context: &LemmyContext,
|
|
community: Community,
|
|
) -> Result<(), LemmyError> {
|
|
let deleted_community = blocking(context.pool(), move |conn| {
|
|
Community::update_deleted(conn, community.id, true)
|
|
})
|
|
.await??;
|
|
|
|
let community_id = deleted_community.id;
|
|
let res = CommunityResponse {
|
|
community_view: blocking(context.pool(), move |conn| {
|
|
CommunityView::read(conn, community_id, None)
|
|
})
|
|
.await??,
|
|
};
|
|
|
|
let community_id = res.community_view.community.id;
|
|
context.chat_server().do_send(SendCommunityRoomMessage {
|
|
op: UserOperationCrud::EditCommunity,
|
|
response: res,
|
|
community_id,
|
|
websocket_id: None,
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) async fn receive_remove_community(
|
|
context: &LemmyContext,
|
|
community: Community,
|
|
) -> Result<(), LemmyError> {
|
|
let removed_community = blocking(context.pool(), move |conn| {
|
|
Community::update_removed(conn, community.id, true)
|
|
})
|
|
.await??;
|
|
|
|
let community_id = removed_community.id;
|
|
let res = CommunityResponse {
|
|
community_view: blocking(context.pool(), move |conn| {
|
|
CommunityView::read(conn, community_id, None)
|
|
})
|
|
.await??,
|
|
};
|
|
|
|
let community_id = res.community_view.community.id;
|
|
context.chat_server().do_send(SendCommunityRoomMessage {
|
|
op: UserOperationCrud::EditCommunity,
|
|
response: res,
|
|
community_id,
|
|
websocket_id: None,
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) async fn receive_remote_mod_undo_delete_community(
|
|
undo: Undo,
|
|
community: Community,
|
|
context: &LemmyContext,
|
|
request_counter: &mut i32,
|
|
) -> Result<(), LemmyError> {
|
|
verify_actor_is_community_mod(&undo, &community, context).await?;
|
|
let actor = get_actor_as_person(&undo, context, request_counter).await?;
|
|
verify_is_remote_community_creator(&actor, &community, context).await?;
|
|
let community_id = community.id;
|
|
blocking(context.pool(), move |conn| {
|
|
Community::update_deleted(conn, community_id, false)
|
|
})
|
|
.await??;
|
|
community.send_undo_delete(actor, context).await
|
|
}
|
|
|
|
pub(crate) async fn receive_undo_delete_community(
|
|
context: &LemmyContext,
|
|
community: Community,
|
|
) -> Result<(), LemmyError> {
|
|
let deleted_community = blocking(context.pool(), move |conn| {
|
|
Community::update_deleted(conn, community.id, false)
|
|
})
|
|
.await??;
|
|
|
|
let community_id = deleted_community.id;
|
|
let res = CommunityResponse {
|
|
community_view: blocking(context.pool(), move |conn| {
|
|
CommunityView::read(conn, community_id, None)
|
|
})
|
|
.await??,
|
|
};
|
|
|
|
let community_id = res.community_view.community.id;
|
|
context.chat_server().do_send(SendCommunityRoomMessage {
|
|
op: UserOperationCrud::EditCommunity,
|
|
response: res,
|
|
community_id,
|
|
websocket_id: None,
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) async fn receive_undo_remove_community(
|
|
context: &LemmyContext,
|
|
community: Community,
|
|
) -> Result<(), LemmyError> {
|
|
let removed_community = blocking(context.pool(), move |conn| {
|
|
Community::update_removed(conn, community.id, false)
|
|
})
|
|
.await??;
|
|
|
|
let community_id = removed_community.id;
|
|
let res = CommunityResponse {
|
|
community_view: blocking(context.pool(), move |conn| {
|
|
CommunityView::read(conn, community_id, None)
|
|
})
|
|
.await??,
|
|
};
|
|
|
|
let community_id = res.community_view.community.id;
|
|
|
|
context.chat_server().do_send(SendCommunityRoomMessage {
|
|
op: UserOperationCrud::EditCommunity,
|
|
response: res,
|
|
community_id,
|
|
websocket_id: None,
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Checks if the remote user is creator of the local community. This can only happen if a community
|
|
/// is created by a local user, and then transferred to a remote user.
|
|
async fn verify_is_remote_community_creator(
|
|
user: &Person,
|
|
community: &Community,
|
|
context: &LemmyContext,
|
|
) -> Result<(), LemmyError> {
|
|
let community_id = community.id;
|
|
let community_mods = blocking(context.pool(), move |conn| {
|
|
CommunityModeratorView::for_community(conn, community_id)
|
|
})
|
|
.await??;
|
|
|
|
if user.id != community_mods[0].moderator.id {
|
|
Err(anyhow!("Actor is not community creator").into())
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|