]> Untitled Git - lemmy.git/blob - server/src/apub/inbox/activities/update.rs
routes.api: fix get_captcha endpoint (#1135)
[lemmy.git] / server / src / apub / inbox / activities / update.rs
1 use crate::{
2   apub::{
3     fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
4     inbox::shared_inbox::{
5       announce_if_community_is_local,
6       get_user_from_activity,
7       receive_unhandled_activity,
8     },
9     ActorType,
10     FromApub,
11     PageExt,
12   },
13   websocket::{
14     messages::{SendComment, SendPost},
15     UserOperation,
16   },
17   LemmyContext,
18 };
19 use activitystreams::{activity::Update, base::AnyBase, object::Note, prelude::*};
20 use actix_web::HttpResponse;
21 use anyhow::Context;
22 use lemmy_api_structs::{
23   blocking,
24   comment::CommentResponse,
25   post::PostResponse,
26   send_local_notifs,
27 };
28 use lemmy_db::{
29   comment::{Comment, CommentForm},
30   comment_view::CommentView,
31   post::{Post, PostForm},
32   post_view::PostView,
33   Crud,
34 };
35 use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError};
36
37 pub async fn receive_update(
38   activity: AnyBase,
39   context: &LemmyContext,
40 ) -> Result<HttpResponse, LemmyError> {
41   let update = Update::from_any_base(activity)?.context(location_info!())?;
42
43   // ensure that update and actor come from the same instance
44   let user = get_user_from_activity(&update, context).await?;
45   update.id(user.actor_id()?.domain().context(location_info!())?)?;
46
47   match update.object().as_single_kind_str() {
48     Some("Page") => receive_update_post(update, context).await,
49     Some("Note") => receive_update_comment(update, context).await,
50     _ => receive_unhandled_activity(update),
51   }
52 }
53
54 async fn receive_update_post(
55   update: Update,
56   context: &LemmyContext,
57 ) -> Result<HttpResponse, LemmyError> {
58   let user = get_user_from_activity(&update, context).await?;
59   let page = PageExt::from_any_base(update.object().to_owned().one().context(location_info!())?)?
60     .context(location_info!())?;
61
62   let post = PostForm::from_apub(&page, context, Some(user.actor_id()?)).await?;
63
64   let original_post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context)
65     .await?
66     .id;
67
68   blocking(context.pool(), move |conn| {
69     Post::update(conn, original_post_id, &post)
70   })
71   .await??;
72
73   // Refetch the view
74   let post_view = blocking(context.pool(), move |conn| {
75     PostView::read(conn, original_post_id, None)
76   })
77   .await??;
78
79   let res = PostResponse { post: post_view };
80
81   context.chat_server().do_send(SendPost {
82     op: UserOperation::EditPost,
83     post: res,
84     websocket_id: None,
85   });
86
87   announce_if_community_is_local(update, &user, context).await?;
88   Ok(HttpResponse::Ok().finish())
89 }
90
91 async fn receive_update_comment(
92   update: Update,
93   context: &LemmyContext,
94 ) -> Result<HttpResponse, LemmyError> {
95   let note = Note::from_any_base(update.object().to_owned().one().context(location_info!())?)?
96     .context(location_info!())?;
97   let user = get_user_from_activity(&update, context).await?;
98
99   let comment = CommentForm::from_apub(&note, context, Some(user.actor_id()?)).await?;
100
101   let original_comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context)
102     .await?
103     .id;
104
105   let updated_comment = blocking(context.pool(), move |conn| {
106     Comment::update(conn, original_comment_id, &comment)
107   })
108   .await??;
109
110   let post_id = updated_comment.post_id;
111   let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
112
113   let mentions = scrape_text_for_mentions(&updated_comment.content);
114   let recipient_ids = send_local_notifs(
115     mentions,
116     updated_comment,
117     &user,
118     post,
119     context.pool(),
120     false,
121   )
122   .await?;
123
124   // Refetch the view
125   let comment_view = blocking(context.pool(), move |conn| {
126     CommentView::read(conn, original_comment_id, None)
127   })
128   .await??;
129
130   let res = CommentResponse {
131     comment: comment_view,
132     recipient_ids,
133     form_id: None,
134   };
135
136   context.chat_server().do_send(SendComment {
137     op: UserOperation::EditComment,
138     comment: res,
139     websocket_id: None,
140   });
141
142   announce_if_community_is_local(update, &user, context).await?;
143   Ok(HttpResponse::Ok().finish())
144 }