]> Untitled Git - lemmy.git/blob - src/apub/inbox/activities/create.rs
961991a651de9781a46b303219b41342f4cb364a
[lemmy.git] / src / apub / inbox / activities / create.rs
1 use crate::{
2   apub::{
3     inbox::shared_inbox::{
4       announce_if_community_is_local,
5       get_user_from_activity,
6       receive_unhandled_activity,
7     },
8     ActorType,
9     FromApub,
10     PageExt,
11   },
12   LemmyContext,
13 };
14 use activitystreams::{activity::Create, base::AnyBase, object::Note, prelude::*};
15 use actix_web::HttpResponse;
16 use anyhow::Context;
17 use lemmy_db::{
18   comment::{Comment, CommentForm},
19   comment_view::CommentView,
20   post::{Post, PostForm},
21   post_view::PostView,
22 };
23 use lemmy_structs::{
24   blocking,
25   comment::CommentResponse,
26   post::PostResponse,
27   send_local_notifs,
28   websocket::{SendComment, SendPost, UserOperation},
29 };
30 use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError};
31
32 pub async fn receive_create(
33   activity: AnyBase,
34   context: &LemmyContext,
35 ) -> Result<HttpResponse, LemmyError> {
36   let create = Create::from_any_base(activity)?.context(location_info!())?;
37
38   // ensure that create and actor come from the same instance
39   let user = get_user_from_activity(&create, context).await?;
40   create.id(user.actor_id()?.domain().context(location_info!())?)?;
41
42   match create.object().as_single_kind_str() {
43     Some("Page") => receive_create_post(create, context).await,
44     Some("Note") => receive_create_comment(create, context).await,
45     _ => receive_unhandled_activity(create),
46   }
47 }
48
49 async fn receive_create_post(
50   create: Create,
51   context: &LemmyContext,
52 ) -> Result<HttpResponse, LemmyError> {
53   let user = get_user_from_activity(&create, context).await?;
54   let page = PageExt::from_any_base(create.object().to_owned().one().context(location_info!())?)?
55     .context(location_info!())?;
56
57   let post = PostForm::from_apub(&page, context, Some(user.actor_id()?)).await?;
58
59   // Using an upsert, since likes (which fetch the post), sometimes come in before the create
60   // resulting in double posts.
61   let inserted_post = blocking(context.pool(), move |conn| Post::upsert(conn, &post)).await??;
62
63   // Refetch the view
64   let inserted_post_id = inserted_post.id;
65   let post_view = blocking(context.pool(), move |conn| {
66     PostView::read(conn, inserted_post_id, None)
67   })
68   .await??;
69
70   let res = PostResponse { post: post_view };
71
72   context.chat_server().do_send(SendPost {
73     op: UserOperation::CreatePost,
74     post: res,
75     websocket_id: None,
76   });
77
78   announce_if_community_is_local(create, &user, context).await?;
79   Ok(HttpResponse::Ok().finish())
80 }
81
82 async fn receive_create_comment(
83   create: Create,
84   context: &LemmyContext,
85 ) -> Result<HttpResponse, LemmyError> {
86   let user = get_user_from_activity(&create, context).await?;
87   let note = Note::from_any_base(create.object().to_owned().one().context(location_info!())?)?
88     .context(location_info!())?;
89
90   let comment = CommentForm::from_apub(&note, context, Some(user.actor_id()?)).await?;
91
92   let inserted_comment =
93     blocking(context.pool(), move |conn| Comment::upsert(conn, &comment)).await??;
94
95   let post_id = inserted_comment.post_id;
96   let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
97
98   // Note:
99   // Although mentions could be gotten from the post tags (they are included there), or the ccs,
100   // Its much easier to scrape them from the comment body, since the API has to do that
101   // anyway.
102   let mentions = scrape_text_for_mentions(&inserted_comment.content);
103   let recipient_ids = send_local_notifs(
104     mentions,
105     inserted_comment.clone(),
106     &user,
107     post,
108     context.pool(),
109     true,
110   )
111   .await?;
112
113   // Refetch the view
114   let comment_view = blocking(context.pool(), move |conn| {
115     CommentView::read(conn, inserted_comment.id, None)
116   })
117   .await??;
118
119   let res = CommentResponse {
120     comment: comment_view,
121     recipient_ids,
122     form_id: None,
123   };
124
125   context.chat_server().do_send(SendComment {
126     op: UserOperation::CreateComment,
127     comment: res,
128     websocket_id: None,
129   });
130
131   announce_if_community_is_local(create, &user, context).await?;
132   Ok(HttpResponse::Ok().finish())
133 }