2 api::{comment::CommentResponse, community::CommunityResponse, post::PostResponse},
4 fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
6 announce_if_community_is_local,
7 get_user_from_activity,
8 receive_unhandled_activity,
16 routes::ChatServerParam,
18 server::{SendComment, SendCommunityRoomMessage, SendPost},
24 use activitystreams::{
26 base::{AnyBase, AsBase},
30 use actix_web::{client::Client, HttpResponse};
33 comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
34 comment_view::CommentView,
35 community::{Community, CommunityForm},
36 community_view::CommunityView,
38 post::{Post, PostForm, PostLike, PostLikeForm},
44 pub async fn receive_undo(
48 chat_server: ChatServerParam,
49 ) -> Result<HttpResponse, LemmyError> {
50 let undo = Undo::from_any_base(activity)?.unwrap();
51 match undo.object().as_single_kind_str() {
52 Some("Delete") => receive_undo_delete(undo, client, pool, chat_server).await,
53 Some("Remove") => receive_undo_remove(undo, client, pool, chat_server).await,
54 Some("Like") => receive_undo_like(undo, client, pool, chat_server).await,
55 Some("Dislike") => receive_undo_dislike(undo, client, pool, chat_server).await,
56 _ => receive_unhandled_activity(undo),
60 fn check_is_undo_valid<T, A>(outer_activity: &Undo, inner_activity: &T) -> Result<(), LemmyError>
62 T: AsBase<A> + ActorAndObjectRef,
64 let outer_actor = outer_activity.actor()?;
65 let outer_actor_uri = outer_actor.as_single_xsd_any_uri().unwrap();
67 let inner_actor = inner_activity.actor()?;
68 let inner_actor_uri = inner_actor.as_single_xsd_any_uri().unwrap();
70 if outer_actor_uri != inner_actor_uri {
71 Err(anyhow!("An actor can only undo its own activities").into())
77 async fn receive_undo_delete(
81 chat_server: ChatServerParam,
82 ) -> Result<HttpResponse, LemmyError> {
83 let delete = Delete::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
84 check_is_undo_valid(&undo, &delete)?;
85 let type_ = delete.object().as_single_kind_str().unwrap();
87 "Note" => receive_undo_delete_comment(undo, &delete, client, pool, chat_server).await,
88 "Page" => receive_undo_delete_post(undo, &delete, client, pool, chat_server).await,
89 "Group" => receive_undo_delete_community(undo, &delete, client, pool, chat_server).await,
90 d => Err(anyhow!("Undo Delete type {} not supported", d).into()),
94 async fn receive_undo_remove(
98 chat_server: ChatServerParam,
99 ) -> Result<HttpResponse, LemmyError> {
100 let remove = Remove::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
101 check_is_undo_valid(&undo, &remove)?;
103 let type_ = remove.object().as_single_kind_str().unwrap();
105 "Note" => receive_undo_remove_comment(undo, &remove, client, pool, chat_server).await,
106 "Page" => receive_undo_remove_post(undo, &remove, client, pool, chat_server).await,
107 "Group" => receive_undo_remove_community(undo, &remove, client, pool, chat_server).await,
108 d => Err(anyhow!("Undo Delete type {} not supported", d).into()),
112 async fn receive_undo_like(
116 chat_server: ChatServerParam,
117 ) -> Result<HttpResponse, LemmyError> {
118 let like = Like::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
119 check_is_undo_valid(&undo, &like)?;
121 let type_ = like.object().as_single_kind_str().unwrap();
123 "Note" => receive_undo_like_comment(undo, &like, client, pool, chat_server).await,
124 "Page" => receive_undo_like_post(undo, &like, client, pool, chat_server).await,
125 d => Err(anyhow!("Undo Delete type {} not supported", d).into()),
129 async fn receive_undo_dislike(
133 _chat_server: ChatServerParam,
134 ) -> Result<HttpResponse, LemmyError> {
135 let dislike = Dislike::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
136 check_is_undo_valid(&undo, &dislike)?;
138 // TODO: need to implement Undo<Dislike>
140 let type_ = dislike.object().as_single_kind_str().unwrap();
141 Err(anyhow!("Undo Delete type {} not supported", type_).into())
144 async fn receive_undo_delete_comment(
149 chat_server: ChatServerParam,
150 ) -> Result<HttpResponse, LemmyError> {
151 let user = get_user_from_activity(delete, client, pool).await?;
152 let note = Note::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
154 let comment_ap_id = CommentForm::from_apub(¬e, client, pool, Some(user.actor_id()?))
158 let comment = get_or_fetch_and_insert_comment(&comment_ap_id, client, pool).await?;
160 let comment_form = CommentForm {
161 content: comment.content.to_owned(),
162 parent_id: comment.parent_id,
163 post_id: comment.post_id,
164 creator_id: comment.creator_id,
166 deleted: Some(false),
169 updated: Some(naive_now()),
170 ap_id: comment.ap_id,
171 local: comment.local,
173 let comment_id = comment.id;
174 blocking(pool, move |conn| {
175 Comment::update(conn, comment_id, &comment_form)
180 let comment_id = comment.id;
182 blocking(pool, move |conn| CommentView::read(conn, comment_id, None)).await??;
184 // TODO get those recipient actor ids from somewhere
185 let recipient_ids = vec![];
186 let res = CommentResponse {
187 comment: comment_view,
192 chat_server.do_send(SendComment {
193 op: UserOperation::EditComment,
198 announce_if_community_is_local(undo, &user, client, pool).await?;
199 Ok(HttpResponse::Ok().finish())
202 async fn receive_undo_remove_comment(
207 chat_server: ChatServerParam,
208 ) -> Result<HttpResponse, LemmyError> {
209 let mod_ = get_user_from_activity(remove, client, pool).await?;
210 let note = Note::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
212 let comment_ap_id = CommentForm::from_apub(¬e, client, pool, Some(mod_.actor_id()?))
216 let comment = get_or_fetch_and_insert_comment(&comment_ap_id, client, pool).await?;
218 let comment_form = CommentForm {
219 content: comment.content.to_owned(),
220 parent_id: comment.parent_id,
221 post_id: comment.post_id,
222 creator_id: comment.creator_id,
223 removed: Some(false),
227 updated: Some(naive_now()),
228 ap_id: comment.ap_id,
229 local: comment.local,
231 let comment_id = comment.id;
232 blocking(pool, move |conn| {
233 Comment::update(conn, comment_id, &comment_form)
238 let comment_id = comment.id;
240 blocking(pool, move |conn| CommentView::read(conn, comment_id, None)).await??;
242 // TODO get those recipient actor ids from somewhere
243 let recipient_ids = vec![];
244 let res = CommentResponse {
245 comment: comment_view,
250 chat_server.do_send(SendComment {
251 op: UserOperation::EditComment,
256 announce_if_community_is_local(undo, &mod_, client, pool).await?;
257 Ok(HttpResponse::Ok().finish())
260 async fn receive_undo_delete_post(
265 chat_server: ChatServerParam,
266 ) -> Result<HttpResponse, LemmyError> {
267 let user = get_user_from_activity(delete, client, pool).await?;
268 let page = PageExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
270 let post_ap_id = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?))
274 let post = get_or_fetch_and_insert_post(&post_ap_id, client, pool).await?;
276 let post_form = PostForm {
277 name: post.name.to_owned(),
278 url: post.url.to_owned(),
279 body: post.body.to_owned(),
280 creator_id: post.creator_id.to_owned(),
281 community_id: post.community_id,
283 deleted: Some(false),
287 updated: Some(naive_now()),
288 embed_title: post.embed_title,
289 embed_description: post.embed_description,
290 embed_html: post.embed_html,
291 thumbnail_url: post.thumbnail_url,
296 let post_id = post.id;
297 blocking(pool, move |conn| Post::update(conn, post_id, &post_form)).await??;
300 let post_id = post.id;
301 let post_view = blocking(pool, move |conn| PostView::read(conn, post_id, None)).await??;
303 let res = PostResponse { post: post_view };
305 chat_server.do_send(SendPost {
306 op: UserOperation::EditPost,
311 announce_if_community_is_local(undo, &user, client, pool).await?;
312 Ok(HttpResponse::Ok().finish())
315 async fn receive_undo_remove_post(
320 chat_server: ChatServerParam,
321 ) -> Result<HttpResponse, LemmyError> {
322 let mod_ = get_user_from_activity(remove, client, pool).await?;
323 let page = PageExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
325 let post_ap_id = PostForm::from_apub(&page, client, pool, Some(mod_.actor_id()?))
329 let post = get_or_fetch_and_insert_post(&post_ap_id, client, pool).await?;
331 let post_form = PostForm {
332 name: post.name.to_owned(),
333 url: post.url.to_owned(),
334 body: post.body.to_owned(),
335 creator_id: post.creator_id.to_owned(),
336 community_id: post.community_id,
337 removed: Some(false),
342 updated: Some(naive_now()),
343 embed_title: post.embed_title,
344 embed_description: post.embed_description,
345 embed_html: post.embed_html,
346 thumbnail_url: post.thumbnail_url,
351 let post_id = post.id;
352 blocking(pool, move |conn| Post::update(conn, post_id, &post_form)).await??;
355 let post_id = post.id;
356 let post_view = blocking(pool, move |conn| PostView::read(conn, post_id, None)).await??;
358 let res = PostResponse { post: post_view };
360 chat_server.do_send(SendPost {
361 op: UserOperation::EditPost,
366 announce_if_community_is_local(undo, &mod_, client, pool).await?;
367 Ok(HttpResponse::Ok().finish())
370 async fn receive_undo_delete_community(
375 chat_server: ChatServerParam,
376 ) -> Result<HttpResponse, LemmyError> {
377 let user = get_user_from_activity(delete, client, pool).await?;
378 let group = GroupExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
380 let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(user.actor_id()?))
384 let community = blocking(pool, move |conn| {
385 Community::read_from_actor_id(conn, &community_actor_id)
389 let community_form = CommunityForm {
390 name: community.name.to_owned(),
391 title: community.title.to_owned(),
392 description: community.description.to_owned(),
393 category_id: community.category_id, // Note: need to keep this due to foreign key constraint
394 creator_id: community.creator_id, // Note: need to keep this due to foreign key constraint
397 updated: Some(naive_now()),
398 deleted: Some(false),
399 nsfw: community.nsfw,
400 actor_id: community.actor_id,
401 local: community.local,
402 private_key: community.private_key,
403 public_key: community.public_key,
404 last_refreshed_at: None,
407 let community_id = community.id;
408 blocking(pool, move |conn| {
409 Community::update(conn, community_id, &community_form)
413 let community_id = community.id;
414 let res = CommunityResponse {
415 community: blocking(pool, move |conn| {
416 CommunityView::read(conn, community_id, None)
421 let community_id = res.community.id;
423 chat_server.do_send(SendCommunityRoomMessage {
424 op: UserOperation::EditCommunity,
430 announce_if_community_is_local(undo, &user, client, pool).await?;
431 Ok(HttpResponse::Ok().finish())
434 async fn receive_undo_remove_community(
439 chat_server: ChatServerParam,
440 ) -> Result<HttpResponse, LemmyError> {
441 let mod_ = get_user_from_activity(remove, client, pool).await?;
442 let group = GroupExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
444 let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(mod_.actor_id()?))
448 let community = blocking(pool, move |conn| {
449 Community::read_from_actor_id(conn, &community_actor_id)
453 let community_form = CommunityForm {
454 name: community.name.to_owned(),
455 title: community.title.to_owned(),
456 description: community.description.to_owned(),
457 category_id: community.category_id, // Note: need to keep this due to foreign key constraint
458 creator_id: community.creator_id, // Note: need to keep this due to foreign key constraint
459 removed: Some(false),
461 updated: Some(naive_now()),
463 nsfw: community.nsfw,
464 actor_id: community.actor_id,
465 local: community.local,
466 private_key: community.private_key,
467 public_key: community.public_key,
468 last_refreshed_at: None,
471 let community_id = community.id;
472 blocking(pool, move |conn| {
473 Community::update(conn, community_id, &community_form)
477 let community_id = community.id;
478 let res = CommunityResponse {
479 community: blocking(pool, move |conn| {
480 CommunityView::read(conn, community_id, None)
485 let community_id = res.community.id;
487 chat_server.do_send(SendCommunityRoomMessage {
488 op: UserOperation::EditCommunity,
494 announce_if_community_is_local(undo, &mod_, client, pool).await?;
495 Ok(HttpResponse::Ok().finish())
498 async fn receive_undo_like_comment(
503 chat_server: ChatServerParam,
504 ) -> Result<HttpResponse, LemmyError> {
505 let user = get_user_from_activity(like, client, pool).await?;
506 let note = Note::from_any_base(like.object().to_owned().one().unwrap())?.unwrap();
508 let comment = CommentForm::from_apub(¬e, client, pool, None).await?;
510 let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, client, pool)
514 let like_form = CommentLikeForm {
516 post_id: comment.post_id,
520 blocking(pool, move |conn| CommentLike::remove(conn, &like_form)).await??;
524 blocking(pool, move |conn| CommentView::read(conn, comment_id, None)).await??;
526 // TODO get those recipient actor ids from somewhere
527 let recipient_ids = vec![];
528 let res = CommentResponse {
529 comment: comment_view,
534 chat_server.do_send(SendComment {
535 op: UserOperation::CreateCommentLike,
540 announce_if_community_is_local(undo, &user, client, pool).await?;
541 Ok(HttpResponse::Ok().finish())
544 async fn receive_undo_like_post(
549 chat_server: ChatServerParam,
550 ) -> Result<HttpResponse, LemmyError> {
551 let user = get_user_from_activity(like, client, pool).await?;
552 let page = PageExt::from_any_base(like.object().to_owned().one().unwrap())?.unwrap();
554 let post = PostForm::from_apub(&page, client, pool, None).await?;
556 let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, client, pool)
560 let like_form = PostLikeForm {
565 blocking(pool, move |conn| PostLike::remove(conn, &like_form)).await??;
568 let post_view = blocking(pool, move |conn| PostView::read(conn, post_id, None)).await??;
570 let res = PostResponse { post: post_view };
572 chat_server.do_send(SendPost {
573 op: UserOperation::CreatePostLike,
578 announce_if_community_is_local(undo, &user, client, pool).await?;
579 Ok(HttpResponse::Ok().finish())