]> Untitled Git - lemmy.git/blob - server/src/apub/post.rs
Merge branch 'dev' into federation
[lemmy.git] / server / src / apub / post.rs
1 use crate::apub::create_apub_response;
2 use crate::apub::fetcher::{fetch_remote_community, fetch_remote_user};
3 use crate::convert_datetime;
4 use crate::db::community::Community;
5 use crate::db::post::{Post, PostForm};
6 use crate::db::user::User_;
7 use crate::db::Crud;
8 use activitystreams::{context, object::properties::ObjectProperties, object::Page};
9 use actix_web::body::Body;
10 use actix_web::web::Path;
11 use actix_web::{web, HttpResponse};
12 use diesel::r2d2::{ConnectionManager, Pool};
13 use diesel::PgConnection;
14 use failure::Error;
15 use serde::Deserialize;
16 use url::Url;
17
18 #[derive(Deserialize)]
19 pub struct PostQuery {
20   post_id: String,
21 }
22
23 pub async fn get_apub_post(
24   info: Path<PostQuery>,
25   db: web::Data<Pool<ConnectionManager<PgConnection>>>,
26 ) -> Result<HttpResponse<Body>, Error> {
27   let id = info.post_id.parse::<i32>()?;
28   let post = Post::read(&&db.get()?, id)?;
29   Ok(create_apub_response(&post.as_page(&db.get().unwrap())?))
30 }
31
32 impl Post {
33   pub fn as_page(&self, conn: &PgConnection) -> Result<Page, Error> {
34     let mut page = Page::default();
35     let oprops: &mut ObjectProperties = page.as_mut();
36     let creator = User_::read(conn, self.creator_id)?;
37     let community = Community::read(conn, self.community_id)?;
38
39     oprops
40       // Not needed when the Post is embedded in a collection (like for community outbox)
41       .set_context_xsd_any_uri(context())?
42       .set_id(self.ap_id.to_owned())?
43       // Use summary field to be consistent with mastodon content warning.
44       // https://mastodon.xyz/@Louisa/103987265222901387.json
45       .set_summary_xsd_string(self.name.to_owned())?
46       .set_published(convert_datetime(self.published))?
47       .set_to_xsd_any_uri(community.actor_id)?
48       .set_attributed_to_xsd_any_uri(creator.actor_id)?;
49
50     if let Some(body) = &self.body {
51       oprops.set_content_xsd_string(body.to_owned())?;
52     }
53
54     // TODO: hacky code because we get self.url == Some("")
55     // https://github.com/dessalines/lemmy/issues/602
56     let url = self.url.as_ref().filter(|u| !u.is_empty());
57     if let Some(u) = url {
58       oprops.set_url_xsd_any_uri(u.to_owned())?;
59     }
60
61     if let Some(u) = self.updated {
62       oprops.set_updated(convert_datetime(u))?;
63     }
64
65     Ok(page)
66   }
67 }
68
69 impl PostForm {
70   pub fn from_page(page: &Page, conn: &PgConnection) -> Result<PostForm, Error> {
71     let oprops = &page.object_props;
72     let creator_id = Url::parse(&oprops.get_attributed_to_xsd_any_uri().unwrap().to_string())?;
73     let creator = fetch_remote_user(&creator_id, conn)?;
74     let community_id = Url::parse(&oprops.get_to_xsd_any_uri().unwrap().to_string())?;
75     let community = fetch_remote_community(&community_id, conn)?;
76
77     Ok(PostForm {
78       name: oprops.get_summary_xsd_string().unwrap().to_string(),
79       url: oprops.get_url_xsd_any_uri().map(|u| u.to_string()),
80       body: oprops.get_content_xsd_string().map(|c| c.to_string()),
81       creator_id: creator.id,
82       community_id: community.id,
83       removed: None, // -> Delete activity / tombstone
84       locked: None,  // -> commentsEnabled
85       published: oprops
86         .get_published()
87         .map(|u| u.as_ref().to_owned().naive_local()),
88       updated: oprops
89         .get_updated()
90         .map(|u| u.as_ref().to_owned().naive_local()),
91       deleted: None,     // -> Delete activity / tombstone
92       nsfw: false,       // -> sensitive
93       stickied: None,    // -> put it in "featured" collection of the community
94       embed_title: None, // -> attachment?
95       embed_description: None,
96       embed_html: None,
97       thumbnail_url: None,
98       ap_id: oprops.get_id().unwrap().to_string(),
99       local: false,
100     })
101   }
102 }