Send activities to correct inbox, seperate community/user inboxes

This commit is contained in:
Felix 2020-04-15 20:12:25 +02:00
parent 5e0040d8c8
commit 58142e64d0
7 changed files with 135 additions and 122 deletions

View file

@ -3,6 +3,7 @@ set -e
if [ "$1" = "-yarn" ]; then if [ "$1" = "-yarn" ]; then
pushd ../../ui/ || exit pushd ../../ui/ || exit
yarn
yarn build yarn build
popd || exit popd || exit
fi fi
@ -13,4 +14,4 @@ popd || exit
sudo docker build ../../ -f Dockerfile -t lemmy-federation:latest sudo docker build ../../ -f Dockerfile -t lemmy-federation:latest
sudo docker-compose up sudo docker-compose up

View file

@ -1,5 +1,5 @@
use crate::apub::{get_apub_protocol_string, get_following_instances};
use crate::db::community::Community; use crate::db::community::Community;
use crate::db::community_view::CommunityFollowerView;
use crate::db::post::Post; use crate::db::post::Post;
use crate::db::user::User_; use crate::db::user::User_;
use crate::db::Crud; use crate::db::Crud;
@ -46,18 +46,14 @@ where
Ok(()) Ok(())
} }
fn get_followers(_community: &Community) -> Vec<String> { fn get_followers(conn: &PgConnection, community: &Community) -> Result<Vec<String>, Error> {
// TODO: this is wrong, needs to go to the (non-local) followers of the community Ok(
get_following_instances() CommunityFollowerView::for_community(conn, community.id)?
.iter() .iter()
.map(|i| { .filter(|c| !c.user_local)
format!( .map(|c| format!("{}/inbox", c.user_actor_id.to_owned()))
"{}://{}/federation/inbox", .collect(),
get_apub_protocol_string(), )
i.domain
)
})
.collect()
} }
pub fn post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> { 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 .create_props
.set_actor_xsd_any_uri(creator.actor_id.to_owned())? .set_actor_xsd_any_uri(creator.actor_id.to_owned())?
.set_object_base_box(page)?; .set_object_base_box(page)?;
send_activity(&create, get_followers(&community))?; send_activity(&create, get_followers(conn, &community)?)?;
Ok(()) Ok(())
} }
@ -90,7 +86,7 @@ pub fn post_update(post: &Post, creator: &User_, conn: &PgConnection) -> Result<
.update_props .update_props
.set_actor_xsd_any_uri(creator.actor_id.to_owned())? .set_actor_xsd_any_uri(creator.actor_id.to_owned())?
.set_object_base_box(page)?; .set_object_base_box(page)?;
send_activity(&update, get_followers(&community))?; send_activity(&update, get_followers(conn, &community)?)?;
Ok(()) Ok(())
} }

View file

@ -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<CommunityAcceptedObjects>,
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
) -> Result<HttpResponse, Error> {
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<HttpResponse, Error> {
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())
}

View file

@ -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<AcceptedObjects>,
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
) -> Result<HttpResponse, Error> {
// 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<HttpResponse, Error> {
let page = create
.create_props
.get_object_base_box()
.to_owned()
.unwrap()
.to_owned()
.to_concrete::<Page>()?;
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<HttpResponse, Error> {
let page = update
.update_props
.get_object_base_box()
.to_owned()
.unwrap()
.to_owned()
.to_concrete::<Page>()?;
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<HttpResponse, Error> {
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<HttpResponse, Error> {
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),
}

View file

@ -1,10 +1,11 @@
pub mod activities; pub mod activities;
pub mod community; pub mod community;
pub mod community_inbox;
pub mod fetcher; pub mod fetcher;
pub mod inbox;
pub mod post; pub mod post;
pub mod signatures; pub mod signatures;
pub mod user; pub mod user;
pub mod user_inbox;
use crate::apub::signatures::PublicKeyExtension; use crate::apub::signatures::PublicKeyExtension;
use crate::Settings; use crate::Settings;
use activitystreams::actor::{properties::ApActorProperties, Group, Person}; use activitystreams::actor::{properties::ApActorProperties, Group, Person};

View file

@ -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<UserAcceptedObjects>,
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
) -> Result<HttpResponse, Error> {
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<HttpResponse, Error> {
let page = create
.create_props
.get_object_base_box()
.to_owned()
.unwrap()
.to_owned()
.to_concrete::<Page>()?;
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<HttpResponse, Error> {
let page = update
.update_props
.get_object_base_box()
.to_owned()
.unwrap()
.to_owned()
.to_concrete::<Page>()?;
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<HttpResponse, Error> {
println!("received accept: {:?}", &accept);
// TODO: at this point, indicate to the user that they are following the community
Ok(HttpResponse::Ok().finish())
}

View file

@ -10,15 +10,14 @@ 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: this needs to be moved to the actors (eg /federation/u/{}/inbox) // TODO: check the user/community params for these
.route("/federation/inbox", web::post().to(apub::inbox::inbox))
.route( .route(
"/federation/c/{_}/inbox", "/federation/c/{_}/inbox",
web::post().to(apub::inbox::inbox), web::post().to(apub::community_inbox::community_inbox),
) )
.route( .route(
"/federation/u/{_}/inbox", "/federation/u/{_}/inbox",
web::post().to(apub::inbox::inbox), web::post().to(apub::user_inbox::user_inbox),
) )
.route( .route(
"/federation/c/{community_name}", "/federation/c/{community_name}",