"lemmy_api_common",
"lemmy_db_queries",
"lemmy_db_schema",
+ "lemmy_db_views",
+ "lemmy_db_views_actor",
"lemmy_utils",
"log",
"rand 0.8.4",
use lemmy_db_schema::{source::comment::*, LocalUserId};
use lemmy_db_views::{comment_view::CommentView, local_user_view::LocalUserView};
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
-use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation};
+use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperation};
use std::convert::TryInto;
#[async_trait::async_trait(?Send)]
.await?;
}
- // Have to refetch the comment to get the current state
- let comment_id = data.comment_id;
- let person_id = local_user_view.person.id;
- let liked_comment = blocking(context.pool(), move |conn| {
- CommentView::read(conn, comment_id, Some(person_id))
- })
- .await??;
-
- let res = CommentResponse {
- comment_view: liked_comment,
- recipient_ids,
- form_id: None,
- };
-
- context.chat_server().do_send(SendComment {
- op: UserOperation::CreateCommentLike,
- comment: res.clone(),
+ send_comment_ws_message(
+ data.comment_id,
+ UserOperation::CreateCommentLike,
websocket_id,
- });
-
- Ok(res)
+ None,
+ Some(local_user_view.person.id),
+ recipient_ids,
+ context,
+ )
+ .await
}
}
use lemmy_db_schema::source::{moderator::*, post::*};
use lemmy_db_views::post_view::PostView;
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
-use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation};
+use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperation};
use std::convert::TryInto;
#[async_trait::async_trait(?Send)]
// Mark the post as read
mark_post_as_read(person_id, post_id, context.pool()).await?;
- let post_id = data.post_id;
- let person_id = local_user_view.person.id;
- let post_view = blocking(context.pool(), move |conn| {
- PostView::read(conn, post_id, Some(person_id))
- })
- .await?
- .map_err(|_| ApiError::err("couldnt_find_post"))?;
-
- let res = PostResponse { post_view };
-
- context.chat_server().do_send(SendPost {
- op: UserOperation::CreatePostLike,
- post: res.clone(),
+ send_post_ws_message(
+ data.post_id,
+ UserOperation::CreatePostLike,
websocket_id,
- });
-
- Ok(res)
+ Some(local_user_view.person.id),
+ context,
+ )
+ .await
}
}
)
.await?;
- // Refetch the post
- let post_id = data.post_id;
- let post_view = blocking(context.pool(), move |conn| {
- PostView::read(conn, post_id, Some(local_user_view.person.id))
- })
- .await??;
-
- let res = PostResponse { post_view };
-
- context.chat_server().do_send(SendPost {
- op: UserOperation::LockPost,
- post: res.clone(),
+ send_post_ws_message(
+ data.post_id,
+ UserOperation::LockPost,
websocket_id,
- });
-
- Ok(res)
+ Some(local_user_view.person.id),
+ context,
+ )
+ .await
}
}
)
.await?;
- // Refetch the post
- let post_id = data.post_id;
- let post_view = blocking(context.pool(), move |conn| {
- PostView::read(conn, post_id, Some(local_user_view.person.id))
- })
- .await??;
-
- let res = PostResponse { post_view };
-
- context.chat_server().do_send(SendPost {
- op: UserOperation::StickyPost,
- post: res.clone(),
+ send_post_ws_message(
+ data.post_id,
+ UserOperation::StickyPost,
websocket_id,
- });
-
- Ok(res)
+ Some(local_user_view.person.id),
+ context,
+ )
+ .await
}
}
};
use lemmy_db_queries::{source::private_message::PrivateMessage_, Crud};
use lemmy_db_schema::source::private_message::PrivateMessage;
-use lemmy_db_views::{local_user_view::LocalUserView, private_message_view::PrivateMessageView};
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
-use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperation};
+use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperation};
#[async_trait::async_trait(?Send)]
impl Perform for MarkPrivateMessageAsRead {
.map_err(|_| ApiError::err("couldnt_update_private_message"))?;
// No need to send an apub update
- let private_message_id = data.private_message_id;
- let private_message_view = blocking(context.pool(), move |conn| {
- PrivateMessageView::read(conn, private_message_id)
- })
- .await??;
-
- let res = PrivateMessageResponse {
- private_message_view,
- };
-
- // Send notifications to the local recipient, if one exists
- let recipient_id = orig_private_message.recipient_id;
- if let Ok(local_recipient) = blocking(context.pool(), move |conn| {
- LocalUserView::read_person(conn, recipient_id)
- })
- .await?
- {
- let local_recipient_id = local_recipient.local_user.id;
- context.chat_server().do_send(SendUserRoomMessage {
- op: UserOperation::MarkPrivateMessageAsRead,
- response: res.clone(),
- local_recipient_id,
- websocket_id,
- });
- }
-
- Ok(res)
+ let op = UserOperation::MarkPrivateMessageAsRead;
+ send_pm_ws_message(data.private_message_id, op, websocket_id, context).await
}
}
};
use lemmy_db_queries::{source::comment::Comment_, Crud, Likeable};
use lemmy_db_schema::source::comment::*;
-use lemmy_db_views::comment_view::CommentView;
use lemmy_utils::{
utils::{remove_slurs, scrape_text_for_mentions},
ApiError,
ConnectionId,
LemmyError,
};
-use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
impl PerformCrud for CreateComment {
)
.await?;
- let person_id = local_user_view.person.id;
- let mut comment_view = blocking(context.pool(), move |conn| {
- CommentView::read(conn, inserted_comment.id, Some(person_id))
- })
- .await??;
-
// If its a comment to yourself, mark it as read
- let comment_id = comment_view.comment.id;
- if local_user_view.person.id == comment_view.get_recipient_id() {
+ if local_user_view.person.id == inserted_comment.creator_id {
+ let comment_id = inserted_comment.id;
blocking(context.pool(), move |conn| {
Comment::update_read(conn, comment_id, true)
})
.await?
.map_err(|_| ApiError::err("couldnt_update_comment"))?;
- comment_view.comment.read = true;
}
- let mut res = CommentResponse {
- comment_view,
- recipient_ids,
- form_id: data.form_id.to_owned(),
- };
-
- context.chat_server().do_send(SendComment {
- op: UserOperationCrud::CreateComment,
- comment: res.clone(),
+ send_comment_ws_message(
+ inserted_comment.id,
+ UserOperationCrud::CreateComment,
websocket_id,
- });
-
- res.recipient_ids = Vec::new(); // Necessary to avoid doubles
-
- Ok(res)
+ data.form_id.to_owned(),
+ Some(local_user_view.person.id),
+ recipient_ids,
+ context,
+ )
+ .await
}
}
is_mod_or_admin,
send_local_notifs,
};
-use lemmy_apub::ApubObjectType;
-use lemmy_db_queries::{source::comment::Comment_, Crud, DeleteableOrRemoveable};
-use lemmy_db_schema::source::{comment::*, moderator::*};
+use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove};
+use lemmy_db_queries::{source::comment::Comment_, Crud};
+use lemmy_db_schema::source::{comment::*, community::Community, moderator::*, post::Post};
use lemmy_db_views::comment_view::CommentView;
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
-use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
impl PerformCrud for DeleteComment {
// Do the delete
let deleted = data.deleted;
- let mut updated_comment = blocking(context.pool(), move |conn| {
+ let updated_comment = blocking(context.pool(), move |conn| {
Comment::update_deleted(conn, comment_id, deleted)
})
.await?
.map_err(|_| ApiError::err("couldnt_update_comment"))?;
// Send the apub message
- if deleted {
- updated_comment = updated_comment.blank_out_deleted_or_removed_info();
- updated_comment
- .send_delete(&local_user_view.person, context)
- .await?;
- } else {
- updated_comment
- .send_undo_delete(&local_user_view.person, context)
- .await?;
- }
-
- // Refetch it
- let comment_id = data.comment_id;
- let person_id = local_user_view.person.id;
- let mut comment_view = blocking(context.pool(), move |conn| {
- CommentView::read(conn, comment_id, Some(person_id))
+ let community = blocking(context.pool(), move |conn| {
+ Community::read(conn, orig_comment.post.community_id)
})
.await??;
+ send_apub_delete(
+ &local_user_view.person,
+ &community,
+ updated_comment.ap_id.clone().into(),
+ deleted,
+ context,
+ )
+ .await?;
- // Blank out deleted or removed info
- if deleted {
- comment_view.comment = comment_view.comment.blank_out_deleted_or_removed_info();
- }
-
- // Build the recipients
- let comment_view_2 = comment_view.clone();
- let mentions = vec![];
+ let post_id = updated_comment.post_id;
+ let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
let recipient_ids = send_local_notifs(
- mentions,
+ vec![],
updated_comment,
local_user_view.person.clone(),
- comment_view_2.post,
+ post,
context.pool(),
false,
)
.await?;
- let res = CommentResponse {
- comment_view,
- recipient_ids,
- form_id: None, // TODO a comment delete might clear forms?
- };
-
- context.chat_server().do_send(SendComment {
- op: UserOperationCrud::DeleteComment,
- comment: res.clone(),
+ send_comment_ws_message(
+ data.comment_id,
+ UserOperationCrud::DeleteComment,
websocket_id,
- });
-
- Ok(res)
+ None, // TODO a comment delete might clear forms?
+ Some(local_user_view.person.id),
+ recipient_ids,
+ context,
+ )
+ .await
}
}
// Do the remove
let removed = data.removed;
- let mut updated_comment = blocking(context.pool(), move |conn| {
+ let updated_comment = blocking(context.pool(), move |conn| {
Comment::update_removed(conn, comment_id, removed)
})
.await?
.await??;
// Send the apub message
- if removed {
- updated_comment = updated_comment.blank_out_deleted_or_removed_info();
- updated_comment
- .send_remove(&local_user_view.person, context)
- .await?;
- } else {
- updated_comment
- .send_undo_remove(&local_user_view.person, context)
- .await?;
- }
-
- // Refetch it
- let comment_id = data.comment_id;
- let person_id = local_user_view.person.id;
- let mut comment_view = blocking(context.pool(), move |conn| {
- CommentView::read(conn, comment_id, Some(person_id))
+ let community = blocking(context.pool(), move |conn| {
+ Community::read(conn, orig_comment.post.community_id)
})
.await??;
+ send_apub_remove(
+ &local_user_view.person,
+ &community,
+ updated_comment.ap_id.clone().into(),
+ data.reason.clone().unwrap_or_else(|| "".to_string()),
+ removed,
+ context,
+ )
+ .await?;
- // Blank out deleted or removed info
- if removed {
- comment_view.comment = comment_view.comment.blank_out_deleted_or_removed_info();
- }
-
- // Build the recipients
- let comment_view_2 = comment_view.clone();
-
- let mentions = vec![];
+ let post_id = updated_comment.post_id;
+ let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
let recipient_ids = send_local_notifs(
- mentions,
+ vec![],
updated_comment,
local_user_view.person.clone(),
- comment_view_2.post,
+ post,
context.pool(),
false,
)
.await?;
- let res = CommentResponse {
- comment_view,
- recipient_ids,
- form_id: None, // TODO maybe this might clear other forms
- };
-
- context.chat_server().do_send(SendComment {
- op: UserOperationCrud::RemoveComment,
- comment: res.clone(),
+ send_comment_ws_message(
+ data.comment_id,
+ UserOperationCrud::RemoveComment,
websocket_id,
- });
-
- Ok(res)
+ None, // TODO maybe this might clear other forms
+ Some(local_user_view.person.id),
+ recipient_ids,
+ context,
+ )
+ .await
}
}
comment::create_or_update::CreateOrUpdateComment,
CreateOrUpdateType,
};
-use lemmy_db_queries::{source::comment::Comment_, DeleteableOrRemoveable};
+use lemmy_db_queries::source::comment::Comment_;
use lemmy_db_schema::source::comment::*;
use lemmy_db_views::comment_view::CommentView;
use lemmy_utils::{
ConnectionId,
LemmyError,
};
-use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
impl PerformCrud for EditComment {
)
.await?;
- let comment_id = data.comment_id;
- let person_id = local_user_view.person.id;
- let mut comment_view = blocking(context.pool(), move |conn| {
- CommentView::read(conn, comment_id, Some(person_id))
- })
- .await??;
-
- // Blank out deleted or removed info
- if comment_view.comment.deleted || comment_view.comment.removed {
- comment_view.comment = comment_view.comment.blank_out_deleted_or_removed_info();
- }
-
- let res = CommentResponse {
- comment_view,
- recipient_ids,
- form_id: data.form_id.to_owned(),
- };
-
- context.chat_server().do_send(SendComment {
- op: UserOperationCrud::EditComment,
- comment: res.clone(),
+ send_comment_ws_message(
+ data.comment_id,
+ UserOperationCrud::EditComment,
websocket_id,
- });
-
- Ok(res)
+ data.form_id.to_owned(),
+ None,
+ recipient_ids,
+ context,
+ )
+ .await
}
}
-use crate::{community::send_community_websocket, PerformCrud};
+use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt, is_admin};
-use lemmy_apub::CommunityType;
-use lemmy_db_queries::{source::community::Community_, Crud, DeleteableOrRemoveable};
+use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove};
+use lemmy_db_queries::{source::community::Community_, Crud};
use lemmy_db_schema::source::{
community::*,
moderator::{ModRemoveCommunity, ModRemoveCommunityForm},
};
-use lemmy_db_views_actor::{
- community_moderator_view::CommunityModeratorView,
- community_view::CommunityView,
-};
+use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView;
use lemmy_utils::{utils::naive_from_unix, ApiError, ConnectionId, LemmyError};
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
impl PerformCrud for DeleteCommunity {
.map_err(|_| ApiError::err("couldnt_update_community"))?;
// Send apub messages
- if deleted {
- updated_community
- .blank_out_deleted_or_removed_info()
- .send_delete(local_user_view.person.to_owned(), context)
- .await?;
- } else {
- updated_community
- .send_undo_delete(local_user_view.person.to_owned(), context)
- .await?;
- }
-
- let community_id = data.community_id;
- let person_id = local_user_view.person.id;
- let mut community_view = blocking(context.pool(), move |conn| {
- CommunityView::read(conn, community_id, Some(person_id))
- })
- .await??;
-
- // Blank out deleted or removed info
- if deleted {
- community_view.community = community_view.community.blank_out_deleted_or_removed_info();
- }
-
- let res = CommunityResponse { community_view };
-
- send_community_websocket(
- &res,
+ send_apub_delete(
+ &local_user_view.person,
+ &updated_community,
+ updated_community.actor_id.clone().into(),
+ deleted,
context,
- websocket_id,
- UserOperationCrud::DeleteCommunity,
- );
+ )
+ .await?;
- Ok(res)
+ send_community_ws_message(
+ data.community_id,
+ UserOperationCrud::DeleteCommunity,
+ websocket_id,
+ Some(local_user_view.person.id),
+ context,
+ )
+ .await
}
}
.await??;
// Apub messages
- if removed {
- updated_community
- .blank_out_deleted_or_removed_info()
- .send_remove(context)
- .await?;
- } else {
- updated_community.send_undo_remove(context).await?;
- }
-
- let community_id = data.community_id;
- let person_id = local_user_view.person.id;
- let mut community_view = blocking(context.pool(), move |conn| {
- CommunityView::read(conn, community_id, Some(person_id))
- })
- .await??;
-
- // Blank out deleted or removed info
- if removed {
- community_view.community = community_view.community.blank_out_deleted_or_removed_info();
- }
-
- let res = CommunityResponse { community_view };
-
- send_community_websocket(
- &res,
+ send_apub_remove(
+ &local_user_view.person,
+ &updated_community,
+ updated_community.actor_id.clone().into(),
+ data.reason.clone().unwrap_or_else(|| "".to_string()),
+ removed,
context,
- websocket_id,
- UserOperationCrud::RemoveCommunity,
- );
+ )
+ .await?;
- Ok(res)
+ send_community_ws_message(
+ data.community_id,
+ UserOperationCrud::RemoveCommunity,
+ websocket_id,
+ Some(local_user_view.person.id),
+ context,
+ )
+ .await
}
}
-use actix_web::web::Data;
-use lemmy_api_common::community::CommunityResponse;
-use lemmy_utils::ConnectionId;
-use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperationCrud};
-
mod create;
mod delete;
mod read;
mod update;
-
-pub(in crate::community) fn send_community_websocket(
- res: &CommunityResponse,
- context: &Data<LemmyContext>,
- websocket_id: Option<ConnectionId>,
- op: UserOperationCrud,
-) {
- // Strip out the person id and subscribed when sending to others
- let mut res_sent = res.clone();
- res_sent.community_view.subscribed = false;
-
- context.chat_server().do_send(SendCommunityRoomMessage {
- op,
- response: res_sent,
- community_id: res.community_view.community.id,
- websocket_id,
- });
-}
-use crate::{community::send_community_websocket, PerformCrud};
+use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
blocking,
get_local_user_view_from_jwt,
};
use lemmy_apub::CommunityType;
-use lemmy_db_queries::{diesel_option_overwrite_to_url, Crud, DeleteableOrRemoveable};
+use lemmy_db_queries::{diesel_option_overwrite_to_url, Crud};
use lemmy_db_schema::{
naive_now,
source::community::{Community, CommunityForm},
PersonId,
};
-use lemmy_db_views_actor::{
- community_moderator_view::CommunityModeratorView,
- community_view::CommunityView,
-};
+use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView;
use lemmy_utils::{utils::check_slurs_opt, ApiError, ConnectionId, LemmyError};
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
impl PerformCrud for EditCommunity {
.send_update(local_user_view.person.to_owned(), context)
.await?;
- let community_id = data.community_id;
- let person_id = local_user_view.person.id;
- let mut community_view = blocking(context.pool(), move |conn| {
- CommunityView::read(conn, community_id, Some(person_id))
- })
- .await??;
-
- // Blank out deleted or removed info
- if community_view.community.deleted || community_view.community.removed {
- community_view.community = community_view.community.blank_out_deleted_or_removed_info();
- }
-
- let res = CommunityResponse { community_view };
-
- send_community_websocket(
- &res,
- context,
- websocket_id,
- UserOperationCrud::EditCommunity,
- );
-
- Ok(res)
+ let op = UserOperationCrud::EditCommunity;
+ send_community_ws_message(data.community_id, op, websocket_id, None, context).await
}
}
};
use lemmy_db_queries::{source::post::Post_, Crud, Likeable};
use lemmy_db_schema::source::post::*;
-use lemmy_db_views::post_view::PostView;
use lemmy_utils::{
request::fetch_iframely_and_pictrs_data,
utils::{check_slurs, check_slurs_opt, clean_url_params, is_valid_post_title},
ConnectionId,
LemmyError,
};
-use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
impl PerformCrud for CreatePost {
)
.await?;
- // Refetch the view
- let inserted_post_id = inserted_post.id;
- let post_view = blocking(context.pool(), move |conn| {
- PostView::read(conn, inserted_post_id, Some(local_user_view.person.id))
- })
- .await?
- .map_err(|_| ApiError::err("couldnt_find_post"))?;
-
- let res = PostResponse { post_view };
-
- context.chat_server().do_send(SendPost {
- op: UserOperationCrud::CreatePost,
- post: res.clone(),
+ send_post_ws_message(
+ inserted_post.id,
+ UserOperationCrud::CreatePost,
websocket_id,
- });
-
- Ok(res)
+ Some(local_user_view.person.id),
+ context,
+ )
+ .await
}
}
is_mod_or_admin,
post::*,
};
-use lemmy_apub::ApubObjectType;
-use lemmy_db_queries::{source::post::Post_, Crud, DeleteableOrRemoveable};
-use lemmy_db_schema::source::{moderator::*, post::*};
-use lemmy_db_views::post_view::PostView;
+use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove};
+use lemmy_db_queries::{source::post::Post_, Crud};
+use lemmy_db_schema::source::{community::Community, moderator::*, post::*};
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
-use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
impl PerformCrud for DeletePost {
.await??;
// apub updates
- if deleted {
- updated_post
- .blank_out_deleted_or_removed_info()
- .send_delete(&local_user_view.person, context)
- .await?;
- } else {
- updated_post
- .send_undo_delete(&local_user_view.person, context)
- .await?;
- }
-
- // Refetch the post
- let post_id = data.post_id;
- let mut post_view = blocking(context.pool(), move |conn| {
- PostView::read(conn, post_id, Some(local_user_view.person.id))
+ let community = blocking(context.pool(), move |conn| {
+ Community::read(conn, orig_post.community_id)
})
.await??;
+ send_apub_delete(
+ &local_user_view.person,
+ &community,
+ updated_post.ap_id.into(),
+ deleted,
+ context,
+ )
+ .await?;
- if deleted {
- post_view.post = post_view.post.blank_out_deleted_or_removed_info();
- }
-
- let res = PostResponse { post_view };
-
- context.chat_server().do_send(SendPost {
- op: UserOperationCrud::DeletePost,
- post: res.clone(),
+ send_post_ws_message(
+ data.post_id,
+ UserOperationCrud::DeletePost,
websocket_id,
- });
-
- Ok(res)
+ Some(local_user_view.person.id),
+ context,
+ )
+ .await
}
}
.await??;
// apub updates
- if removed {
- updated_post
- .blank_out_deleted_or_removed_info()
- .send_remove(&local_user_view.person, context)
- .await?;
- } else {
- updated_post
- .send_undo_remove(&local_user_view.person, context)
- .await?;
- }
-
- // Refetch the post
- let post_id = data.post_id;
- let person_id = local_user_view.person.id;
- let mut post_view = blocking(context.pool(), move |conn| {
- PostView::read(conn, post_id, Some(person_id))
+ let community = blocking(context.pool(), move |conn| {
+ Community::read(conn, orig_post.community_id)
})
.await??;
+ send_apub_remove(
+ &local_user_view.person,
+ &community,
+ updated_post.ap_id.into(),
+ data.reason.clone().unwrap_or_else(|| "".to_string()),
+ removed,
+ context,
+ )
+ .await?;
- // Blank out deleted or removed info
- if removed {
- post_view.post = post_view.post.blank_out_deleted_or_removed_info();
- }
-
- let res = PostResponse { post_view };
-
- context.chat_server().do_send(SendPost {
- op: UserOperationCrud::RemovePost,
- post: res.clone(),
+ send_post_ws_message(
+ data.post_id,
+ UserOperationCrud::RemovePost,
websocket_id,
- });
-
- Ok(res)
+ Some(local_user_view.person.id),
+ context,
+ )
+ .await
}
}
use actix_web::web::Data;
use lemmy_api_common::{blocking, check_community_ban, get_local_user_view_from_jwt, post::*};
use lemmy_apub::activities::{post::create_or_update::CreateOrUpdatePost, CreateOrUpdateType};
-use lemmy_db_queries::{source::post::Post_, Crud, DeleteableOrRemoveable};
+use lemmy_db_queries::{source::post::Post_, Crud};
use lemmy_db_schema::{naive_now, source::post::*};
-use lemmy_db_views::post_view::PostView;
use lemmy_utils::{
request::fetch_iframely_and_pictrs_data,
utils::{check_slurs_opt, clean_url_params, is_valid_post_title},
ConnectionId,
LemmyError,
};
-use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
impl PerformCrud for EditPost {
)
.await?;
- let post_id = data.post_id;
- let mut post_view = blocking(context.pool(), move |conn| {
- PostView::read(conn, post_id, Some(local_user_view.person.id))
- })
- .await??;
-
- // Blank out deleted info
- if post_view.post.deleted || post_view.post.removed {
- post_view.post = post_view.post.blank_out_deleted_or_removed_info();
- }
-
- let res = PostResponse { post_view };
-
- context.chat_server().do_send(SendPost {
- op: UserOperationCrud::EditPost,
- post: res.clone(),
+ send_post_ws_message(
+ data.post_id,
+ UserOperationCrud::EditPost,
websocket_id,
- });
-
- Ok(res)
+ Some(local_user_view.person.id),
+ context,
+ )
+ .await
}
}
};
use lemmy_db_queries::{source::private_message::PrivateMessage_, Crud};
use lemmy_db_schema::source::private_message::{PrivateMessage, PrivateMessageForm};
-use lemmy_db_views::{local_user_view::LocalUserView, private_message_view::PrivateMessageView};
+use lemmy_db_views::local_user_view::LocalUserView;
use lemmy_utils::{utils::remove_slurs, ApiError, ConnectionId, LemmyError};
-use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
impl PerformCrud for CreatePrivateMessage {
)
.await?;
- let private_message_view = blocking(context.pool(), move |conn| {
- PrivateMessageView::read(conn, inserted_private_message.id)
- })
- .await??;
-
- let res = PrivateMessageResponse {
- private_message_view,
- };
+ let res = send_pm_ws_message(
+ inserted_private_message.id,
+ UserOperationCrud::CreatePrivateMessage,
+ websocket_id,
+ context,
+ )
+ .await?;
- // Send notifications to the local recipient, if one exists
- let recipient_id = data.recipient_id;
- if let Ok(local_recipient) = blocking(context.pool(), move |conn| {
- LocalUserView::read_person(conn, recipient_id)
- })
- .await?
- {
+ // Send email to the local recipient, if one exists
+ if res.private_message_view.recipient.local {
+ let recipient_id = data.recipient_id;
+ let local_recipient = blocking(context.pool(), move |conn| {
+ LocalUserView::read_person(conn, recipient_id)
+ })
+ .await??;
send_email_to_user(
&local_recipient,
"Private Message from",
"Private Message",
&content_slurs_removed,
);
-
- let local_recipient_id = local_recipient.local_user.id;
- context.chat_server().do_send(SendUserRoomMessage {
- op: UserOperationCrud::CreatePrivateMessage,
- response: res.clone(),
- local_recipient_id,
- websocket_id,
- });
}
Ok(res)
};
use lemmy_db_queries::{source::private_message::PrivateMessage_, Crud, DeleteableOrRemoveable};
use lemmy_db_schema::source::private_message::PrivateMessage;
-use lemmy_db_views::{local_user_view::LocalUserView, private_message_view::PrivateMessageView};
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
-use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
impl PerformCrud for DeletePrivateMessage {
.await?;
}
- let private_message_id = data.private_message_id;
- let mut private_message_view = blocking(context.pool(), move |conn| {
- PrivateMessageView::read(conn, private_message_id)
- })
- .await??;
-
- // Blank out deleted or removed info
- if deleted {
- private_message_view.private_message = private_message_view
- .private_message
- .blank_out_deleted_or_removed_info();
- }
-
- let res = PrivateMessageResponse {
- private_message_view,
- };
-
- // Send notifications to the local recipient, if one exists
- let recipient_id = orig_private_message.recipient_id;
- if let Ok(local_recipient) = blocking(context.pool(), move |conn| {
- LocalUserView::read_person(conn, recipient_id)
- })
- .await?
- {
- let local_recipient_id = local_recipient.local_user.id;
- context.chat_server().do_send(SendUserRoomMessage {
- op: UserOperationCrud::DeletePrivateMessage,
- response: res.clone(),
- local_recipient_id,
- websocket_id,
- });
- }
-
- Ok(res)
+ let op = UserOperationCrud::DeletePrivateMessage;
+ send_pm_ws_message(data.private_message_id, op, websocket_id, context).await
}
}
private_message::create_or_update::CreateOrUpdatePrivateMessage,
CreateOrUpdateType,
};
-use lemmy_db_queries::{source::private_message::PrivateMessage_, Crud, DeleteableOrRemoveable};
+use lemmy_db_queries::{source::private_message::PrivateMessage_, Crud};
use lemmy_db_schema::source::private_message::PrivateMessage;
-use lemmy_db_views::{local_user_view::LocalUserView, private_message_view::PrivateMessageView};
use lemmy_utils::{utils::remove_slurs, ApiError, ConnectionId, LemmyError};
-use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
impl PerformCrud for EditPrivateMessage {
)
.await?;
- let private_message_id = data.private_message_id;
- let mut private_message_view = blocking(context.pool(), move |conn| {
- PrivateMessageView::read(conn, private_message_id)
- })
- .await??;
-
- // Blank out deleted or removed info
- if private_message_view.private_message.deleted {
- private_message_view.private_message = private_message_view
- .private_message
- .blank_out_deleted_or_removed_info();
- }
-
- let res = PrivateMessageResponse {
- private_message_view,
- };
-
- // Send notifications to the local recipient, if one exists
- let recipient_id = orig_private_message.recipient_id;
- if let Ok(local_recipient) = blocking(context.pool(), move |conn| {
- LocalUserView::read_person(conn, recipient_id)
- })
- .await?
- {
- let local_recipient_id = local_recipient.local_user.id;
- context.chat_server().do_send(SendUserRoomMessage {
- op: UserOperationCrud::EditPrivateMessage,
- response: res.clone(),
- local_recipient_id,
- websocket_id,
- });
- }
-
- Ok(res)
+ let op = UserOperationCrud::EditPrivateMessage;
+ send_pm_ws_message(data.private_message_id, op, websocket_id, context).await
}
}
use crate::{
activities::{
- comment::{collect_non_local_mentions, get_notif_recipients, send_websocket_message},
+ comment::{collect_non_local_mentions, get_notif_recipients},
community::announce::AnnouncableActivities,
extract_community,
generate_activity_id,
use lemmy_db_queries::Crud;
use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post};
use lemmy_utils::LemmyError;
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperationCrud};
use serde::{Deserialize, Serialize};
use url::Url;
CreateOrUpdateType::Create => UserOperationCrud::CreateComment,
CreateOrUpdateType::Update => UserOperationCrud::EditComment,
};
- send_websocket_message(comment.id, recipients, notif_type, context).await
+ send_comment_ws_message(
+ comment.id, notif_type, None, None, None, recipients, context,
+ )
+ .await?;
+ Ok(())
}
fn common(&self) -> &ActivityCommonFields {
};
use anyhow::anyhow;
use itertools::Itertools;
-use lemmy_api_common::{blocking, comment::CommentResponse, send_local_notifs, WebFingerResponse};
+use lemmy_api_common::{blocking, send_local_notifs, WebFingerResponse};
use lemmy_db_queries::{Crud, DbPool};
use lemmy_db_schema::{
source::{comment::Comment, community::Community, person::Person, post::Post},
- CommentId,
LocalUserId,
};
-use lemmy_db_views::comment_view::CommentView;
use lemmy_utils::{
request::{retry, RecvError},
settings::structs::Settings,
utils::{scrape_text_for_mentions, MentionData},
LemmyError,
};
-use lemmy_websocket::{messages::SendComment, LemmyContext};
+use lemmy_websocket::LemmyContext;
use log::debug;
use reqwest::Client;
use url::Url;
send_local_notifs(mentions, comment.clone(), actor, post, context.pool(), true).await
}
-// TODO: in many call sites we are setting an empty vec for recipient_ids, we should get the actual
-// recipient actors from somewhere
-pub(crate) async fn send_websocket_message<
- OP: ToString + Send + lemmy_websocket::OperationType + 'static,
->(
- comment_id: CommentId,
- recipient_ids: Vec<LocalUserId>,
- op: OP,
- context: &LemmyContext,
-) -> Result<(), LemmyError> {
- // Refetch the view
- let comment_view = blocking(context.pool(), move |conn| {
- CommentView::read(conn, comment_id, None)
- })
- .await??;
-
- let res = CommentResponse {
- comment_view,
- recipient_ids,
- form_id: None,
- };
-
- context.chat_server().do_send(SendComment {
- op,
- comment: res,
- websocket_id: None,
- });
-
- Ok(())
-}
-
pub struct MentionsAndAddresses {
pub ccs: Vec<Url>,
pub inboxes: Vec<Url>,
list_community_follower_inboxes,
undo_block_user::UndoBlockUserFromCommunity,
},
- deletion::{
- delete::DeletePostCommentOrCommunity,
- undo_delete::UndoDeletePostCommentOrCommunity,
- },
+ deletion::{delete::Delete, undo_delete::UndoDelete},
generate_activity_id,
post::create_or_update::CreateOrUpdatePost,
- removal::{
- remove::RemovePostCommentCommunityOrMod,
- undo_remove::UndoRemovePostCommentOrCommunity,
- },
+ removal::{remove::RemoveMod, undo_remove::UndoRemovePostCommentOrCommunity},
verify_activity,
verify_community,
voting::{undo_vote::UndoVote, vote::Vote},
CreateOrUpdatePost(Box<CreateOrUpdatePost>),
Vote(Vote),
UndoVote(UndoVote),
- DeletePostCommentOrCommunity(DeletePostCommentOrCommunity),
- UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity),
- RemovePostCommentCommunityOrMod(RemovePostCommentCommunityOrMod),
+ Delete(Delete),
+ UndoDelete(UndoDelete),
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
BlockUserFromCommunity(BlockUserFromCommunity),
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
AddMod(AddMod),
+ RemoveMod(RemoveMod),
}
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
use crate::{check_is_apub_id_valid, CommunityType};
use itertools::Itertools;
-use lemmy_api_common::{blocking, community::CommunityResponse};
-use lemmy_db_schema::{source::community::Community, CommunityId};
-use lemmy_db_views_actor::community_view::CommunityView;
+use lemmy_db_schema::source::community::Community;
use lemmy_utils::{settings::structs::Settings, LemmyError};
-use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext};
+use lemmy_websocket::LemmyContext;
use url::Url;
pub mod add_mod;
pub mod undo_block_user;
pub mod update;
-pub(crate) async fn send_websocket_message<
- OP: ToString + Send + lemmy_websocket::OperationType + 'static,
->(
- community_id: CommunityId,
- op: OP,
- context: &LemmyContext,
-) -> Result<(), LemmyError> {
- let community_view = blocking(context.pool(), move |conn| {
- CommunityView::read(conn, community_id, None)
- })
- .await??;
-
- let res = CommunityResponse { community_view };
-
- context.chat_server().do_send(SendCommunityRoomMessage {
- op,
- response: res,
- community_id,
- websocket_id: None,
- });
-
- Ok(())
-}
-
async fn list_community_follower_inboxes(
community: &Community,
additional_inboxes: Vec<Url>,
use crate::{
- activities::{
- community::send_websocket_message,
- verify_activity,
- verify_mod_action,
- verify_person_in_community,
- },
+ activities::{verify_activity, verify_mod_action, verify_person_in_community},
objects::community::Group,
};
use activitystreams::activity::kind::UpdateType;
use lemmy_db_queries::{ApubObject, Crud};
use lemmy_db_schema::source::community::{Community, CommunityForm};
use lemmy_utils::LemmyError;
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
use url::Url;
/// This activity is received from a remote community mod, and updates the description or other
})
.await??;
- send_websocket_message(
+ send_community_ws_message(
updated_community.id,
UserOperationCrud::EditCommunity,
+ None,
+ None,
context,
)
- .await
+ .await?;
+ Ok(())
}
fn common(&self) -> &ActivityCommonFields {
use crate::{
activities::{
- comment::send_websocket_message as send_comment_message,
- community::send_websocket_message as send_community_message,
- post::send_websocket_message as send_post_message,
+ community::announce::AnnouncableActivities,
+ deletion::{
+ receive_delete_action,
+ verify_delete_activity,
+ DeletableObjects,
+ WebsocketMessages,
+ },
+ generate_activity_id,
verify_activity,
- verify_mod_action,
- verify_person_in_community,
- },
- fetcher::{
- community::get_or_fetch_and_upsert_community,
- objects::get_or_fetch_and_insert_post_or_comment,
- person::get_or_fetch_and_upsert_person,
},
+ activity_queue::send_to_community_new,
+ extensions::context::lemmy_context,
+ fetcher::person::get_or_fetch_and_upsert_person,
ActorType,
- CommunityType,
- PostOrComment,
};
use activitystreams::activity::kind::DeleteType;
+use anyhow::anyhow;
use lemmy_api_common::blocking;
-use lemmy_apub_lib::{values::PublicUrl, verify_urls_match, ActivityCommonFields, ActivityHandler};
+use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
use lemmy_db_queries::{
source::{comment::Comment_, community::Community_, post::Post_},
Crud,
};
-use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post};
+use lemmy_db_schema::source::{
+ comment::Comment,
+ community::Community,
+ moderator::{
+ ModRemoveComment,
+ ModRemoveCommentForm,
+ ModRemoveCommunity,
+ ModRemoveCommunityForm,
+ ModRemovePost,
+ ModRemovePostForm,
+ },
+ person::Person,
+ post::Post,
+};
use lemmy_utils::LemmyError;
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::{
+ send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
+ LemmyContext,
+ UserOperationCrud,
+};
use url::Url;
/// This is very confusing, because there are four distinct cases to handle:
/// wrapping it in an announce just like other activities, instead of having the community send it.
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
-pub struct DeletePostCommentOrCommunity {
- to: PublicUrl,
+pub struct Delete {
+ pub(in crate::activities::deletion) to: PublicUrl,
pub(in crate::activities::deletion) object: Url,
- cc: [Url; 1],
+ pub(in crate::activities::deletion) cc: [Url; 1],
#[serde(rename = "type")]
- kind: DeleteType,
+ pub(in crate::activities::deletion) kind: DeleteType,
+ /// If summary is present, this is a mod action (Remove in Lemmy terms). Otherwise, its a user
+ /// deleting their own content.
+ pub(in crate::activities::deletion) summary: Option<String>,
#[serde(flatten)]
- common: ActivityCommonFields,
+ pub(in crate::activities::deletion) common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
-impl ActivityHandler for DeletePostCommentOrCommunity {
+impl ActivityHandler for Delete {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self.common())?;
- let object_community =
- get_or_fetch_and_upsert_community(&self.object, context, request_counter).await;
- // deleting a community (set counter 0 to only fetch from local db)
- if object_community.is_ok() {
- verify_mod_action(&self.common.actor, self.object.clone(), context).await?;
- }
- // deleting a post or comment
- else {
- verify_person_in_community(&self.common().actor, &self.cc[0], context, request_counter)
- .await?;
- let object_creator =
- get_post_or_comment_actor_id(&self.object, context, request_counter).await?;
- verify_urls_match(&self.common.actor, &object_creator)?;
- }
+ verify_delete_activity(
+ &self.object,
+ &self.cc[0],
+ &self.common,
+ self.summary.is_some(),
+ context,
+ request_counter,
+ )
+ .await?;
Ok(())
}
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- let object_community =
- get_or_fetch_and_upsert_community(&self.object, context, request_counter).await;
- // deleting a community
- if let Ok(community) = object_community {
- if community.local {
- // repeat these checks just to be sure
- verify_person_in_community(&self.common().actor, &self.cc[0], context, request_counter)
- .await?;
- verify_mod_action(&self.common.actor, self.object.clone(), context).await?;
- let mod_ =
- get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?;
- community.send_delete(mod_, context).await?;
- }
- let deleted_community = blocking(context.pool(), move |conn| {
- Community::update_deleted(conn, community.id, true)
- })
- .await??;
-
- send_community_message(
- deleted_community.id,
- UserOperationCrud::DeleteCommunity,
+ if let Some(reason) = self.summary {
+ // We set reason to empty string if it doesn't exist, to distinguish between delete and
+ // remove. Here we change it back to option, so we don't write it to db.
+ let reason = if reason.is_empty() {
+ None
+ } else {
+ Some(reason)
+ };
+ receive_remove_action(
+ &self.common.actor,
+ &self.object,
+ reason,
context,
+ request_counter,
+ )
+ .await
+ } else {
+ receive_delete_action(
+ &self.object,
+ &self.common.actor,
+ WebsocketMessages {
+ community: UserOperationCrud::DeleteCommunity,
+ post: UserOperationCrud::DeletePost,
+ comment: UserOperationCrud::DeleteComment,
+ },
+ true,
+ context,
+ request_counter,
)
.await
- }
- // deleting a post or comment
- else {
- match get_or_fetch_and_insert_post_or_comment(&self.object, context, request_counter).await? {
- PostOrComment::Post(post) => {
- let deleted_post = blocking(context.pool(), move |conn| {
- Post::update_deleted(conn, post.id, true)
- })
- .await??;
- send_post_message(deleted_post.id, UserOperationCrud::EditPost, context).await
- }
- PostOrComment::Comment(comment) => {
- let deleted_comment = blocking(context.pool(), move |conn| {
- Comment::update_deleted(conn, comment.id, true)
- })
- .await??;
- send_comment_message(
- deleted_comment.id,
- vec![],
- UserOperationCrud::EditComment,
- context,
- )
- .await
- }
- }
}
}
}
}
-async fn get_post_or_comment_actor_id(
+impl Delete {
+ pub(in crate::activities::deletion) async fn send(
+ actor: &Person,
+ community: &Community,
+ object_id: Url,
+ summary: Option<String>,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let id = generate_activity_id(DeleteType::Delete)?;
+ let delete = Delete {
+ to: PublicUrl::Public,
+ object: object_id,
+ cc: [community.actor_id()],
+ kind: DeleteType::Delete,
+ summary,
+ common: ActivityCommonFields {
+ context: lemmy_context(),
+ id: id.clone(),
+ actor: actor.actor_id(),
+ unparsed: Default::default(),
+ },
+ };
+
+ let activity = AnnouncableActivities::Delete(delete);
+ send_to_community_new(activity, &id, actor, community, vec![], context).await
+ }
+}
+
+pub(in crate::activities) async fn receive_remove_action(
+ actor: &Url,
object: &Url,
+ reason: Option<String>,
context: &LemmyContext,
request_counter: &mut i32,
-) -> Result<Url, LemmyError> {
- let actor_id =
- match get_or_fetch_and_insert_post_or_comment(object, context, request_counter).await? {
- PostOrComment::Post(post) => {
- let creator_id = post.creator_id;
- blocking(context.pool(), move |conn| Person::read(conn, creator_id))
- .await??
- .actor_id()
- }
- PostOrComment::Comment(comment) => {
- let creator_id = comment.creator_id;
- blocking(context.pool(), move |conn| Person::read(conn, creator_id))
- .await??
- .actor_id()
+) -> Result<(), LemmyError> {
+ let actor = get_or_fetch_and_upsert_person(actor, context, request_counter).await?;
+ use UserOperationCrud::*;
+ match DeletableObjects::read_from_db(object, context).await? {
+ DeletableObjects::Community(community) => {
+ if community.local {
+ return Err(anyhow!("Only local admin can remove community").into());
}
- };
- Ok(actor_id)
+ let form = ModRemoveCommunityForm {
+ mod_person_id: actor.id,
+ community_id: community.id,
+ removed: Some(true),
+ reason,
+ expires: None,
+ };
+ blocking(context.pool(), move |conn| {
+ ModRemoveCommunity::create(conn, &form)
+ })
+ .await??;
+ let deleted_community = blocking(context.pool(), move |conn| {
+ Community::update_removed(conn, community.id, true)
+ })
+ .await??;
+
+ send_community_ws_message(deleted_community.id, RemoveCommunity, None, None, context).await?;
+ }
+ DeletableObjects::Post(post) => {
+ let form = ModRemovePostForm {
+ mod_person_id: actor.id,
+ post_id: post.id,
+ removed: Some(true),
+ reason,
+ };
+ blocking(context.pool(), move |conn| {
+ ModRemovePost::create(conn, &form)
+ })
+ .await??;
+ let removed_post = blocking(context.pool(), move |conn| {
+ Post::update_removed(conn, post.id, true)
+ })
+ .await??;
+
+ send_post_ws_message(removed_post.id, RemovePost, None, None, context).await?;
+ }
+ DeletableObjects::Comment(comment) => {
+ let form = ModRemoveCommentForm {
+ mod_person_id: actor.id,
+ comment_id: comment.id,
+ removed: Some(true),
+ reason,
+ };
+ blocking(context.pool(), move |conn| {
+ ModRemoveComment::create(conn, &form)
+ })
+ .await??;
+ let removed_comment = blocking(context.pool(), move |conn| {
+ Comment::update_removed(conn, comment.id, true)
+ })
+ .await??;
+
+ send_comment_ws_message_simple(removed_comment.id, RemoveComment, context).await?;
+ }
+ }
+ Ok(())
}
+use crate::{
+ activities::{
+ deletion::{delete::Delete, undo_delete::UndoDelete},
+ verify_mod_action,
+ verify_person_in_community,
+ },
+ fetcher::person::get_or_fetch_and_upsert_person,
+ ActorType,
+};
+use lemmy_api_common::blocking;
+use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields};
+use lemmy_db_queries::{
+ source::{comment::Comment_, community::Community_, post::Post_},
+ ApubObject,
+};
+use lemmy_db_schema::{
+ source::{comment::Comment, community::Community, person::Person, post::Post},
+ DbUrl,
+};
+use lemmy_utils::LemmyError;
+use lemmy_websocket::{
+ send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
+ LemmyContext,
+ UserOperationCrud,
+};
+use url::Url;
+
pub mod delete;
pub mod undo_delete;
+
+pub async fn send_apub_delete(
+ actor: &Person,
+ community: &Community,
+ object_id: Url,
+ deleted: bool,
+ context: &LemmyContext,
+) -> Result<(), LemmyError> {
+ if deleted {
+ Delete::send(actor, community, object_id, None, context).await
+ } else {
+ UndoDelete::send(actor, community, object_id, None, context).await
+ }
+}
+
+// TODO: remove reason is actually optional in lemmy. we set an empty string in that case, but its
+// ugly
+pub async fn send_apub_remove(
+ actor: &Person,
+ community: &Community,
+ object_id: Url,
+ reason: String,
+ removed: bool,
+ context: &LemmyContext,
+) -> Result<(), LemmyError> {
+ if removed {
+ Delete::send(actor, community, object_id, Some(reason), context).await
+ } else {
+ UndoDelete::send(actor, community, object_id, Some(reason), context).await
+ }
+}
+
+pub enum DeletableObjects {
+ Community(Box<Community>),
+ Comment(Box<Comment>),
+ Post(Box<Post>),
+}
+
+impl DeletableObjects {
+ pub(crate) async fn read_from_db(
+ ap_id: &Url,
+ context: &LemmyContext,
+ ) -> Result<DeletableObjects, LemmyError> {
+ let id: DbUrl = ap_id.clone().into();
+
+ if let Some(c) = DeletableObjects::read_type_from_db::<Community>(id.clone(), context).await? {
+ return Ok(DeletableObjects::Community(Box::new(c)));
+ }
+ if let Some(p) = DeletableObjects::read_type_from_db::<Post>(id.clone(), context).await? {
+ return Ok(DeletableObjects::Post(Box::new(p)));
+ }
+ if let Some(c) = DeletableObjects::read_type_from_db::<Comment>(id.clone(), context).await? {
+ return Ok(DeletableObjects::Comment(Box::new(c)));
+ }
+ Err(diesel::NotFound.into())
+ }
+
+ // TODO: a method like this should be provided by fetcher module
+ async fn read_type_from_db<Type: ApubObject + Send + 'static>(
+ ap_id: DbUrl,
+ context: &LemmyContext,
+ ) -> Result<Option<Type>, LemmyError> {
+ blocking(context.pool(), move |conn| {
+ Type::read_from_apub_id(conn, &ap_id).ok()
+ })
+ .await
+ }
+}
+
+pub(in crate::activities) async fn verify_delete_activity(
+ object: &Url,
+ cc: &Url,
+ common: &ActivityCommonFields,
+ is_mod_action: bool,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+) -> Result<(), LemmyError> {
+ let object = DeletableObjects::read_from_db(object, context).await?;
+ match object {
+ DeletableObjects::Community(c) => {
+ if c.local {
+ // can only do this check for local community, in remote case it would try to fetch the
+ // deleted community (which fails)
+ verify_person_in_community(&common.actor, cc, context, request_counter).await?;
+ }
+ // community deletion is always a mod (or admin) action
+ verify_mod_action(&common.actor, c.actor_id(), context).await?;
+ }
+ DeletableObjects::Post(p) => {
+ verify_delete_activity_post_or_comment(
+ cc,
+ common,
+ &p.ap_id.into(),
+ is_mod_action,
+ context,
+ request_counter,
+ )
+ .await?;
+ }
+ DeletableObjects::Comment(c) => {
+ verify_delete_activity_post_or_comment(
+ cc,
+ common,
+ &c.ap_id.into(),
+ is_mod_action,
+ context,
+ request_counter,
+ )
+ .await?;
+ }
+ }
+ Ok(())
+}
+
+async fn verify_delete_activity_post_or_comment(
+ cc: &Url,
+ common: &ActivityCommonFields,
+ object_id: &Url,
+ is_mod_action: bool,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+) -> Result<(), LemmyError> {
+ verify_person_in_community(&common.actor, cc, context, request_counter).await?;
+ if is_mod_action {
+ verify_mod_action(&common.actor, cc.clone(), context).await?;
+ } else {
+ // domain of post ap_id and post.creator ap_id are identical, so we just check the former
+ verify_domains_match(&common.actor, object_id)?;
+ }
+ Ok(())
+}
+
+struct WebsocketMessages {
+ community: UserOperationCrud,
+ post: UserOperationCrud,
+ comment: UserOperationCrud,
+}
+
+/// Write deletion or restoring of an object to the database, and send websocket message.
+/// TODO: we should do something similar for receive_remove_action(), but its much more complicated
+/// because of the mod log
+async fn receive_delete_action(
+ object: &Url,
+ actor: &Url,
+ ws_messages: WebsocketMessages,
+ deleted: bool,
+ context: &LemmyContext,
+ request_counter: &mut i32,
+) -> Result<(), LemmyError> {
+ match DeletableObjects::read_from_db(object, context).await? {
+ DeletableObjects::Community(community) => {
+ if community.local {
+ let mod_ = get_or_fetch_and_upsert_person(actor, context, request_counter).await?;
+ let object = community.actor_id();
+ send_apub_delete(&mod_, &community.clone(), object, true, context).await?;
+ }
+
+ let community = blocking(context.pool(), move |conn| {
+ Community::update_deleted(conn, community.id, deleted)
+ })
+ .await??;
+ send_community_ws_message(community.id, ws_messages.community, None, None, context).await?;
+ }
+ DeletableObjects::Post(post) => {
+ let deleted_post = blocking(context.pool(), move |conn| {
+ Post::update_deleted(conn, post.id, deleted)
+ })
+ .await??;
+ send_post_ws_message(deleted_post.id, ws_messages.post, None, None, context).await?;
+ }
+ DeletableObjects::Comment(comment) => {
+ let deleted_comment = blocking(context.pool(), move |conn| {
+ Comment::update_deleted(conn, comment.id, deleted)
+ })
+ .await??;
+ send_comment_ws_message_simple(deleted_comment.id, ws_messages.comment, context).await?;
+ }
+ }
+ Ok(())
+}
use crate::{
activities::{
- comment::send_websocket_message as send_comment_message,
- community::send_websocket_message as send_community_message,
- deletion::delete::DeletePostCommentOrCommunity,
- post::send_websocket_message as send_post_message,
+ community::announce::AnnouncableActivities,
+ deletion::{
+ delete::Delete,
+ receive_delete_action,
+ verify_delete_activity,
+ DeletableObjects,
+ WebsocketMessages,
+ },
+ generate_activity_id,
verify_activity,
- verify_mod_action,
- verify_person_in_community,
},
- fetcher::{
- community::get_or_fetch_and_upsert_community,
- objects::get_or_fetch_and_insert_post_or_comment,
- person::get_or_fetch_and_upsert_person,
- },
- CommunityType,
- PostOrComment,
+ activity_queue::send_to_community_new,
+ extensions::context::lemmy_context,
+ ActorType,
};
-use activitystreams::activity::kind::UndoType;
+use activitystreams::activity::kind::{DeleteType, UndoType};
+use anyhow::anyhow;
use lemmy_api_common::blocking;
-use lemmy_apub_lib::{values::PublicUrl, verify_urls_match, ActivityCommonFields, ActivityHandler};
+use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
use lemmy_db_queries::source::{comment::Comment_, community::Community_, post::Post_};
-use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
+use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post};
use lemmy_utils::LemmyError;
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::{
+ send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
+ LemmyContext,
+ UserOperationCrud,
+};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
-pub struct UndoDeletePostCommentOrCommunity {
+pub struct UndoDelete {
to: PublicUrl,
- object: DeletePostCommentOrCommunity,
+ object: Delete,
cc: [Url; 1],
#[serde(rename = "type")]
kind: UndoType,
}
#[async_trait::async_trait(?Send)]
-impl ActivityHandler for UndoDeletePostCommentOrCommunity {
+impl ActivityHandler for UndoDelete {
async fn verify(
&self,
context: &LemmyContext,
) -> Result<(), LemmyError> {
verify_activity(self.common())?;
self.object.verify(context, request_counter).await?;
- let object_community =
- get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await;
- // restoring a community
- if object_community.is_ok() {
- verify_mod_action(&self.common.actor, self.object.object.clone(), context).await?;
- }
- // restoring a post or comment
- else {
- verify_person_in_community(&self.common().actor, &self.cc[0], context, request_counter)
- .await?;
- verify_urls_match(&self.common.actor, &self.object.common().actor)?;
- }
+ verify_delete_activity(
+ &self.object.object,
+ &self.cc[0],
+ &self.common,
+ self.object.summary.is_some(),
+ context,
+ request_counter,
+ )
+ .await?;
Ok(())
}
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- let object_community =
- get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await;
- // restoring a community
- if let Ok(community) = object_community {
- if community.local {
- // repeat these checks just to be sure
- verify_person_in_community(&self.common().actor, &self.cc[0], context, request_counter)
- .await?;
- verify_mod_action(&self.common.actor, self.object.object.clone(), context).await?;
- let mod_ =
- get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?;
- community.send_undo_delete(mod_, context).await?;
- }
- let deleted_community = blocking(context.pool(), move |conn| {
- Community::update_deleted(conn, community.id, false)
- })
- .await??;
-
- send_community_message(
- deleted_community.id,
- UserOperationCrud::EditCommunity,
+ if self.object.summary.is_some() {
+ UndoDelete::receive_undo_remove_action(&self.object.object, context).await
+ } else {
+ receive_delete_action(
+ &self.object.object,
+ &self.common.actor,
+ WebsocketMessages {
+ community: UserOperationCrud::EditCommunity,
+ post: UserOperationCrud::EditPost,
+ comment: UserOperationCrud::EditComment,
+ },
+ false,
context,
+ request_counter,
)
.await
}
- // restoring a post or comment
- else {
- match get_or_fetch_and_insert_post_or_comment(&self.object.object, context, request_counter)
- .await?
- {
- PostOrComment::Post(post) => {
- let deleted_post = blocking(context.pool(), move |conn| {
- Post::update_deleted(conn, post.id, false)
- })
- .await??;
- send_post_message(deleted_post.id, UserOperationCrud::EditPost, context).await
- }
- PostOrComment::Comment(comment) => {
- let deleted_comment = blocking(context.pool(), move |conn| {
- Comment::update_deleted(conn, comment.id, false)
- })
- .await??;
- send_comment_message(
- deleted_comment.id,
- vec![],
- UserOperationCrud::EditComment,
- context,
- )
- .await
- }
- }
- }
}
fn common(&self) -> &ActivityCommonFields {
&self.common
}
}
+
+impl UndoDelete {
+ pub(in crate::activities::deletion) async fn send(
+ actor: &Person,
+ community: &Community,
+ object_id: Url,
+ summary: Option<String>,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let delete = Delete {
+ to: PublicUrl::Public,
+ object: object_id,
+ cc: [community.actor_id()],
+ kind: DeleteType::Delete,
+ summary,
+ common: ActivityCommonFields {
+ context: lemmy_context(),
+ id: generate_activity_id(DeleteType::Delete)?,
+ actor: actor.actor_id(),
+ unparsed: Default::default(),
+ },
+ };
+
+ let id = generate_activity_id(UndoType::Undo)?;
+ let undo = UndoDelete {
+ to: PublicUrl::Public,
+ object: delete,
+ cc: [community.actor_id()],
+ kind: UndoType::Undo,
+ common: ActivityCommonFields {
+ context: lemmy_context(),
+ id: id.clone(),
+ actor: actor.actor_id(),
+ unparsed: Default::default(),
+ },
+ };
+
+ let activity = AnnouncableActivities::UndoDelete(undo);
+ send_to_community_new(activity, &id, actor, community, vec![], context).await
+ }
+
+ pub(in crate::activities) async fn receive_undo_remove_action(
+ object: &Url,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ use UserOperationCrud::*;
+ match DeletableObjects::read_from_db(object, context).await? {
+ DeletableObjects::Community(community) => {
+ if community.local {
+ return Err(anyhow!("Only local admin can restore community").into());
+ }
+ let deleted_community = blocking(context.pool(), move |conn| {
+ Community::update_removed(conn, community.id, false)
+ })
+ .await??;
+ send_community_ws_message(deleted_community.id, EditCommunity, None, None, context).await?;
+ }
+ DeletableObjects::Post(post) => {
+ let removed_post = blocking(context.pool(), move |conn| {
+ Post::update_removed(conn, post.id, false)
+ })
+ .await??;
+ send_post_ws_message(removed_post.id, EditPost, None, None, context).await?;
+ }
+ DeletableObjects::Comment(comment) => {
+ let removed_comment = blocking(context.pool(), move |conn| {
+ Comment::update_removed(conn, comment.id, false)
+ })
+ .await??;
+ send_comment_ws_message_simple(removed_comment.id, EditComment, context).await?;
+ }
+ }
+ Ok(())
+ }
+}
community::announce::AnnouncableActivities,
extract_community,
generate_activity_id,
- post::send_websocket_message,
verify_activity,
verify_mod_action,
verify_person_in_community,
use lemmy_db_queries::Crud;
use lemmy_db_schema::source::{community::Community, person::Person, post::Post};
use lemmy_utils::LemmyError;
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
CreateOrUpdateType::Create => UserOperationCrud::CreatePost,
CreateOrUpdateType::Update => UserOperationCrud::EditPost,
};
- send_websocket_message(post.id, notif_type, context).await
+ send_post_ws_message(post.id, notif_type, None, None, context).await?;
+ Ok(())
}
fn common(&self) -> &ActivityCommonFields {
-use lemmy_api_common::{blocking, post::PostResponse};
-use lemmy_db_schema::PostId;
-use lemmy_db_views::post_view::PostView;
-use lemmy_utils::LemmyError;
-use lemmy_websocket::{messages::SendPost, LemmyContext};
-
pub mod create_or_update;
-
-pub(crate) async fn send_websocket_message<
- OP: ToString + Send + lemmy_websocket::OperationType + 'static,
->(
- post_id: PostId,
- op: OP,
- context: &LemmyContext,
-) -> Result<(), LemmyError> {
- let post_view = blocking(context.pool(), move |conn| {
- PostView::read(conn, post_id, None)
- })
- .await??;
-
- let res = PostResponse { post_view };
-
- context.chat_server().do_send(SendPost {
- op,
- post: res,
- websocket_id: None,
- });
-
- Ok(())
-}
use crate::{
- activities::{
- generate_activity_id,
- private_message::send_websocket_message,
- verify_activity,
- verify_person,
- CreateOrUpdateType,
- },
+ activities::{generate_activity_id, verify_activity, verify_person, CreateOrUpdateType},
activity_queue::send_activity_new,
extensions::context::lemmy_context,
objects::{private_message::Note, FromApub, ToApub},
use lemmy_db_queries::Crud;
use lemmy_db_schema::source::{person::Person, private_message::PrivateMessage};
use lemmy_utils::LemmyError;
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
CreateOrUpdateType::Create => UserOperationCrud::CreatePrivateMessage,
CreateOrUpdateType::Update => UserOperationCrud::EditPrivateMessage,
};
- send_websocket_message(private_message.id, notif_type, context).await?;
+ send_pm_ws_message(private_message.id, notif_type, None, context).await?;
Ok(())
}
use crate::{
- activities::{
- generate_activity_id,
- private_message::send_websocket_message,
- verify_activity,
- verify_person,
- },
+ activities::{generate_activity_id, verify_activity, verify_person},
activity_queue::send_activity_new,
extensions::context::lemmy_context,
ActorType,
use lemmy_db_queries::{source::private_message::PrivateMessage_, ApubObject, Crud};
use lemmy_db_schema::source::{person::Person, private_message::PrivateMessage};
use lemmy_utils::LemmyError;
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
})
.await??;
- send_websocket_message(
+ send_pm_ws_message(
deleted_private_message.id,
UserOperationCrud::DeletePrivateMessage,
+ None,
context,
)
.await?;
-use lemmy_api_common::{blocking, person::PrivateMessageResponse};
-use lemmy_db_schema::PrivateMessageId;
-use lemmy_db_views::{local_user_view::LocalUserView, private_message_view::PrivateMessageView};
-use lemmy_utils::LemmyError;
-use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperationCrud};
-
pub mod create_or_update;
pub mod delete;
pub mod undo_delete;
-
-async fn send_websocket_message(
- private_message_id: PrivateMessageId,
- op: UserOperationCrud,
- context: &LemmyContext,
-) -> Result<(), LemmyError> {
- let message = blocking(context.pool(), move |conn| {
- PrivateMessageView::read(conn, private_message_id)
- })
- .await??;
- let res = PrivateMessageResponse {
- private_message_view: message,
- };
-
- // Send notifications to the local recipient, if one exists
- let recipient_id = res.private_message_view.recipient.id;
- let local_recipient_id = blocking(context.pool(), move |conn| {
- LocalUserView::read_person(conn, recipient_id)
- })
- .await??
- .local_user
- .id;
-
- context.chat_server().do_send(SendUserRoomMessage {
- op,
- response: res,
- local_recipient_id,
- websocket_id: None,
- });
-
- Ok(())
-}
use crate::{
activities::{
generate_activity_id,
- private_message::{delete::DeletePrivateMessage, send_websocket_message},
+ private_message::delete::DeletePrivateMessage,
verify_activity,
verify_person,
},
use lemmy_db_queries::{source::private_message::PrivateMessage_, ApubObject, Crud};
use lemmy_db_schema::source::{person::Person, private_message::PrivateMessage};
use lemmy_utils::LemmyError;
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
})
.await??;
- send_websocket_message(
+ send_pm_ws_message(
deleted_private_message.id,
UserOperationCrud::EditPrivateMessage,
+ None,
context,
)
.await?;
use crate::{
activities::{
- comment::send_websocket_message as send_comment_message,
- community::send_websocket_message as send_community_message,
- post::send_websocket_message as send_post_message,
+ deletion::{delete::receive_remove_action, verify_delete_activity},
verify_activity,
verify_add_remove_moderator_target,
verify_mod_action,
verify_person_in_community,
},
- fetcher::{
- community::get_or_fetch_and_upsert_community,
- objects::get_or_fetch_and_insert_post_or_comment,
- person::get_or_fetch_and_upsert_person,
- },
+ fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
CommunityType,
- PostOrComment,
};
use activitystreams::{activity::kind::RemoveType, base::AnyBase};
-use anyhow::anyhow;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
-use lemmy_db_queries::{
- source::{comment::Comment_, community::Community_, post::Post_},
- Joinable,
-};
-use lemmy_db_schema::source::{
- comment::Comment,
- community::{Community, CommunityModerator, CommunityModeratorForm},
- post::Post,
-};
+use lemmy_db_queries::Joinable;
+use lemmy_db_schema::source::community::{CommunityModerator, CommunityModeratorForm};
use lemmy_utils::LemmyError;
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::LemmyContext;
use url::Url;
-// TODO: we can probably deduplicate a bunch of code between this and DeletePostCommentOrCommunity
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
-pub struct RemovePostCommentCommunityOrMod {
+pub struct RemoveMod {
to: PublicUrl,
pub(in crate::activities::removal) object: Url,
cc: [Url; 1],
#[serde(rename = "type")]
kind: RemoveType,
// if target is set, this is means remove mod from community
- target: Option<Url>,
+ pub(in crate::activities::removal) target: Option<Url>,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
-impl ActivityHandler for RemovePostCommentCommunityOrMod {
+impl ActivityHandler for RemoveMod {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self.common())?;
- let object_community =
- get_or_fetch_and_upsert_community(&self.object, context, request_counter).await;
- // removing a community
- if object_community.is_ok() {
- verify_mod_action(&self.common.actor, self.object.clone(), context).await?;
- }
- // removing community mod
- else if let Some(target) = &self.target {
+ if let Some(target) = &self.target {
verify_person_in_community(&self.common.actor, &self.cc[0], context, request_counter).await?;
verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?;
verify_add_remove_moderator_target(target, self.cc[0].clone())?;
- }
- // removing a post or comment
- else {
- verify_person_in_community(&self.common.actor, &self.cc[0], context, request_counter).await?;
- verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?;
+ } else {
+ verify_delete_activity(
+ &self.object,
+ &self.cc[0],
+ self.common(),
+ true,
+ context,
+ request_counter,
+ )
+ .await?;
}
Ok(())
}
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- let object_community =
- get_or_fetch_and_upsert_community(&self.object, context, request_counter).await;
- // removing a community
- if let Ok(community) = object_community {
- if community.local {
- return Err(anyhow!("Only local admin can remove community").into());
- }
- let deleted_community = blocking(context.pool(), move |conn| {
- Community::update_removed(conn, community.id, true)
- })
- .await??;
-
- send_community_message(
- deleted_community.id,
- UserOperationCrud::RemoveCommunity,
- context,
- )
- .await
- }
- // removing community mod
- else if self.target.is_some() {
+ if self.target.is_some() {
let community =
get_or_fetch_and_upsert_community(&self.cc[0], context, request_counter).await?;
let remove_mod =
.await?;
// TODO: send websocket notification about removed mod
Ok(())
- }
- // removing a post or comment
- else {
- match get_or_fetch_and_insert_post_or_comment(&self.object, context, request_counter).await? {
- PostOrComment::Post(post) => {
- let removed_post = blocking(context.pool(), move |conn| {
- Post::update_removed(conn, post.id, true)
- })
- .await??;
- send_post_message(removed_post.id, UserOperationCrud::EditPost, context).await
- }
- PostOrComment::Comment(comment) => {
- let removed_comment = blocking(context.pool(), move |conn| {
- Comment::update_removed(conn, comment.id, true)
- })
- .await??;
- send_comment_message(
- removed_comment.id,
- vec![],
- UserOperationCrud::EditComment,
- context,
- )
- .await
- }
- }
+ } else {
+ receive_remove_action(
+ &self.common.actor,
+ &self.object,
+ None,
+ context,
+ request_counter,
+ )
+ .await
}
}
-use crate::{
- activities::{
- comment::send_websocket_message as send_comment_message,
- community::send_websocket_message as send_community_message,
- post::send_websocket_message as send_post_message,
- removal::remove::RemovePostCommentCommunityOrMod,
- verify_activity,
- verify_mod_action,
- verify_person_in_community,
- },
- fetcher::{
- community::get_or_fetch_and_upsert_community,
- objects::get_or_fetch_and_insert_post_or_comment,
- },
- PostOrComment,
+use crate::activities::{
+ deletion::{undo_delete::UndoDelete, verify_delete_activity},
+ removal::remove::RemoveMod,
+ verify_activity,
};
use activitystreams::activity::kind::UndoType;
-use anyhow::anyhow;
-use lemmy_api_common::blocking;
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
-use lemmy_db_queries::source::{comment::Comment_, community::Community_, post::Post_};
-use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
use lemmy_utils::LemmyError;
-use lemmy_websocket::{LemmyContext, UserOperationCrud};
+use lemmy_websocket::LemmyContext;
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoRemovePostCommentOrCommunity {
to: PublicUrl,
- object: RemovePostCommentCommunityOrMod,
+ // Note, there is no such thing as Undo/Remove/Mod, so we ignore that
+ object: RemoveMod,
cc: [Url; 1],
#[serde(rename = "type")]
kind: UndoType,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self.common())?;
- let object_community =
- get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await;
- // removing a community
- if object_community.is_ok() {
- verify_mod_action(&self.common.actor, self.object.object.clone(), context).await?;
- }
- // removing a post or comment
- else {
- verify_person_in_community(&self.common.actor, &self.cc[0], context, request_counter).await?;
- verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?;
- }
self.object.verify(context, request_counter).await?;
- // dont check that actor and object.actor are identical, so that one mod can
- // undo the action of another
+
+ verify_delete_activity(
+ &self.object.object,
+ &self.cc[0],
+ self.common(),
+ true,
+ context,
+ request_counter,
+ )
+ .await?;
Ok(())
}
async fn receive(
self,
context: &LemmyContext,
- request_counter: &mut i32,
+ _request_counter: &mut i32,
) -> Result<(), LemmyError> {
- let object_community =
- get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await;
- // restoring a community
- if let Ok(community) = object_community {
- if community.local {
- return Err(anyhow!("Only local admin can undo remove community").into());
- }
- let deleted_community = blocking(context.pool(), move |conn| {
- Community::update_removed(conn, community.id, false)
- })
- .await??;
-
- send_community_message(
- deleted_community.id,
- UserOperationCrud::EditCommunity,
- context,
- )
- .await
- }
- // restoring a post or comment
- else {
- match get_or_fetch_and_insert_post_or_comment(&self.object.object, context, request_counter)
- .await?
- {
- PostOrComment::Post(post) => {
- let removed_post = blocking(context.pool(), move |conn| {
- Post::update_removed(conn, post.id, false)
- })
- .await??;
- send_post_message(removed_post.id, UserOperationCrud::EditPost, context).await
- }
- PostOrComment::Comment(comment) => {
- let removed_comment = blocking(context.pool(), move |conn| {
- Comment::update_removed(conn, comment.id, false)
- })
- .await??;
- send_comment_message(
- removed_comment.id,
- vec![],
- UserOperationCrud::EditComment,
- context,
- )
- .await
- }
- }
- }
+ UndoDelete::receive_undo_remove_action(&self.object.object, context).await
}
fn common(&self) -> &ActivityCommonFields {
+++ /dev/null
-use crate::{
- activities::generate_activity_id,
- activity_queue::send_to_community,
- extensions::context::lemmy_context,
- ActorType,
- ApubObjectType,
-};
-use activitystreams::{
- activity::{
- kind::{DeleteType, RemoveType, UndoType},
- Delete,
- Remove,
- Undo,
- },
- prelude::*,
- public,
-};
-use lemmy_api_common::blocking;
-use lemmy_db_queries::Crud;
-use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post};
-use lemmy_utils::LemmyError;
-use lemmy_websocket::LemmyContext;
-
-#[async_trait::async_trait(?Send)]
-impl ApubObjectType for Comment {
- async fn send_delete(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> {
- let post_id = self.post_id;
- let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
-
- let community_id = post.community_id;
- let community = blocking(context.pool(), move |conn| {
- Community::read(conn, community_id)
- })
- .await??;
-
- let mut delete = Delete::new(
- creator.actor_id.to_owned().into_inner(),
- self.ap_id.to_owned().into_inner(),
- );
- delete
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(DeleteType::Delete)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- send_to_community(delete, creator, &community, None, context).await?;
- Ok(())
- }
-
- async fn send_undo_delete(
- &self,
- creator: &Person,
- context: &LemmyContext,
- ) -> Result<(), LemmyError> {
- let post_id = self.post_id;
- let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
-
- let community_id = post.community_id;
- let community = blocking(context.pool(), move |conn| {
- Community::read(conn, community_id)
- })
- .await??;
-
- // Generate a fake delete activity, with the correct object
- let mut delete = Delete::new(
- creator.actor_id.to_owned().into_inner(),
- self.ap_id.to_owned().into_inner(),
- );
- delete
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(DeleteType::Delete)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- // Undo that fake activity
- let mut undo = Undo::new(
- creator.actor_id.to_owned().into_inner(),
- delete.into_any_base()?,
- );
- undo
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(UndoType::Undo)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- send_to_community(undo, creator, &community, None, context).await?;
- Ok(())
- }
-
- async fn send_remove(&self, mod_: &Person, context: &LemmyContext) -> Result<(), LemmyError> {
- let post_id = self.post_id;
- let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
-
- let community_id = post.community_id;
- let community = blocking(context.pool(), move |conn| {
- Community::read(conn, community_id)
- })
- .await??;
-
- let mut remove = Remove::new(
- mod_.actor_id.to_owned().into_inner(),
- self.ap_id.to_owned().into_inner(),
- );
- remove
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(RemoveType::Remove)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- send_to_community(remove, mod_, &community, None, context).await?;
- Ok(())
- }
-
- async fn send_undo_remove(
- &self,
- mod_: &Person,
- context: &LemmyContext,
- ) -> Result<(), LemmyError> {
- let post_id = self.post_id;
- let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
-
- let community_id = post.community_id;
- let community = blocking(context.pool(), move |conn| {
- Community::read(conn, community_id)
- })
- .await??;
-
- // Generate a fake delete activity, with the correct object
- let mut remove = Remove::new(
- mod_.actor_id.to_owned().into_inner(),
- self.ap_id.to_owned().into_inner(),
- );
- remove
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(RemoveType::Remove)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- // Undo that fake activity
- let mut undo = Undo::new(
- mod_.actor_id.to_owned().into_inner(),
- remove.into_any_base()?,
- );
- undo
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(UndoType::Undo)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- send_to_community(undo, mod_, &community, None, context).await?;
- Ok(())
- }
-}
};
use activitystreams::{
activity::{
- kind::{
- AddType,
- AnnounceType,
- BlockType,
- DeleteType,
- LikeType,
- RemoveType,
- UndoType,
- UpdateType,
- },
+ kind::{AddType, AnnounceType, BlockType, RemoveType, UndoType, UpdateType},
Add,
Announce,
Block,
- Delete,
OptTargetRefExt,
Remove,
Undo,
Ok(())
}
- /// If the creator of a community deletes the community, send this to all followers.
- ///
- /// We need to handle deletion by a remote mod separately.
- async fn send_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> {
- // Local mod, send directly from community to followers
- if self.local {
- let mut delete = Delete::new(self.actor_id(), self.actor_id());
- delete
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(DeleteType::Delete)?)
- .set_to(public())
- .set_many_ccs(vec![self.followers_url()]);
-
- send_to_community_followers(delete, self, None, context).await?;
- }
- // Remote mod, send from mod to community
- else {
- let mut delete = Delete::new(mod_.actor_id(), self.actor_id());
- delete
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(DeleteType::Delete)?)
- .set_to(public())
- .set_many_ccs(vec![self.actor_id()]);
-
- send_to_community(delete, &mod_, self, None, context).await?;
- }
- Ok(())
- }
-
- /// If the creator of a community reverts the deletion of a community, send this to all followers.
- ///
- /// We need to handle undelete by a remote mod separately.
- async fn send_undo_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> {
- // Local mod, send directly from community to followers
- if self.local {
- let mut delete = Delete::new(self.actor_id(), self.actor_id());
- delete
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(DeleteType::Delete)?)
- .set_to(public())
- .set_many_ccs(vec![self.followers_url()]);
-
- let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?);
- undo
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(UndoType::Undo)?)
- .set_to(public())
- .set_many_ccs(vec![self.followers_url()]);
-
- send_to_community_followers(undo, self, None, context).await?;
- }
- // Remote mod, send from mod to community
- else {
- let mut delete = Delete::new(mod_.actor_id(), self.actor_id());
- delete
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(DeleteType::Delete)?)
- .set_to(public())
- .set_many_ccs(vec![self.actor_id()]);
-
- let mut undo = Undo::new(mod_.actor_id(), delete.into_any_base()?);
- undo
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(UndoType::Undo)?)
- .set_to(public())
- .set_many_ccs(vec![self.actor_id()]);
-
- send_to_community(undo, &mod_, self, None, context).await?;
- }
- Ok(())
- }
-
- /// If an admin removes a community, send this to all followers.
- async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
- let mut remove = Remove::new(self.actor_id(), self.actor_id());
- remove
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(RemoveType::Remove)?)
- .set_to(public())
- .set_many_ccs(vec![self.followers_url()]);
-
- send_to_community_followers(remove, self, None, context).await?;
- Ok(())
- }
-
- /// If an admin reverts the removal of a community, send this to all followers.
- async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
- let mut remove = Remove::new(self.actor_id(), self.actor_id());
- remove
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(RemoveType::Remove)?)
- .set_to(public())
- .set_many_ccs(vec![self.followers_url()]);
-
- // Undo that fake activity
- let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?);
- undo
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(LikeType::Like)?)
- .set_to(public())
- .set_many_ccs(vec![self.followers_url()]);
-
- send_to_community_followers(undo, self, None, context).await?;
- Ok(())
- }
-
/// Wraps an activity sent to the community in an announce, and then sends the announce to all
/// community followers.
///
-pub(crate) mod comment;
pub(crate) mod community;
pub(crate) mod person;
-pub(crate) mod post;
+++ /dev/null
-use crate::{
- activities::generate_activity_id,
- activity_queue::send_to_community,
- extensions::context::lemmy_context,
- ActorType,
- ApubObjectType,
-};
-use activitystreams::{
- activity::{
- kind::{DeleteType, RemoveType, UndoType},
- Delete,
- Remove,
- Undo,
- },
- prelude::*,
- public,
-};
-use lemmy_api_common::blocking;
-use lemmy_db_queries::Crud;
-use lemmy_db_schema::source::{community::Community, person::Person, post::Post};
-use lemmy_utils::LemmyError;
-use lemmy_websocket::LemmyContext;
-
-#[async_trait::async_trait(?Send)]
-impl ApubObjectType for Post {
- async fn send_delete(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> {
- let community_id = self.community_id;
- let community = blocking(context.pool(), move |conn| {
- Community::read(conn, community_id)
- })
- .await??;
-
- let mut delete = Delete::new(
- creator.actor_id.to_owned().into_inner(),
- self.ap_id.to_owned().into_inner(),
- );
- delete
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(DeleteType::Delete)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- send_to_community(delete, creator, &community, None, context).await?;
- Ok(())
- }
-
- async fn send_undo_delete(
- &self,
- creator: &Person,
- context: &LemmyContext,
- ) -> Result<(), LemmyError> {
- let community_id = self.community_id;
- let community = blocking(context.pool(), move |conn| {
- Community::read(conn, community_id)
- })
- .await??;
-
- let mut delete = Delete::new(
- creator.actor_id.to_owned().into_inner(),
- self.ap_id.to_owned().into_inner(),
- );
- delete
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(DeleteType::Delete)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- // Undo that fake activity
- let mut undo = Undo::new(
- creator.actor_id.to_owned().into_inner(),
- delete.into_any_base()?,
- );
- undo
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(UndoType::Undo)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- send_to_community(undo, creator, &community, None, context).await?;
- Ok(())
- }
-
- async fn send_remove(&self, mod_: &Person, context: &LemmyContext) -> Result<(), LemmyError> {
- let community_id = self.community_id;
- let community = blocking(context.pool(), move |conn| {
- Community::read(conn, community_id)
- })
- .await??;
-
- let mut remove = Remove::new(
- mod_.actor_id.to_owned().into_inner(),
- self.ap_id.to_owned().into_inner(),
- );
- remove
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(RemoveType::Remove)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- send_to_community(remove, mod_, &community, None, context).await?;
- Ok(())
- }
-
- async fn send_undo_remove(
- &self,
- mod_: &Person,
- context: &LemmyContext,
- ) -> Result<(), LemmyError> {
- let community_id = self.community_id;
- let community = blocking(context.pool(), move |conn| {
- Community::read(conn, community_id)
- })
- .await??;
-
- let mut remove = Remove::new(
- mod_.actor_id.to_owned().into_inner(),
- self.ap_id.to_owned().into_inner(),
- );
- remove
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(RemoveType::Remove)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- // Undo that fake activity
- let mut undo = Undo::new(
- mod_.actor_id.to_owned().into_inner(),
- remove.into_any_base()?,
- );
- undo
- .set_many_contexts(lemmy_context())
- .set_id(generate_activity_id(UndoType::Undo)?)
- .set_to(public())
- .set_many_ccs(vec![community.actor_id()]);
-
- send_to_community(undo, mod_, &community, None, context).await?;
- Ok(())
- }
-}
-use crate::activities::{
- comment::send_websocket_message as send_comment_message,
- post::send_websocket_message as send_post_message,
- voting::vote::VoteType,
-};
+use crate::activities::voting::vote::VoteType;
use lemmy_api_common::blocking;
use lemmy_db_queries::Likeable;
use lemmy_db_schema::source::{
post::{Post, PostLike, PostLikeForm},
};
use lemmy_utils::LemmyError;
-use lemmy_websocket::{LemmyContext, UserOperation};
+use lemmy_websocket::{
+ send::{send_comment_ws_message_simple, send_post_ws_message},
+ LemmyContext,
+ UserOperation,
+};
pub mod undo_vote;
pub mod vote;
})
.await??;
- send_comment_message(
- comment_id,
- vec![],
- UserOperation::CreateCommentLike,
- context,
- )
- .await
+ send_comment_ws_message_simple(comment_id, UserOperation::CreateCommentLike, context).await?;
+ Ok(())
}
async fn vote_post(
})
.await??;
- send_post_message(post.id, UserOperation::CreatePostLike, context).await
+ send_post_ws_message(post.id, UserOperation::CreatePostLike, None, None, context).await?;
+ Ok(())
}
async fn undo_vote_comment(
})
.await??;
- send_comment_message(
- comment.id,
- vec![],
- UserOperation::CreateCommentLike,
- context,
- )
- .await
+ send_comment_ws_message_simple(comment_id, UserOperation::CreateCommentLike, context).await?;
+ Ok(())
}
async fn undo_vote_post(
PostLike::remove(conn, person_id, post_id)
})
.await??;
- send_post_message(post.id, UserOperation::CreatePostLike, context).await
+
+ send_post_ws_message(post_id, UserOperation::CreatePostLike, None, None, context).await?;
+ Ok(())
}
use serde_json::json;
use url::Url;
-pub fn lemmy_context() -> OneOrMany<AnyBase> {
+pub(crate) fn lemmy_context() -> OneOrMany<AnyBase> {
let context_ext = AnyBase::from_arbitrary_json(json!(
{
"sc": "http://schema.org#",
}
/// Verifies the HTTP signature on an incoming inbox request.
-pub fn verify_signature(request: &HttpRequest, public_key: &str) -> Result<(), LemmyError> {
+pub(crate) fn verify_signature(request: &HttpRequest, public_key: &str) -> Result<(), LemmyError> {
let verified = CONFIG2
.begin_verify(
request.method(),
///
/// If it exists locally and `!should_refetch_actor()`, it is returned directly from the database.
/// Otherwise it is fetched from the remote instance, stored and returned.
-pub async fn get_or_fetch_and_upsert_community(
+pub(crate) async fn get_or_fetch_and_upsert_community(
apub_id: &Url,
context: &LemmyContext,
recursion_counter: &mut i32,
///
/// If it exists locally and `!should_refetch_actor()`, it is returned directly from the database.
/// Otherwise it is fetched from the remote instance, stored and returned.
-pub async fn get_or_fetch_and_upsert_actor(
+pub(crate) async fn get_or_fetch_and_upsert_actor(
apub_id: &Url,
context: &LemmyContext,
recursion_counter: &mut i32,
/// pulled from its apub ID, inserted and returned.
///
/// The parent community is also pulled if necessary. Comments are not pulled.
-pub async fn get_or_fetch_and_insert_post(
+pub(crate) async fn get_or_fetch_and_insert_post(
post_ap_id: &Url,
context: &LemmyContext,
recursion_counter: &mut i32,
/// pulled from its apub ID, inserted and returned.
///
/// The parent community, post and comment are also pulled if necessary.
-pub async fn get_or_fetch_and_insert_comment(
+pub(crate) async fn get_or_fetch_and_insert_comment(
comment_ap_id: &Url,
context: &LemmyContext,
recursion_counter: &mut i32,
}
}
-pub async fn get_or_fetch_and_insert_post_or_comment(
+pub(crate) async fn get_or_fetch_and_insert_post_or_comment(
ap_id: &Url,
context: &LemmyContext,
recursion_counter: &mut i32,
///
/// If it exists locally and `!should_refetch_actor()`, it is returned directly from the database.
/// Otherwise it is fetched from the remote instance, stored and returned.
-pub async fn get_or_fetch_and_upsert_person(
+pub(crate) async fn get_or_fetch_and_upsert_person(
apub_id: &Url,
context: &LemmyContext,
recursion_counter: &mut i32,
undo_block_user::UndoBlockUserFromCommunity,
update::UpdateCommunity,
},
- deletion::{delete::DeletePostCommentOrCommunity, undo_delete::UndoDeletePostCommentOrCommunity},
+ deletion::{delete::Delete, undo_delete::UndoDelete},
following::{accept::AcceptFollowCommunity, follow::FollowCommunity, undo::UndoFollowCommunity},
post::create_or_update::CreateOrUpdatePost,
private_message::{
delete::DeletePrivateMessage,
undo_delete::UndoDeletePrivateMessage,
},
- removal::{
- remove::RemovePostCommentCommunityOrMod,
- undo_remove::UndoRemovePostCommentOrCommunity,
- },
+ removal::{remove::RemoveMod, undo_remove::UndoRemovePostCommentOrCommunity},
voting::{undo_vote::UndoVote, vote::Vote},
};
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler};
CreateOrUpdatePost(Box<CreateOrUpdatePost>),
Vote(Vote),
UndoVote(UndoVote),
- DeletePostCommentOrCommunity(DeletePostCommentOrCommunity),
- UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity),
- RemovePostCommentOrCommunity(RemovePostCommentCommunityOrMod),
+ DeletePostCommentOrCommunity(Delete),
+ UndoDeletePostCommentOrCommunity(UndoDelete),
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
UpdateCommunity(Box<UpdateCommunity>),
BlockUserFromCommunity(BlockUserFromCommunity),
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
AddMod(AddMod),
+ RemoveMod(RemoveMod),
}
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
CreateOrUpdatePost(Box<CreateOrUpdatePost>),
Vote(Vote),
UndoVote(UndoVote),
- DeletePostCommentOrCommunity(DeletePostCommentOrCommunity),
- UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity),
- RemovePostCommentOrCommunity(RemovePostCommentCommunityOrMod),
+ Delete(Delete),
+ UndoDelete(UndoDelete),
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
UpdateCommunity(Box<UpdateCommunity>),
BlockUserFromCommunity(BlockUserFromCommunity),
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
AddMod(AddMod),
+ RemoveMod(RemoveMod),
// received by person
AcceptFollowCommunity(AcceptFollowCommunity),
// Note, pm activities need to be at the end, otherwise comments will end up here. We can probably
use std::net::IpAddr;
use url::{ParseError, Url};
-pub static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
+static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
/// Checks if the ID is allowed for sending or receiving.
///
Ok(())
}
-/// Common functions for ActivityPub objects, which are implemented by most (but not all) objects
-/// and actors in Lemmy.
-#[async_trait::async_trait(?Send)]
-pub trait ApubObjectType {
- async fn send_delete(&self, creator: &DbPerson, context: &LemmyContext)
- -> Result<(), LemmyError>;
- async fn send_undo_delete(
- &self,
- creator: &DbPerson,
- context: &LemmyContext,
- ) -> Result<(), LemmyError>;
- async fn send_remove(&self, mod_: &DbPerson, context: &LemmyContext) -> Result<(), LemmyError>;
- async fn send_undo_remove(
- &self,
- mod_: &DbPerson,
- context: &LemmyContext,
- ) -> Result<(), LemmyError>;
-}
-
/// Common methods provided by ActivityPub actors (community and person). Not all methods are
/// implemented by all actors.
-pub trait ActorType {
+trait ActorType {
fn is_local(&self) -> bool;
fn actor_id(&self) -> Url;
fn name(&self) -> String;
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError>;
async fn send_update(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError>;
- async fn send_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError>;
- async fn send_undo_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError>;
-
- async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError>;
- async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError>;
async fn send_announce(
&self,
}
/// Generates an apub endpoint for a given domain, IE xyz.tld
-pub(crate) fn generate_apub_endpoint_for_domain(
+fn generate_apub_endpoint_for_domain(
endpoint_type: EndpointType,
name: &str,
domain: &str,
Ok(Url::parse(&url)?.into())
}
-pub fn generate_moderators_url(community_id: &DbUrl) -> Result<DbUrl, LemmyError> {
+fn generate_moderators_url(community_id: &DbUrl) -> Result<DbUrl, LemmyError> {
Ok(Url::parse(&format!("{}/moderators", community_id))?.into())
}
/// Store a sent or received activity in the database, for logging purposes. These records are not
/// persistent.
-pub(crate) async fn insert_activity<T>(
+async fn insert_activity<T>(
ap_id: &Url,
activity: T,
local: bool,
}
#[derive(Debug)]
-pub enum Object {
+enum Object {
Comment(Box<Comment>),
Post(Box<Post>),
Community(Box<Community>),
PrivateMessage(Box<PrivateMessage>),
}
-pub(crate) async fn find_object_by_id(
- context: &LemmyContext,
- apub_id: Url,
-) -> Result<Object, LemmyError> {
+async fn find_object_by_id(context: &LemmyContext, apub_id: Url) -> Result<Object, LemmyError> {
let ap_id = apub_id.clone();
if let Ok(pc) = find_post_or_comment_by_id(context, ap_id.to_owned()).await {
return Ok(match pc {
Err(NotFound.into())
}
-pub(crate) async fn check_community_or_site_ban(
+async fn check_community_or_site_ban(
person: &Person,
community_id: CommunityId,
pool: &DbPool,
Old(Vec<Url>),
New(Url),
}
+
+// Another migration we are doing is to handle all deletions and removals using Delete activity.
+// This is because Remove is for removing an object from a collection, so using it that way doesn't
+// really make sense. It is also a problem because we have a RemoveMod activity, which was awkward
+// to handle together with removing posts etc.
+//
+// v0.11: send and receive mod removals as Remove
+// v0.12: receive removals as Remove, send as Delete (compatible with v0.11)
+// v0.13: send and receive mod removals as Delete (compatible with v0.12)
+//
+// For v0.13, delete [`UndoRemovePostCommentOrCommunity`], and don't handle object deletion in
+// [`RemoveMod`] handler.
/// Trait for converting an object or actor into the respective ActivityPub type.
#[async_trait::async_trait(?Send)]
-pub trait ToApub {
+pub(crate) trait ToApub {
type ApubType;
async fn to_apub(&self, pool: &DbPool) -> Result<Self::ApubType, LemmyError>;
fn to_tombstone(&self) -> Result<Tombstone, LemmyError>;
}
#[async_trait::async_trait(?Send)]
-pub trait FromApub {
+pub(crate) trait FromApub {
type ApubType;
/// Converts an object from ActivityPub type to Lemmy internal type.
///
pub type DbPool = diesel::r2d2::Pool<diesel::r2d2::ConnectionManager<diesel::PgConnection>>;
-pub trait Crud<Form, IdType> {
- fn create(conn: &PgConnection, form: &Form) -> Result<Self, Error>
+pub trait Crud {
+ type Form;
+ type IdType;
+ fn create(conn: &PgConnection, form: &Self::Form) -> Result<Self, Error>
where
Self: Sized;
- fn read(conn: &PgConnection, id: IdType) -> Result<Self, Error>
+ fn read(conn: &PgConnection, id: Self::IdType) -> Result<Self, Error>
where
Self: Sized;
- fn update(conn: &PgConnection, id: IdType, form: &Form) -> Result<Self, Error>
+ fn update(conn: &PgConnection, id: Self::IdType, form: &Self::Form) -> Result<Self, Error>
where
Self: Sized;
- fn delete(_conn: &PgConnection, _id: IdType) -> Result<usize, Error>
+ fn delete(_conn: &PgConnection, _id: Self::IdType) -> Result<usize, Error>
where
Self: Sized,
{
}
}
-pub trait Followable<Form> {
- fn follow(conn: &PgConnection, form: &Form) -> Result<Self, Error>
+pub trait Followable {
+ type Form;
+ fn follow(conn: &PgConnection, form: &Self::Form) -> Result<Self, Error>
where
Self: Sized;
fn follow_accepted(
) -> Result<Self, Error>
where
Self: Sized;
- fn unfollow(conn: &PgConnection, form: &Form) -> Result<usize, Error>
+ fn unfollow(conn: &PgConnection, form: &Self::Form) -> Result<usize, Error>
where
Self: Sized;
fn has_local_followers(conn: &PgConnection, community_id: CommunityId) -> Result<bool, Error>;
}
-pub trait Joinable<Form> {
- fn join(conn: &PgConnection, form: &Form) -> Result<Self, Error>
+pub trait Joinable {
+ type Form;
+ fn join(conn: &PgConnection, form: &Self::Form) -> Result<Self, Error>
where
Self: Sized;
- fn leave(conn: &PgConnection, form: &Form) -> Result<usize, Error>
+ fn leave(conn: &PgConnection, form: &Self::Form) -> Result<usize, Error>
where
Self: Sized;
}
-pub trait Likeable<Form, IdType> {
- fn like(conn: &PgConnection, form: &Form) -> Result<Self, Error>
+pub trait Likeable {
+ type Form;
+ type IdType;
+ fn like(conn: &PgConnection, form: &Self::Form) -> Result<Self, Error>
where
Self: Sized;
- fn remove(conn: &PgConnection, person_id: PersonId, item_id: IdType) -> Result<usize, Error>
+ fn remove(
+ conn: &PgConnection,
+ person_id: PersonId,
+ item_id: Self::IdType,
+ ) -> Result<usize, Error>
where
Self: Sized;
}
-pub trait Bannable<Form> {
- fn ban(conn: &PgConnection, form: &Form) -> Result<Self, Error>
+pub trait Bannable {
+ type Form;
+ fn ban(conn: &PgConnection, form: &Self::Form) -> Result<Self, Error>
where
Self: Sized;
- fn unban(conn: &PgConnection, form: &Form) -> Result<usize, Error>
+ fn unban(conn: &PgConnection, form: &Self::Form) -> Result<usize, Error>
where
Self: Sized;
}
-pub trait Saveable<Form> {
- fn save(conn: &PgConnection, form: &Form) -> Result<Self, Error>
+pub trait Saveable {
+ type Form;
+ fn save(conn: &PgConnection, form: &Self::Form) -> Result<Self, Error>
where
Self: Sized;
- fn unsave(conn: &PgConnection, form: &Form) -> Result<usize, Error>
+ fn unsave(conn: &PgConnection, form: &Self::Form) -> Result<usize, Error>
where
Self: Sized;
}
-pub trait Readable<Form> {
- fn mark_as_read(conn: &PgConnection, form: &Form) -> Result<Self, Error>
+pub trait Readable {
+ type Form;
+ fn mark_as_read(conn: &PgConnection, form: &Self::Form) -> Result<Self, Error>
where
Self: Sized;
- fn mark_as_unread(conn: &PgConnection, form: &Form) -> Result<usize, Error>
+ fn mark_as_unread(conn: &PgConnection, form: &Self::Form) -> Result<usize, Error>
where
Self: Sized;
}
-pub trait Reportable<Form> {
- fn report(conn: &PgConnection, form: &Form) -> Result<Self, Error>
+pub trait Reportable {
+ type Form;
+ fn report(conn: &PgConnection, form: &Self::Form) -> Result<Self, Error>
where
Self: Sized;
fn resolve(conn: &PgConnection, report_id: i32, resolver_id: PersonId) -> Result<usize, Error>
fn blank_out_deleted_or_removed_info(self) -> Self;
}
-pub trait ApubObject<Form> {
+pub trait ApubObject {
+ type Form;
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Self, Error>
where
Self: Sized;
- fn upsert(conn: &PgConnection, user_form: &Form) -> Result<Self, Error>
+ fn upsert(conn: &PgConnection, user_form: &Self::Form) -> Result<Self, Error>
where
Self: Sized;
}
io::{Error as IoError, ErrorKind},
};
-impl Crud<ActivityForm, i32> for Activity {
+impl Crud for Activity {
+ type Form = ActivityForm;
+ type IdType = i32;
fn read(conn: &PgConnection, activity_id: i32) -> Result<Self, Error> {
use lemmy_db_schema::schema::activity::dsl::*;
activity.find(activity_id).first::<Self>(conn)
}
}
-impl Crud<CommentForm, CommentId> for Comment {
+impl Crud for Comment {
+ type Form = CommentForm;
+ type IdType = CommentId;
fn read(conn: &PgConnection, comment_id: CommentId) -> Result<Self, Error> {
use lemmy_db_schema::schema::comment::dsl::*;
comment.find(comment_id).first::<Self>(conn)
}
}
-impl ApubObject<CommentForm> for Comment {
+impl ApubObject for Comment {
+ type Form = CommentForm;
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Self, Error> {
use lemmy_db_schema::schema::comment::dsl::*;
comment.filter(ap_id.eq(object_id)).first::<Self>(conn)
}
}
-impl Likeable<CommentLikeForm, CommentId> for CommentLike {
+impl Likeable for CommentLike {
+ type Form = CommentLikeForm;
+ type IdType = CommentId;
fn like(conn: &PgConnection, comment_like_form: &CommentLikeForm) -> Result<Self, Error> {
use lemmy_db_schema::schema::comment_like::dsl::*;
insert_into(comment_like)
}
}
-impl Saveable<CommentSavedForm> for CommentSaved {
+impl Saveable for CommentSaved {
+ type Form = CommentSavedForm;
fn save(conn: &PgConnection, comment_saved_form: &CommentSavedForm) -> Result<Self, Error> {
use lemmy_db_schema::schema::comment_saved::dsl::*;
insert_into(comment_saved)
PersonId,
};
-impl Reportable<CommentReportForm> for CommentReport {
+impl Reportable for CommentReport {
+ type Form = CommentReportForm;
/// creates a comment report and returns it
///
/// * `conn` - the postgres connection
}
}
-impl Crud<CommunityForm, CommunityId> for Community {
+impl Crud for Community {
+ type Form = CommunityForm;
+ type IdType = CommunityId;
fn read(conn: &PgConnection, community_id: CommunityId) -> Result<Self, Error> {
use lemmy_db_schema::schema::community::dsl::*;
community.find(community_id).first::<Self>(conn)
}
}
-impl ApubObject<CommunityForm> for Community {
+impl ApubObject for Community {
+ type Form = CommunityForm;
fn read_from_apub_id(conn: &PgConnection, for_actor_id: &DbUrl) -> Result<Self, Error> {
use lemmy_db_schema::schema::community::dsl::*;
community
}
}
-impl Joinable<CommunityModeratorForm> for CommunityModerator {
+impl Joinable for CommunityModerator {
+ type Form = CommunityModeratorForm;
fn join(
conn: &PgConnection,
community_moderator_form: &CommunityModeratorForm,
}
}
-impl Bannable<CommunityPersonBanForm> for CommunityPersonBan {
+impl Bannable for CommunityPersonBan {
+ type Form = CommunityPersonBanForm;
fn ban(
conn: &PgConnection,
community_person_ban_form: &CommunityPersonBanForm,
}
}
-impl Followable<CommunityFollowerForm> for CommunityFollower {
+impl Followable for CommunityFollower {
+ type Form = CommunityFollowerForm;
fn follow(
conn: &PgConnection,
community_follower_form: &CommunityFollowerForm,
}
}
-impl Crud<LocalUserForm, LocalUserId> for LocalUser {
+impl Crud for LocalUser {
+ type Form = LocalUserForm;
+ type IdType = LocalUserId;
fn read(conn: &PgConnection, local_user_id: LocalUserId) -> Result<Self, Error> {
local_user.find(local_user_id).first::<Self>(conn)
}
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::source::moderator::*;
-impl Crud<ModRemovePostForm, i32> for ModRemovePost {
+impl Crud for ModRemovePost {
+ type Form = ModRemovePostForm;
+ type IdType = i32;
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use lemmy_db_schema::schema::mod_remove_post::dsl::*;
mod_remove_post.find(from_id).first::<Self>(conn)
}
}
-impl Crud<ModLockPostForm, i32> for ModLockPost {
+impl Crud for ModLockPost {
+ type Form = ModLockPostForm;
+ type IdType = i32;
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use lemmy_db_schema::schema::mod_lock_post::dsl::*;
mod_lock_post.find(from_id).first::<Self>(conn)
}
}
-impl Crud<ModStickyPostForm, i32> for ModStickyPost {
+impl Crud for ModStickyPost {
+ type Form = ModStickyPostForm;
+ type IdType = i32;
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use lemmy_db_schema::schema::mod_sticky_post::dsl::*;
mod_sticky_post.find(from_id).first::<Self>(conn)
}
}
-impl Crud<ModRemoveCommentForm, i32> for ModRemoveComment {
+impl Crud for ModRemoveComment {
+ type Form = ModRemoveCommentForm;
+ type IdType = i32;
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use lemmy_db_schema::schema::mod_remove_comment::dsl::*;
mod_remove_comment.find(from_id).first::<Self>(conn)
}
}
-impl Crud<ModRemoveCommunityForm, i32> for ModRemoveCommunity {
+impl Crud for ModRemoveCommunity {
+ type Form = ModRemoveCommunityForm;
+ type IdType = i32;
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use lemmy_db_schema::schema::mod_remove_community::dsl::*;
mod_remove_community.find(from_id).first::<Self>(conn)
}
}
-impl Crud<ModBanFromCommunityForm, i32> for ModBanFromCommunity {
+impl Crud for ModBanFromCommunity {
+ type Form = ModBanFromCommunityForm;
+ type IdType = i32;
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use lemmy_db_schema::schema::mod_ban_from_community::dsl::*;
mod_ban_from_community.find(from_id).first::<Self>(conn)
}
}
-impl Crud<ModBanForm, i32> for ModBan {
+impl Crud for ModBan {
+ type Form = ModBanForm;
+ type IdType = i32;
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use lemmy_db_schema::schema::mod_ban::dsl::*;
mod_ban.find(from_id).first::<Self>(conn)
}
}
-impl Crud<ModAddCommunityForm, i32> for ModAddCommunity {
+impl Crud for ModAddCommunity {
+ type Form = ModAddCommunityForm;
+ type IdType = i32;
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use lemmy_db_schema::schema::mod_add_community::dsl::*;
mod_add_community.find(from_id).first::<Self>(conn)
}
}
-impl Crud<ModAddForm, i32> for ModAdd {
+impl Crud for ModAdd {
+ type Form = ModAddForm;
+ type IdType = i32;
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use lemmy_db_schema::schema::mod_add::dsl::*;
mod_add.find(from_id).first::<Self>(conn)
};
use sha2::{Digest, Sha256};
-impl Crud<PasswordResetRequestForm, i32> for PasswordResetRequest {
+impl Crud for PasswordResetRequest {
+ type Form = PasswordResetRequestForm;
+ type IdType = i32;
fn read(conn: &PgConnection, password_reset_request_id: i32) -> Result<Self, Error> {
password_reset_request
.find(password_reset_request_id)
}
}
-impl Crud<PersonForm, PersonId> for Person {
+impl Crud for Person {
+ type Form = PersonForm;
+ type IdType = PersonId;
fn read(conn: &PgConnection, person_id: PersonId) -> Result<Self, Error> {
person
.filter(deleted.eq(false))
}
}
-impl ApubObject<PersonForm> for Person {
+impl ApubObject for Person {
+ type Form = PersonForm;
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Self, Error> {
use lemmy_db_schema::schema::person::dsl::*;
person
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{source::person_mention::*, PersonId, PersonMentionId};
-impl Crud<PersonMentionForm, PersonMentionId> for PersonMention {
+impl Crud for PersonMention {
+ type Form = PersonMentionForm;
+ type IdType = PersonMentionId;
fn read(conn: &PgConnection, person_mention_id: PersonMentionId) -> Result<Self, Error> {
use lemmy_db_schema::schema::person_mention::dsl::*;
person_mention.find(person_mention_id).first::<Self>(conn)
PostId,
};
-impl Crud<PostForm, PostId> for Post {
+impl Crud for Post {
+ type Form = PostForm;
+ type IdType = PostId;
fn read(conn: &PgConnection, post_id: PostId) -> Result<Self, Error> {
use lemmy_db_schema::schema::post::dsl::*;
post.find(post_id).first::<Self>(conn)
}
}
-impl ApubObject<PostForm> for Post {
+impl ApubObject for Post {
+ type Form = PostForm;
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Self, Error> {
use lemmy_db_schema::schema::post::dsl::*;
post.filter(ap_id.eq(object_id)).first::<Self>(conn)
}
}
-impl Likeable<PostLikeForm, PostId> for PostLike {
+impl Likeable for PostLike {
+ type Form = PostLikeForm;
+ type IdType = PostId;
fn like(conn: &PgConnection, post_like_form: &PostLikeForm) -> Result<Self, Error> {
use lemmy_db_schema::schema::post_like::dsl::*;
insert_into(post_like)
}
}
-impl Saveable<PostSavedForm> for PostSaved {
+impl Saveable for PostSaved {
+ type Form = PostSavedForm;
fn save(conn: &PgConnection, post_saved_form: &PostSavedForm) -> Result<Self, Error> {
use lemmy_db_schema::schema::post_saved::dsl::*;
insert_into(post_saved)
}
}
-impl Readable<PostReadForm> for PostRead {
+impl Readable for PostRead {
+ type Form = PostReadForm;
fn mark_as_read(conn: &PgConnection, post_read_form: &PostReadForm) -> Result<Self, Error> {
use lemmy_db_schema::schema::post_read::dsl::*;
insert_into(post_read)
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{naive_now, source::post_report::*, PersonId};
-impl Reportable<PostReportForm> for PostReport {
+impl Reportable for PostReport {
+ type Form = PostReportForm;
/// creates a post report and returns it
///
/// * `conn` - the postgres connection
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{naive_now, source::private_message::*, DbUrl, PersonId, PrivateMessageId};
-impl Crud<PrivateMessageForm, PrivateMessageId> for PrivateMessage {
+impl Crud for PrivateMessage {
+ type Form = PrivateMessageForm;
+ type IdType = PrivateMessageId;
fn read(conn: &PgConnection, private_message_id: PrivateMessageId) -> Result<Self, Error> {
use lemmy_db_schema::schema::private_message::dsl::*;
private_message.find(private_message_id).first::<Self>(conn)
}
}
-impl ApubObject<PrivateMessageForm> for PrivateMessage {
+impl ApubObject for PrivateMessage {
+ type Form = PrivateMessageForm;
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Self, Error>
where
Self: Sized,
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{naive_now, source::site::*, PersonId};
-impl Crud<SiteForm, i32> for Site {
+impl Crud for Site {
+ type Form = SiteForm;
+ type IdType = i32;
fn read(conn: &PgConnection, _site_id: i32) -> Result<Self, Error> {
use lemmy_db_schema::schema::site::dsl::*;
site.first::<Self>(conn)
lemmy_api_common = { version = "=0.11.3", path = "../api_common" }
lemmy_db_queries = { version = "=0.11.3", path = "../db_queries" }
lemmy_db_schema = { version = "=0.11.3", path = "../db_schema" }
+lemmy_db_views = { version = "=0.11.3", path = "../db_views" }
+lemmy_db_views_actor = { version = "=0.11.3", path = "../db_views_actor" }
reqwest = { version = "0.11.4", features = ["json"] }
log = "0.4.14"
rand = "0.8.4"
pub mod handlers;
pub mod messages;
pub mod routes;
+pub mod send;
pub struct LemmyContext {
pub pool: DbPool,
#[derive(Message)]
#[rtype(result = "()")]
-pub struct SendPost<OP: ToString> {
+pub(crate) struct SendPost<OP: ToString> {
pub op: OP,
pub post: PostResponse,
pub websocket_id: Option<ConnectionId>,
#[derive(Message)]
#[rtype(result = "()")]
-pub struct SendComment<OP: ToString> {
+pub(crate) struct SendComment<OP: ToString> {
pub op: OP,
pub comment: CommentResponse,
pub websocket_id: Option<ConnectionId>,
--- /dev/null
+use crate::{
+ messages::{SendComment, SendCommunityRoomMessage, SendPost, SendUserRoomMessage},
+ LemmyContext,
+ OperationType,
+};
+use lemmy_api_common::{
+ blocking,
+ comment::CommentResponse,
+ community::CommunityResponse,
+ person::PrivateMessageResponse,
+ post::PostResponse,
+};
+use lemmy_db_queries::DeleteableOrRemoveable;
+use lemmy_db_schema::{CommentId, CommunityId, LocalUserId, PersonId, PostId, PrivateMessageId};
+use lemmy_db_views::{
+ comment_view::CommentView,
+ local_user_view::LocalUserView,
+ post_view::PostView,
+ private_message_view::PrivateMessageView,
+};
+use lemmy_db_views_actor::community_view::CommunityView;
+use lemmy_utils::{ConnectionId, LemmyError};
+
+pub async fn send_post_ws_message<OP: ToString + Send + OperationType + 'static>(
+ post_id: PostId,
+ op: OP,
+ websocket_id: Option<ConnectionId>,
+ person_id: Option<PersonId>,
+ context: &LemmyContext,
+) -> Result<PostResponse, LemmyError> {
+ let mut post_view = blocking(context.pool(), move |conn| {
+ PostView::read(conn, post_id, person_id)
+ })
+ .await??;
+
+ if post_view.post.deleted || post_view.post.removed {
+ post_view.post = post_view.post.blank_out_deleted_or_removed_info();
+ }
+
+ let res = PostResponse { post_view };
+
+ context.chat_server().do_send(SendPost {
+ op,
+ post: res.clone(),
+ websocket_id,
+ });
+
+ Ok(res)
+}
+
+// TODO: in many call sites in apub crate, we are setting an empty vec for recipient_ids,
+// we should get the actual recipient actors from somewhere
+pub async fn send_comment_ws_message_simple<OP: ToString + Send + OperationType + 'static>(
+ comment_id: CommentId,
+ op: OP,
+ context: &LemmyContext,
+) -> Result<CommentResponse, LemmyError> {
+ send_comment_ws_message(comment_id, op, None, None, None, vec![], context).await
+}
+
+pub async fn send_comment_ws_message<OP: ToString + Send + OperationType + 'static>(
+ comment_id: CommentId,
+ op: OP,
+ websocket_id: Option<ConnectionId>,
+ form_id: Option<String>,
+ person_id: Option<PersonId>,
+ recipient_ids: Vec<LocalUserId>,
+ context: &LemmyContext,
+) -> Result<CommentResponse, LemmyError> {
+ let mut view = blocking(context.pool(), move |conn| {
+ CommentView::read(conn, comment_id, person_id)
+ })
+ .await??;
+
+ if view.comment.deleted || view.comment.removed {
+ view.comment = view.comment.blank_out_deleted_or_removed_info();
+ }
+
+ let res = CommentResponse {
+ comment_view: view,
+ recipient_ids,
+ form_id,
+ };
+
+ context.chat_server().do_send(SendComment {
+ op,
+ comment: res.clone(),
+ websocket_id,
+ });
+
+ Ok(res)
+}
+
+pub async fn send_community_ws_message<OP: ToString + Send + OperationType + 'static>(
+ community_id: CommunityId,
+ op: OP,
+ websocket_id: Option<ConnectionId>,
+ person_id: Option<PersonId>,
+ context: &LemmyContext,
+) -> Result<CommunityResponse, LemmyError> {
+ let mut community_view = blocking(context.pool(), move |conn| {
+ CommunityView::read(conn, community_id, person_id)
+ })
+ .await??;
+ // Blank out deleted or removed info
+ if community_view.community.deleted || community_view.community.removed {
+ community_view.community = community_view.community.blank_out_deleted_or_removed_info();
+ }
+
+ let res = CommunityResponse { community_view };
+
+ // Strip out the person id and subscribed when sending to others
+ let mut res_mut = res.clone();
+ res_mut.community_view.subscribed = false;
+
+ context.chat_server().do_send(SendCommunityRoomMessage {
+ op,
+ response: res_mut,
+ community_id: res.community_view.community.id,
+ websocket_id,
+ });
+
+ Ok(res)
+}
+
+pub async fn send_pm_ws_message<OP: ToString + Send + OperationType + 'static>(
+ private_message_id: PrivateMessageId,
+ op: OP,
+ websocket_id: Option<ConnectionId>,
+ context: &LemmyContext,
+) -> Result<PrivateMessageResponse, LemmyError> {
+ let mut view = blocking(context.pool(), move |conn| {
+ PrivateMessageView::read(conn, private_message_id)
+ })
+ .await??;
+
+ // Blank out deleted or removed info
+ if view.private_message.deleted {
+ view.private_message = view.private_message.blank_out_deleted_or_removed_info();
+ }
+
+ let res = PrivateMessageResponse {
+ private_message_view: view,
+ };
+
+ // Send notifications to the local recipient, if one exists
+ if res.private_message_view.recipient.local {
+ let recipient_id = res.private_message_view.recipient.id;
+ let local_recipient = blocking(context.pool(), move |conn| {
+ LocalUserView::read_person(conn, recipient_id)
+ })
+ .await??;
+ context.chat_server().do_send(SendUserRoomMessage {
+ op,
+ response: res.clone(),
+ local_recipient_id: local_recipient.local_user.id,
+ websocket_id,
+ });
+ }
+
+ Ok(res)
+}