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