]> Untitled Git - lemmy.git/commitdiff
Implement create activity
authorFelix <me@nutomic.com>
Thu, 9 Apr 2020 19:04:31 +0000 (21:04 +0200)
committerFelix <me@nutomic.com>
Thu, 9 Apr 2020 19:04:31 +0000 (21:04 +0200)
server/src/api/post.rs
server/src/apub/activities.rs [new file with mode: 0644]
server/src/apub/inbox.rs [new file with mode: 0644]
server/src/apub/mod.rs
server/src/apub/post.rs
server/src/apub/puller.rs
server/src/routes/federation.rs

index 18c33dc1af0b3eef7d486e572d10574a887f2813..7e7126a2f64c7039880660aa0c4fd1067d33865c 100644 (file)
@@ -1,4 +1,5 @@
 use super::*;
+use crate::apub::activities::post_create;
 use diesel::PgConnection;
 use std::str::FromStr;
 
@@ -153,6 +154,8 @@ impl Perform<PostResponse> for Oper<CreatePost> {
       Err(_e) => return Err(APIError::err("couldnt_create_post").into()),
     };
 
+    post_create(&inserted_post, conn)?;
+
     // They like their own post by default
     let like_form = PostLikeForm {
       post_id: inserted_post.id,
diff --git a/server/src/apub/activities.rs b/server/src/apub/activities.rs
new file mode 100644 (file)
index 0000000..81a624b
--- /dev/null
@@ -0,0 +1,36 @@
+use crate::apub::{get_apub_protocol_string, get_following_instances};
+use crate::db::post::Post;
+use crate::db::user::User_;
+use crate::db::Crud;
+use activitystreams::activity::Create;
+use activitystreams::context;
+use diesel::PgConnection;
+use failure::Error;
+use isahc::prelude::*;
+
+pub fn post_create(post: &Post, conn: &PgConnection) -> Result<(), Error> {
+  let user = User_::read(conn, post.creator_id)?;
+  let page = post.as_page(conn)?;
+  let mut create = Create::new();
+  create.object_props.set_context_xsd_any_uri(context())?;
+  // TODO: seems like the create activity needs its own id (and be fetchable there)
+  create
+    .object_props
+    .set_id(page.object_props.get_id().unwrap().to_string())?;
+  create.create_props.set_actor_xsd_any_uri(user.actor_id)?;
+  create.create_props.set_object_base_box(page)?;
+  let json = serde_json::to_string(&create)?;
+  for i in get_following_instances() {
+    let inbox = format!(
+      "{}://{}/federation/inbox",
+      get_apub_protocol_string(),
+      i.domain
+    );
+    let res = Request::post(inbox)
+      .header("Content-Type", "application/json")
+      .body(json.to_owned())?
+      .send()?;
+    dbg!(res);
+  }
+  Ok(())
+}
diff --git a/server/src/apub/inbox.rs b/server/src/apub/inbox.rs
new file mode 100644 (file)
index 0000000..53da497
--- /dev/null
@@ -0,0 +1,25 @@
+use crate::db::post::{Post, PostForm};
+use crate::db::Crud;
+use activitystreams::activity::Create;
+use activitystreams::object::Page;
+use actix_web::{web, HttpResponse};
+use diesel::r2d2::{ConnectionManager, Pool};
+use diesel::PgConnection;
+use failure::Error;
+
+pub async fn inbox(
+  create: web::Json<Create>,
+  db: web::Data<Pool<ConnectionManager<PgConnection>>>,
+) -> Result<HttpResponse, Error> {
+  let page = create
+    .create_props
+    .get_object_base_box()
+    .unwrap()
+    .to_owned()
+    .to_concrete::<Page>()?;
+  let post = PostForm::from_page(&page, &db.get().unwrap())?;
+  Post::create(&db.get().unwrap(), &post)?;
+  // TODO: send the new post out via websocket
+  dbg!(&post);
+  Ok(HttpResponse::Ok().finish())
+}
index c9d5e0e57fb3a767054acf219442428343d155d6..eb3097c7a363fe47f9a4e3d44b76fe7fe6905ad6 100644 (file)
@@ -1,4 +1,6 @@
+pub mod activities;
 pub mod community;
+pub mod inbox;
 pub mod post;
 pub mod puller;
 pub mod user;
index 198d9d2fad819814a39f357d988197652df69017..8458e8c9174a69b25567ae3f0ca94e8b2600d212 100644 (file)
@@ -1,6 +1,7 @@
-use crate::apub::puller::fetch_remote_user;
+use crate::apub::puller::{fetch_remote_community, fetch_remote_user};
 use crate::apub::{create_apub_response, make_apub_endpoint, EndpointType};
 use crate::convert_datetime;
+use crate::db::community::Community;
 use crate::db::post::{Post, PostForm};
 use crate::db::user::User_;
 use crate::db::Crud;
@@ -34,6 +35,7 @@ impl Post {
     let mut page = Page::default();
     let oprops: &mut ObjectProperties = page.as_mut();
     let creator = User_::read(conn, self.creator_id)?;
+    let community = Community::read(conn, self.community_id)?;
 
     oprops
       // Not needed when the Post is embedded in a collection (like for community outbox)
@@ -41,6 +43,7 @@ impl Post {
       .set_id(base_url)?
       .set_name_xsd_string(self.name.to_owned())?
       .set_published(convert_datetime(self.published))?
+      .set_to_xsd_any_uri(community.actor_id)?
       .set_attributed_to_xsd_any_uri(make_apub_endpoint(EndpointType::User, &creator.name))?;
 
     if let Some(body) = &self.body {
@@ -65,14 +68,17 @@ impl Post {
 impl PostForm {
   pub fn from_page(page: &Page, conn: &PgConnection) -> Result<PostForm, Error> {
     let oprops = &page.object_props;
-    let apub_id = Url::parse(&oprops.get_attributed_to_xsd_any_uri().unwrap().to_string())?;
-    let creator = fetch_remote_user(&apub_id, conn)?;
+    let creator_id = Url::parse(&oprops.get_attributed_to_xsd_any_uri().unwrap().to_string())?;
+    let creator = fetch_remote_user(&creator_id, conn)?;
+    let community_id = Url::parse(&oprops.get_to_xsd_any_uri().unwrap().to_string())?;
+    let community = fetch_remote_community(&community_id, conn)?;
+
     Ok(PostForm {
       name: oprops.get_name_xsd_string().unwrap().to_string(),
       url: oprops.get_url_xsd_any_uri().map(|u| u.to_string()),
       body: oprops.get_content_xsd_string().map(|c| c.to_string()),
       creator_id: creator.id,
-      community_id: -1,
+      community_id: community.id,
       removed: None,
       locked: None,
       published: oprops
index a00f4d46896b2f04b1446f8eb69ee88de088d1d4..3e9b6a9d1987797025062659bd5b7c6662a0506d 100644 (file)
@@ -91,8 +91,7 @@ fn fetch_remote_community_posts(
         PostForm::from_page(&page, conn)
       })
       .map(|pf: Result<PostForm, Error>| -> Result<Post, Error> {
-        let mut pf2 = pf?;
-        pf2.community_id = community.id;
+        let pf2 = pf?;
         let existing = Post::read_from_apub_id(conn, &pf2.ap_id);
         match existing {
           Err(NotFound {}) => Ok(Post::create(conn, &pf2)?),
@@ -104,6 +103,7 @@ fn fetch_remote_community_posts(
   )
 }
 
+// TODO: can probably merge these two methods?
 pub fn fetch_remote_user(apub_id: &Url, conn: &PgConnection) -> Result<User_, Error> {
   let person = fetch_remote_object::<PersonExt>(apub_id)?;
   let uf = UserForm::from_person(&person)?;
@@ -114,6 +114,16 @@ pub fn fetch_remote_user(apub_id: &Url, conn: &PgConnection) -> Result<User_, Er
     Err(e) => return Err(Error::from(e)),
   })
 }
+pub fn fetch_remote_community(apub_id: &Url, conn: &PgConnection) -> Result<Community, Error> {
+  let group = fetch_remote_object::<GroupExt>(apub_id)?;
+  let cf = CommunityForm::from_group(&group, conn)?;
+  let existing = Community::read_from_actor_id(conn, &cf.actor_id);
+  Ok(match existing {
+    Err(NotFound {}) => Community::create(conn, &cf)?,
+    Ok(u) => Community::update(conn, u.id, &cf)?,
+    Err(e) => return Err(Error::from(e)),
+  })
+}
 
 // TODO: in the future, this should only be done when an instance is followed for the first time
 //       after that, we should rely in the inbox, and fetch on demand when needed
index 28041d31288d51bb92147defd6d4cb82e401468e..64cc5a814dfe2f91e26ec7c367375fff7de3265d 100644 (file)
@@ -1,12 +1,6 @@
-use crate::api::community::ListCommunities;
-use crate::api::Oper;
-use crate::api::Perform;
 use crate::apub;
 use crate::settings::Settings;
-use actix_web::web::Query;
-use actix_web::{web, HttpResponse};
-use diesel::r2d2::{ConnectionManager, Pool};
-use diesel::PgConnection;
+use actix_web::web;
 
 pub fn config(cfg: &mut web::ServiceConfig) {
   if Settings::get().federation.enabled {
@@ -16,6 +10,8 @@ pub fn config(cfg: &mut web::ServiceConfig) {
         "/federation/communities",
         web::get().to(apub::community::get_apub_community_list),
       )
+      // TODO: need a proper actor that has this inbox
+      .route("/federation/inbox", web::post().to(apub::inbox::inbox))
       .route(
         "/federation/c/{community_name}",
         web::get().to(apub::community::get_apub_community_http),
@@ -35,20 +31,6 @@ pub fn config(cfg: &mut web::ServiceConfig) {
       .route(
         "/federation/p/{post_id}",
         web::get().to(apub::user::get_apub_user),
-      )
-      // TODO: we should be able to remove this but somehow that breaks the remote community list
-      .route(
-        "/api/v1/communities/list",
-        web::get().to(
-          |query: Query<ListCommunities>, db: web::Data<Pool<ConnectionManager<PgConnection>>>| {
-            let res = Oper::new(query.into_inner())
-              .perform(&db.get().unwrap())
-              .unwrap();
-            HttpResponse::Ok()
-              .content_type("application/json")
-              .body(serde_json::to_string(&res).unwrap())
-          },
-        ),
       );
   }
 }