diff --git a/docker/federation/run-federation-test.bash b/docker/federation/run-federation-test.bash index 62bc1e8bf..2c8b681ce 100755 --- a/docker/federation/run-federation-test.bash +++ b/docker/federation/run-federation-test.bash @@ -3,6 +3,7 @@ set -e if [ "$1" = "-yarn" ]; then pushd ../../ui/ || exit + yarn yarn build popd || exit fi @@ -13,4 +14,4 @@ popd || exit sudo docker build ../../ -f Dockerfile -t lemmy-federation:latest -sudo docker-compose up \ No newline at end of file +sudo docker-compose up diff --git a/server/src/apub/activities.rs b/server/src/apub/activities.rs index a1707267c..2e35400d0 100644 --- a/server/src/apub/activities.rs +++ b/server/src/apub/activities.rs @@ -1,5 +1,5 @@ -use crate::apub::{get_apub_protocol_string, get_following_instances}; use crate::db::community::Community; +use crate::db::community_view::CommunityFollowerView; use crate::db::post::Post; use crate::db::user::User_; use crate::db::Crud; @@ -46,18 +46,14 @@ where Ok(()) } -fn get_followers(_community: &Community) -> Vec { - // TODO: this is wrong, needs to go to the (non-local) followers of the community - get_following_instances() - .iter() - .map(|i| { - format!( - "{}://{}/federation/inbox", - get_apub_protocol_string(), - i.domain - ) - }) - .collect() +fn get_followers(conn: &PgConnection, community: &Community) -> Result, Error> { + Ok( + CommunityFollowerView::for_community(conn, community.id)? + .iter() + .filter(|c| !c.user_local) + .map(|c| format!("{}/inbox", c.user_actor_id.to_owned())) + .collect(), + ) } pub fn post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> { @@ -73,7 +69,7 @@ pub fn post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result< .create_props .set_actor_xsd_any_uri(creator.actor_id.to_owned())? .set_object_base_box(page)?; - send_activity(&create, get_followers(&community))?; + send_activity(&create, get_followers(conn, &community)?)?; Ok(()) } @@ -90,7 +86,7 @@ pub fn post_update(post: &Post, creator: &User_, conn: &PgConnection) -> Result< .update_props .set_actor_xsd_any_uri(creator.actor_id.to_owned())? .set_object_base_box(page)?; - send_activity(&update, get_followers(&community))?; + send_activity(&update, get_followers(conn, &community)?)?; Ok(()) } diff --git a/server/src/apub/community_inbox.rs b/server/src/apub/community_inbox.rs new file mode 100644 index 000000000..0fe3fd709 --- /dev/null +++ b/server/src/apub/community_inbox.rs @@ -0,0 +1,53 @@ +use crate::apub::activities::accept_follow; +use crate::apub::fetcher::fetch_remote_user; +use crate::db::community::{Community, CommunityFollower, CommunityFollowerForm}; +use crate::db::Followable; +use activitystreams::activity::Follow; +use actix_web::{web, HttpResponse}; +use diesel::r2d2::{ConnectionManager, Pool}; +use diesel::PgConnection; +use failure::Error; +use url::Url; + +#[serde(untagged)] +#[derive(serde::Deserialize)] +pub enum CommunityAcceptedObjects { + Follow(Follow), +} + +pub async fn community_inbox( + input: web::Json, + db: web::Data>>, +) -> Result { + let input = input.into_inner(); + let conn = &db.get().unwrap(); + match input { + CommunityAcceptedObjects::Follow(f) => handle_follow(&f, conn), + } +} + +fn handle_follow(follow: &Follow, conn: &PgConnection) -> Result { + println!("received follow: {:?}", &follow); + + // TODO: make sure this is a local community + let community_uri = follow + .follow_props + .get_object_xsd_any_uri() + .unwrap() + .to_string(); + let community = Community::read_from_actor_id(conn, &community_uri)?; + let user_uri = follow + .follow_props + .get_actor_xsd_any_uri() + .unwrap() + .to_string(); + let user = fetch_remote_user(&Url::parse(&user_uri)?, conn)?; + // TODO: insert ID of the user into follows of the community + let community_follower_form = CommunityFollowerForm { + community_id: community.id, + user_id: user.id, + }; + CommunityFollower::follow(&conn, &community_follower_form)?; + accept_follow(&follow)?; + Ok(HttpResponse::Ok().finish()) +} diff --git a/server/src/apub/inbox.rs b/server/src/apub/inbox.rs deleted file mode 100644 index a2db335a8..000000000 --- a/server/src/apub/inbox.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::apub::activities::accept_follow; -use crate::apub::fetcher::fetch_remote_user; -use crate::db::community::{Community, CommunityFollower, CommunityFollowerForm}; -use crate::db::post::{Post, PostForm}; -use crate::db::Crud; -use crate::db::Followable; -use activitystreams::activity::{Accept, Create, Follow, Update}; -use activitystreams::object::Page; -use actix_web::{web, HttpResponse}; -use diesel::r2d2::{ConnectionManager, Pool}; -use diesel::PgConnection; -use failure::Error; -use url::Url; - -// TODO: need a proper actor that has this inbox - -pub async fn inbox( - input: web::Json, - db: web::Data>>, -) -> Result { - // TODO: make sure that things are received in the correct inbox - // (by using seperate handler functions and checking the user/community name in the path) - let input = input.into_inner(); - let conn = &db.get().unwrap(); - match input { - AcceptedObjects::Create(c) => handle_create(&c, conn), - AcceptedObjects::Update(u) => handle_update(&u, conn), - AcceptedObjects::Follow(f) => handle_follow(&f, conn), - AcceptedObjects::Accept(a) => handle_accept(&a, conn), - } -} - -fn handle_create(create: &Create, conn: &PgConnection) -> Result { - let page = create - .create_props - .get_object_base_box() - .to_owned() - .unwrap() - .to_owned() - .to_concrete::()?; - let post = PostForm::from_page(&page, conn)?; - Post::create(conn, &post)?; - // TODO: send the new post out via websocket - Ok(HttpResponse::Ok().finish()) -} - -fn handle_update(update: &Update, conn: &PgConnection) -> Result { - let page = update - .update_props - .get_object_base_box() - .to_owned() - .unwrap() - .to_owned() - .to_concrete::()?; - let post = PostForm::from_page(&page, conn)?; - let id = Post::read_from_apub_id(conn, &post.ap_id)?.id; - Post::update(conn, id, &post)?; - // TODO: send the new post out via websocket - Ok(HttpResponse::Ok().finish()) -} - -fn handle_follow(follow: &Follow, conn: &PgConnection) -> Result { - println!("received follow: {:?}", &follow); - - // TODO: make sure this is a local community - let community_uri = follow - .follow_props - .get_object_xsd_any_uri() - .unwrap() - .to_string(); - let community = Community::read_from_actor_id(conn, &community_uri)?; - let user_uri = follow - .follow_props - .get_actor_xsd_any_uri() - .unwrap() - .to_string(); - let user = fetch_remote_user(&Url::parse(&user_uri)?, conn)?; - // TODO: insert ID of the user into follows of the community - let community_follower_form = CommunityFollowerForm { - community_id: community.id, - user_id: user.id, - }; - CommunityFollower::follow(&conn, &community_follower_form)?; - accept_follow(&follow)?; - Ok(HttpResponse::Ok().finish()) -} - -fn handle_accept(accept: &Accept, _conn: &PgConnection) -> Result { - println!("received accept: {:?}", &accept); - // TODO: at this point, indicate to the user that they are following the community - Ok(HttpResponse::Ok().finish()) -} - -#[serde(untagged)] -#[derive(serde::Deserialize)] -pub enum AcceptedObjects { - Create(Create), - Update(Update), - Follow(Follow), - Accept(Accept), -} diff --git a/server/src/apub/mod.rs b/server/src/apub/mod.rs index b2d157ae8..11b513beb 100644 --- a/server/src/apub/mod.rs +++ b/server/src/apub/mod.rs @@ -1,10 +1,11 @@ pub mod activities; pub mod community; +pub mod community_inbox; pub mod fetcher; -pub mod inbox; pub mod post; pub mod signatures; pub mod user; +pub mod user_inbox; use crate::apub::signatures::PublicKeyExtension; use crate::Settings; use activitystreams::actor::{properties::ApActorProperties, Group, Person}; diff --git a/server/src/apub/user_inbox.rs b/server/src/apub/user_inbox.rs new file mode 100644 index 000000000..02517afe0 --- /dev/null +++ b/server/src/apub/user_inbox.rs @@ -0,0 +1,64 @@ +use crate::db::post::{Post, PostForm}; +use crate::db::Crud; +use activitystreams::activity::{Accept, Create, Update}; +use activitystreams::object::Page; +use actix_web::{web, HttpResponse}; +use diesel::r2d2::{ConnectionManager, Pool}; +use diesel::PgConnection; +use failure::Error; + +#[serde(untagged)] +#[derive(serde::Deserialize)] +pub enum UserAcceptedObjects { + Create(Create), + Update(Update), + Accept(Accept), +} + +pub async fn user_inbox( + input: web::Json, + db: web::Data>>, +) -> Result { + let input = input.into_inner(); + let conn = &db.get().unwrap(); + match input { + UserAcceptedObjects::Create(c) => handle_create(&c, conn), + UserAcceptedObjects::Update(u) => handle_update(&u, conn), + UserAcceptedObjects::Accept(a) => handle_accept(&a, conn), + } +} + +fn handle_create(create: &Create, conn: &PgConnection) -> Result { + let page = create + .create_props + .get_object_base_box() + .to_owned() + .unwrap() + .to_owned() + .to_concrete::()?; + let post = PostForm::from_page(&page, conn)?; + Post::create(conn, &post)?; + // TODO: send the new post out via websocket + Ok(HttpResponse::Ok().finish()) +} + +fn handle_update(update: &Update, conn: &PgConnection) -> Result { + let page = update + .update_props + .get_object_base_box() + .to_owned() + .unwrap() + .to_owned() + .to_concrete::()?; + let post = PostForm::from_page(&page, conn)?; + let id = Post::read_from_apub_id(conn, &post.ap_id)?.id; + Post::update(conn, id, &post)?; + // TODO: send the new post out via websocket + Ok(HttpResponse::Ok().finish()) +} + +fn handle_accept(accept: &Accept, _conn: &PgConnection) -> Result { + println!("received accept: {:?}", &accept); + // TODO: at this point, indicate to the user that they are following the community + Ok(HttpResponse::Ok().finish()) +} diff --git a/server/src/routes/federation.rs b/server/src/routes/federation.rs index 2798e7a95..6c7cce8a8 100644 --- a/server/src/routes/federation.rs +++ b/server/src/routes/federation.rs @@ -10,15 +10,14 @@ pub fn config(cfg: &mut web::ServiceConfig) { "/federation/communities", web::get().to(apub::community::get_apub_community_list), ) - // TODO: this needs to be moved to the actors (eg /federation/u/{}/inbox) - .route("/federation/inbox", web::post().to(apub::inbox::inbox)) + // TODO: check the user/community params for these .route( "/federation/c/{_}/inbox", - web::post().to(apub::inbox::inbox), + web::post().to(apub::community_inbox::community_inbox), ) .route( "/federation/u/{_}/inbox", - web::post().to(apub::inbox::inbox), + web::post().to(apub::user_inbox::user_inbox), ) .route( "/federation/c/{community_name}",