4 announce_if_community_is_local,
5 get_user_from_activity,
6 receive_unhandled_activity,
13 messages::{SendComment, SendPost},
18 use activitystreams::{activity::Create, base::AnyBase, object::Note, prelude::*};
19 use actix_web::HttpResponse;
21 use lemmy_api_structs::{
23 comment::CommentResponse,
28 comment::{Comment, CommentForm},
29 comment_view::CommentView,
30 post::{Post, PostForm},
33 use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError};
35 pub async fn receive_create(
37 context: &LemmyContext,
38 ) -> Result<HttpResponse, LemmyError> {
39 let create = Create::from_any_base(activity)?.context(location_info!())?;
41 // ensure that create and actor come from the same instance
42 let user = get_user_from_activity(&create, context).await?;
43 create.id(user.actor_id()?.domain().context(location_info!())?)?;
45 match create.object().as_single_kind_str() {
46 Some("Page") => receive_create_post(create, context).await,
47 Some("Note") => receive_create_comment(create, context).await,
48 _ => receive_unhandled_activity(create),
52 async fn receive_create_post(
54 context: &LemmyContext,
55 ) -> Result<HttpResponse, LemmyError> {
56 let user = get_user_from_activity(&create, context).await?;
57 let page = PageExt::from_any_base(create.object().to_owned().one().context(location_info!())?)?
58 .context(location_info!())?;
60 let post = PostForm::from_apub(&page, context, Some(user.actor_id()?)).await?;
62 // Using an upsert, since likes (which fetch the post), sometimes come in before the create
63 // resulting in double posts.
64 let inserted_post = blocking(context.pool(), move |conn| Post::upsert(conn, &post)).await??;
67 let inserted_post_id = inserted_post.id;
68 let post_view = blocking(context.pool(), move |conn| {
69 PostView::read(conn, inserted_post_id, None)
73 let res = PostResponse { post: post_view };
75 context.chat_server().do_send(SendPost {
76 op: UserOperation::CreatePost,
81 announce_if_community_is_local(create, &user, context).await?;
82 Ok(HttpResponse::Ok().finish())
85 async fn receive_create_comment(
87 context: &LemmyContext,
88 ) -> Result<HttpResponse, LemmyError> {
89 let user = get_user_from_activity(&create, context).await?;
90 let note = Note::from_any_base(create.object().to_owned().one().context(location_info!())?)?
91 .context(location_info!())?;
93 let comment = CommentForm::from_apub(¬e, context, Some(user.actor_id()?)).await?;
95 let inserted_comment =
96 blocking(context.pool(), move |conn| Comment::upsert(conn, &comment)).await??;
98 let post_id = inserted_comment.post_id;
99 let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
102 // Although mentions could be gotten from the post tags (they are included there), or the ccs,
103 // Its much easier to scrape them from the comment body, since the API has to do that
105 let mentions = scrape_text_for_mentions(&inserted_comment.content);
106 let recipient_ids = send_local_notifs(
108 inserted_comment.clone(),
117 let comment_view = blocking(context.pool(), move |conn| {
118 CommentView::read(conn, inserted_comment.id, None)
122 let res = CommentResponse {
123 comment: comment_view,
128 context.chat_server().do_send(SendComment {
129 op: UserOperation::CreateComment,
134 announce_if_community_is_local(create, &user, context).await?;
135 Ok(HttpResponse::Ok().finish())