Implement create activity
This commit is contained in:
parent
f5b58bcdaf
commit
0b617377df
7 changed files with 91 additions and 27 deletions
|
@ -1,4 +1,5 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::apub::activities::post_create;
|
||||||
use diesel::PgConnection;
|
use diesel::PgConnection;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
@ -153,6 +154,8 @@ impl Perform<PostResponse> for Oper<CreatePost> {
|
||||||
Err(_e) => return Err(APIError::err("couldnt_create_post").into()),
|
Err(_e) => return Err(APIError::err("couldnt_create_post").into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
post_create(&inserted_post, conn)?;
|
||||||
|
|
||||||
// They like their own post by default
|
// They like their own post by default
|
||||||
let like_form = PostLikeForm {
|
let like_form = PostLikeForm {
|
||||||
post_id: inserted_post.id,
|
post_id: inserted_post.id,
|
||||||
|
|
36
server/src/apub/activities.rs
Normal file
36
server/src/apub/activities.rs
Normal file
|
@ -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(())
|
||||||
|
}
|
25
server/src/apub/inbox.rs
Normal file
25
server/src/apub/inbox.rs
Normal file
|
@ -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())
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
|
pub mod activities;
|
||||||
pub mod community;
|
pub mod community;
|
||||||
|
pub mod inbox;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
pub mod puller;
|
pub mod puller;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
|
@ -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::apub::{create_apub_response, make_apub_endpoint, EndpointType};
|
||||||
use crate::convert_datetime;
|
use crate::convert_datetime;
|
||||||
|
use crate::db::community::Community;
|
||||||
use crate::db::post::{Post, PostForm};
|
use crate::db::post::{Post, PostForm};
|
||||||
use crate::db::user::User_;
|
use crate::db::user::User_;
|
||||||
use crate::db::Crud;
|
use crate::db::Crud;
|
||||||
|
@ -34,6 +35,7 @@ impl Post {
|
||||||
let mut page = Page::default();
|
let mut page = Page::default();
|
||||||
let oprops: &mut ObjectProperties = page.as_mut();
|
let oprops: &mut ObjectProperties = page.as_mut();
|
||||||
let creator = User_::read(conn, self.creator_id)?;
|
let creator = User_::read(conn, self.creator_id)?;
|
||||||
|
let community = Community::read(conn, self.community_id)?;
|
||||||
|
|
||||||
oprops
|
oprops
|
||||||
// Not needed when the Post is embedded in a collection (like for community outbox)
|
// 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_id(base_url)?
|
||||||
.set_name_xsd_string(self.name.to_owned())?
|
.set_name_xsd_string(self.name.to_owned())?
|
||||||
.set_published(convert_datetime(self.published))?
|
.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))?;
|
.set_attributed_to_xsd_any_uri(make_apub_endpoint(EndpointType::User, &creator.name))?;
|
||||||
|
|
||||||
if let Some(body) = &self.body {
|
if let Some(body) = &self.body {
|
||||||
|
@ -65,14 +68,17 @@ impl Post {
|
||||||
impl PostForm {
|
impl PostForm {
|
||||||
pub fn from_page(page: &Page, conn: &PgConnection) -> Result<PostForm, Error> {
|
pub fn from_page(page: &Page, conn: &PgConnection) -> Result<PostForm, Error> {
|
||||||
let oprops = &page.object_props;
|
let oprops = &page.object_props;
|
||||||
let apub_id = Url::parse(&oprops.get_attributed_to_xsd_any_uri().unwrap().to_string())?;
|
let creator_id = Url::parse(&oprops.get_attributed_to_xsd_any_uri().unwrap().to_string())?;
|
||||||
let creator = fetch_remote_user(&apub_id, conn)?;
|
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 {
|
Ok(PostForm {
|
||||||
name: oprops.get_name_xsd_string().unwrap().to_string(),
|
name: oprops.get_name_xsd_string().unwrap().to_string(),
|
||||||
url: oprops.get_url_xsd_any_uri().map(|u| u.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()),
|
body: oprops.get_content_xsd_string().map(|c| c.to_string()),
|
||||||
creator_id: creator.id,
|
creator_id: creator.id,
|
||||||
community_id: -1,
|
community_id: community.id,
|
||||||
removed: None,
|
removed: None,
|
||||||
locked: None,
|
locked: None,
|
||||||
published: oprops
|
published: oprops
|
||||||
|
|
|
@ -91,8 +91,7 @@ fn fetch_remote_community_posts(
|
||||||
PostForm::from_page(&page, conn)
|
PostForm::from_page(&page, conn)
|
||||||
})
|
})
|
||||||
.map(|pf: Result<PostForm, Error>| -> Result<Post, Error> {
|
.map(|pf: Result<PostForm, Error>| -> Result<Post, Error> {
|
||||||
let mut pf2 = pf?;
|
let pf2 = pf?;
|
||||||
pf2.community_id = community.id;
|
|
||||||
let existing = Post::read_from_apub_id(conn, &pf2.ap_id);
|
let existing = Post::read_from_apub_id(conn, &pf2.ap_id);
|
||||||
match existing {
|
match existing {
|
||||||
Err(NotFound {}) => Ok(Post::create(conn, &pf2)?),
|
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> {
|
pub fn fetch_remote_user(apub_id: &Url, conn: &PgConnection) -> Result<User_, Error> {
|
||||||
let person = fetch_remote_object::<PersonExt>(apub_id)?;
|
let person = fetch_remote_object::<PersonExt>(apub_id)?;
|
||||||
let uf = UserForm::from_person(&person)?;
|
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)),
|
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
|
// 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
|
// after that, we should rely in the inbox, and fetch on demand when needed
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
use crate::api::community::ListCommunities;
|
|
||||||
use crate::api::Oper;
|
|
||||||
use crate::api::Perform;
|
|
||||||
use crate::apub;
|
use crate::apub;
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
use actix_web::web::Query;
|
use actix_web::web;
|
||||||
use actix_web::{web, HttpResponse};
|
|
||||||
use diesel::r2d2::{ConnectionManager, Pool};
|
|
||||||
use diesel::PgConnection;
|
|
||||||
|
|
||||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||||
if Settings::get().federation.enabled {
|
if Settings::get().federation.enabled {
|
||||||
|
@ -16,6 +10,8 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||||
"/federation/communities",
|
"/federation/communities",
|
||||||
web::get().to(apub::community::get_apub_community_list),
|
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(
|
.route(
|
||||||
"/federation/c/{community_name}",
|
"/federation/c/{community_name}",
|
||||||
web::get().to(apub::community::get_apub_community_http),
|
web::get().to(apub::community::get_apub_community_http),
|
||||||
|
@ -35,20 +31,6 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||||
.route(
|
.route(
|
||||||
"/federation/p/{post_id}",
|
"/federation/p/{post_id}",
|
||||||
web::get().to(apub::user::get_apub_user),
|
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())
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue