@ -1,29 +1,24 @@
use crate ::{
apub ::{
activities ::{ populate_object_props , send_activity } ,
create_apub_response , create_apub_tombstone_response , create_tombstone ,
extensions ::group_extensions ::GroupExtension ,
fetcher ::get_or_fetch_and_upsert_remote_user ,
get_shared_inbox , insert_activity , ActorType , FromApub , GroupExt , ToApub ,
activities ::send_activity , create_apub_response , create_apub_tombstone_response ,
create_tombstone , extensions ::group_extensions ::GroupExtension ,
fetcher ::get_or_fetch_and_upsert_remote_user , get_shared_inbox , insert_activity , ActorType ,
FromApub , GroupExt , ToApub ,
} ,
blocking ,
routes ::DbPoolParam ,
DbPool , LemmyError ,
} ;
use activitystreams ::{
activity ::{ Accept , Announce , Delete , Remove , Undo } ,
Activity , Base , BaseBox ,
} ;
use activitystreams_ext ::Ext2 ;
use activitystreams_new ::{
activity ::Follow ,
activity ::{ Accept , Announce , Delete , Follow , Remove , Undo } ,
actor ::{ kind ::GroupType , ApActor , Endpoints , Group } ,
base ::BaseExt ,
base ::{ AnyBase , BaseExt } ,
collection ::UnorderedCollection ,
context ,
object ::Tombstone ,
prelude ::* ,
p rimitives::{ XsdAnyUri , XsdDateTime } ,
p ublic ,
} ;
use actix_web ::{ body ::Body , client ::Client , web , HttpResponse } ;
use itertools ::Itertools ;
@ -34,8 +29,8 @@ use lemmy_db::{
user ::User_ ,
} ;
use lemmy_utils ::convert_datetime ;
use serde ::{ Deserialize , Serialize } ;
use std::{ fmt ::Debug , str ::FromStr } ;
use serde ::Deserialize ;
use url::Url ;
#[ derive(Deserialize) ]
pub struct CommunityQuery {
@ -62,13 +57,13 @@ impl ToApub for Community {
let mut group = Group ::new ( ) ;
group
. set_context ( context ( ) )
. set_id ( XsdAnyUri::from_str ( & self . actor_id ) ? )
. set_id ( Url::parse ( & self . actor_id ) ? )
. set_name ( self . name . to_owned ( ) )
. set_published ( XsdDateTime::from ( convert_datetime( self . published ) ) )
. set_published ( convert_datetime( self . published ) )
. set_many_attributed_tos ( moderators ) ;
if let Some ( u ) = self . updated . to_owned ( ) {
group . set_updated ( XsdDateTime::from ( convert_datetime( u ) ) ) ;
group . set_updated ( convert_datetime( u ) ) ;
}
if let Some ( d ) = self . description . to_owned ( ) {
// TODO: this should be html, also add source field with raw markdown
@ -107,14 +102,14 @@ impl ToApub for Community {
self . deleted ,
& self . actor_id ,
self . updated ,
GroupType . to_string ( ) ,
GroupType ::Group . to_string ( ) ,
)
}
}
#[ async_trait::async_trait(?Send) ]
impl ActorType for Community {
fn actor_id ( & self ) -> String {
fn actor_id _str ( & self ) -> String {
self . actor_id . to_owned ( )
}
@ -128,27 +123,23 @@ impl ActorType for Community {
/// As a local community, accept the follow request from a remote user.
async fn send_accept_follow (
& self ,
follow : & Follow ,
follow : Follow ,
client : & Client ,
pool : & DbPool ,
) -> Result < ( ) , LemmyError > {
let actor_uri = follow . actor .as_single_xsd_any_uri ( ) . unwrap ( ) . to_string ( ) ;
let actor_uri = follow . actor () ? .as_single_xsd_any_uri ( ) . unwrap ( ) . to_string ( ) ;
let id = format! ( "{}/accept/{}" , self . actor_id , uuid ::Uuid ::new_v4 ( ) ) ;
let mut accept = Accept ::new ( ) ;
accept
. object_props
. set_context_xsd_any_uri ( context ( ) ) ?
. set_id ( id ) ? ;
accept
. accept_props
. set_actor_xsd_any_uri ( self . actor_id . to_owned ( ) ) ?
. set_object_base_box ( BaseBox ::from_concrete ( follow . clone ( ) ) ? ) ? ;
let mut accept = Accept ::new ( self . actor_id . to_owned ( ) , follow . into_any_base ( ) ? ) ;
let to = format! ( "{}/inbox" , actor_uri ) ;
accept
. set_context ( context ( ) )
. set_id ( Url ::parse ( & id ) ? )
. set_to ( to . clone ( ) ) ;
insert_activity ( self . creator_id , accept . clone ( ) , true , pool ) . await ? ;
send_activity ( client , & accept , self , vec! [ to ] ) . await ? ;
send_activity ( client , & accept .into_any_base ( ) ? , self , vec! [ to ] ) . await ? ;
Ok ( ( ) )
}
@ -162,17 +153,12 @@ impl ActorType for Community {
let id = format! ( "{}/delete/{}" , self . actor_id , uuid ::Uuid ::new_v4 ( ) ) ;
let mut delete = Delete ::default ( ) ;
populate_object_props (
& mut delete . object_props ,
vec! [ self . get_followers_url ( ) ] ,
& id ,
) ? ;
let mut delete = Delete ::new ( creator . actor_id . to_owned ( ) , group . into_any_base ( ) ? ) ;
delete
. delete_props
. set_actor_xsd_any_uri ( creator . actor_id . to_owned ( ) ) ?
. set_object_base_box ( BaseBox ::from_concrete ( group ) ? ) ? ;
. set_context ( context ( ) )
. set_id ( Url ::parse ( & id ) ? )
. set_to ( public ( ) )
. set_many_ccs ( vec! [ self . get_followers_url ( ) ] ) ;
insert_activity ( self . creator_id , delete . clone ( ) , true , pool ) . await ? ;
@ -181,7 +167,7 @@ impl ActorType for Community {
// Note: For an accept, since it was automatic, no one pushed a button,
// the community was the actor.
// But for delete, the creator is the actor, and does the signing
send_activity ( client , & delete , creator , inboxes ) . await ? ;
send_activity ( client , & delete .into_any_base ( ) ? , creator , inboxes ) . await ? ;
Ok ( ( ) )
}
@ -195,33 +181,22 @@ impl ActorType for Community {
let id = format! ( "{}/delete/{}" , self . actor_id , uuid ::Uuid ::new_v4 ( ) ) ;
let mut delete = Delete ::default ( ) ;
populate_object_props (
& mut delete . object_props ,
vec! [ self . get_followers_url ( ) ] ,
& id ,
) ? ;
let mut delete = Delete ::new ( creator . actor_id . to_owned ( ) , group . into_any_base ( ) ? ) ;
delete
. delete_props
. set_actor_xsd_any_uri ( creator . actor_id . to_owned ( ) ) ?
. set_object_base_box ( BaseBox ::from_concrete ( group ) ? ) ? ;
. set_context ( context ( ) )
. set_id ( Url ::parse ( & id ) ? )
. set_to ( public ( ) )
. set_many_ccs ( vec! [ self . get_followers_url ( ) ] ) ;
// TODO
// Undo that fake activity
let undo_id = format! ( "{}/undo/delete/{}" , self . actor_id , uuid ::Uuid ::new_v4 ( ) ) ;
let mut undo = Undo ::default ( ) ;
populate_object_props (
& mut undo . object_props ,
vec! [ self . get_followers_url ( ) ] ,
& undo_id ,
) ? ;
let mut undo = Undo ::new ( creator . actor_id . to_owned ( ) , delete . into_any_base ( ) ? ) ;
undo
. undo_props
. set_actor_xsd_any_uri ( creator . actor_id . to_owned ( ) ) ?
. set_object_base_box ( delete ) ? ;
. set_context ( context ( ) )
. set_id ( Url ::parse ( & undo_id ) ? )
. set_to ( public ( ) )
. set_many_ccs ( vec! [ self . get_followers_url ( ) ] ) ;
insert_activity ( self . creator_id , undo . clone ( ) , true , pool ) . await ? ;
@ -230,7 +205,7 @@ impl ActorType for Community {
// Note: For an accept, since it was automatic, no one pushed a button,
// the community was the actor.
// But for delete, the creator is the actor, and does the signing
send_activity ( client , & undo , creator , inboxes ) . await ? ;
send_activity ( client , & undo .into_any_base ( ) ? , creator , inboxes ) . await ? ;
Ok ( ( ) )
}
@ -244,17 +219,12 @@ impl ActorType for Community {
let id = format! ( "{}/remove/{}" , self . actor_id , uuid ::Uuid ::new_v4 ( ) ) ;
let mut remove = Remove ::default ( ) ;
populate_object_props (
& mut remove . object_props ,
vec! [ self . get_followers_url ( ) ] ,
& id ,
) ? ;
let mut remove = Remove ::new ( mod_ . actor_id . to_owned ( ) , group . into_any_base ( ) ? ) ;
remove
. remove_props
. set_actor_xsd_any_uri ( mod_ . actor_id . to_owned ( ) ) ?
. set_object_base_box ( BaseBox ::from_concrete ( group ) ? ) ? ;
. set_context ( context ( ) )
. set_id ( Url ::parse ( & id ) ? )
. set_to ( public ( ) )
. set_many_ccs ( vec! [ self . get_followers_url ( ) ] ) ;
insert_activity ( mod_ . id , remove . clone ( ) , true , pool ) . await ? ;
@ -263,7 +233,7 @@ impl ActorType for Community {
// Note: For an accept, since it was automatic, no one pushed a button,
// the community was the actor.
// But for delete, the creator is the actor, and does the signing
send_activity ( client , & remove , mod_ , inboxes ) . await ? ;
send_activity ( client , & remove .into_any_base ( ) ? , mod_ , inboxes ) . await ? ;
Ok ( ( ) )
}
@ -277,32 +247,21 @@ impl ActorType for Community {
let id = format! ( "{}/remove/{}" , self . actor_id , uuid ::Uuid ::new_v4 ( ) ) ;
let mut remove = Remove ::default ( ) ;
populate_object_props (
& mut remove . object_props ,
vec! [ self . get_followers_url ( ) ] ,
& id ,
) ? ;
let mut remove = Remove ::new ( mod_ . actor_id . to_owned ( ) , group . into_any_base ( ) ? ) ;
remove
. remove_props
. set_actor_xsd_any_uri ( mod_ . actor_id . to_owned ( ) ) ?
. set_object_base_box ( BaseBox ::from_concrete ( group ) ? ) ? ;
. set_context ( context ( ) )
. set_id ( Url ::parse ( & id ) ? )
. set_to ( public ( ) )
. set_many_ccs ( vec! [ self . get_followers_url ( ) ] ) ;
// Undo that fake activity
let undo_id = format! ( "{}/undo/remove/{}" , self . actor_id , uuid ::Uuid ::new_v4 ( ) ) ;
let mut undo = Undo ::default ( ) ;
populate_object_props (
& mut undo . object_props ,
vec! [ self . get_followers_url ( ) ] ,
& undo_id ,
) ? ;
let mut undo = Undo ::new ( mod_ . actor_id . to_owned ( ) , remove . into_any_base ( ) ? ) ;
undo
. undo_props
. set_actor_xsd_any_uri ( mod_ . actor_id . to_owned ( ) ) ?
. set_object_base_box ( remove ) ? ;
. set_context ( context ( ) )
. set_id ( Url ::parse ( & undo_id ) ? )
. set_to ( public ( ) )
. set_many_ccs ( vec! [ self . get_followers_url ( ) ] ) ;
insert_activity ( mod_ . id , undo . clone ( ) , true , pool ) . await ? ;
@ -311,7 +270,7 @@ impl ActorType for Community {
// Note: For an accept, since it was automatic, no one pushed a button,
// the community was the actor.
// But for remove , the creator is the actor, and does the signing
send_activity ( client , & undo , mod_ , inboxes ) . await ? ;
send_activity ( client , & undo .into_any_base ( ) ? , mod_ , inboxes ) . await ? ;
Ok ( ( ) )
}
@ -325,7 +284,7 @@ impl ActorType for Community {
. await ? ? ;
let inboxes = inboxes
. into_iter ( )
. map ( | c | get_shared_inbox ( & c. user_actor_id ) )
. map ( | c | get_shared_inbox ( & Url::parse ( & c. user_actor_id ) . unwrap ( ) ) )
. filter ( | s | ! s . is_empty ( ) )
. unique ( )
. collect ( ) ;
@ -357,8 +316,13 @@ impl FromApub for CommunityForm {
type ApubType = GroupExt ;
/// Parse an ActivityPub group received from another instance into a Lemmy community.
async fn from_apub ( group : & GroupExt , client : & Client , pool : & DbPool ) -> Result < Self , LemmyError > {
let creator_and_moderator_uris = group . attributed_to ( ) . unwrap ( ) ;
async fn from_apub (
group : & GroupExt ,
client : & Client ,
pool : & DbPool ,
actor_id : & Url ,
) -> Result < Self , LemmyError > {
let creator_and_moderator_uris = group . inner . attributed_to ( ) . unwrap ( ) ;
let creator_uri = creator_and_moderator_uris
. as_many ( )
. unwrap ( )
@ -371,23 +335,34 @@ impl FromApub for CommunityForm {
let creator = get_or_fetch_and_upsert_remote_user ( creator_uri , client , pool ) . await ? ;
Ok ( CommunityForm {
name : group . name ( ) . unwrap ( ) . as_single_xsd_string ( ) . unwrap ( ) . into ( ) ,
name : group
. inner
. name ( )
. unwrap ( )
. as_one ( )
. unwrap ( )
. as_xsd_string ( )
. unwrap ( )
. into ( ) ,
title : group . inner . preferred_username ( ) . unwrap ( ) . to_string ( ) ,
// TODO: should be parsed as html and tags like <script> removed (or use markdown source)
// -> same for post.content etc
description : group
. inner
. content ( )
. map ( | s | s . as_single_xsd_string ( ) . unwrap ( ) . into ( ) ) ,
category_id : group . ext_one . category . identifier . parse ::< i32 > ( ) ? ,
creator_id : creator . id ,
removed : None ,
published : group
. published ( )
. map ( | u | u . as_ref ( ) . to_owned ( ) . naive_local ( ) ) ,
updated : group . updated ( ) . map ( | u | u . as_ref ( ) . to_owned ( ) . naive_local ( ) ) ,
published : group . inner . published ( ) . map ( | u | u . to_owned ( ) . naive_local ( ) ) ,
updated : group . inner . updated ( ) . map ( | u | u . to_owned ( ) . naive_local ( ) ) ,
deleted : None ,
nsfw : group . ext_one . sensitive ,
actor_id : group . id ( ) . unwrap ( ) . to_string ( ) ,
actor_id : group
. inner
. id ( actor_id . domain ( ) . unwrap ( ) ) ?
. unwrap ( )
. to_string ( ) ,
local : false ,
private_key : None ,
public_key : Some ( group . ext_two . to_owned ( ) . public_key . public_key_pem ) ,
@ -440,26 +415,20 @@ pub async fn get_apub_community_followers(
Ok ( create_apub_response ( & collection ) )
}
pub async fn do_announce < A > (
activity : A ,
pub async fn do_announce (
activity : A nyBase ,
community : & Community ,
sender : & dyn ActorType ,
client : & Client ,
pool : & DbPool ,
) -> Result < HttpResponse , LemmyError >
where
A : Activity + Base + Serialize + Debug ,
{
let mut announce = Announce ::default ( ) ;
populate_object_props (
& mut announce . object_props ,
vec! [ community . get_followers_url ( ) ] ,
& format! ( "{}/announce/{}" , community . actor_id , uuid ::Uuid ::new_v4 ( ) ) ,
) ? ;
) -> Result < HttpResponse , LemmyError > {
let id = format! ( "{}/announce/{}" , community . actor_id , uuid ::Uuid ::new_v4 ( ) ) ;
let mut announce = Announce ::new ( community . actor_id . to_owned ( ) , activity ) ;
announce
. announce_props
. set_actor_xsd_any_uri ( community . actor_id . to_owned ( ) ) ?
. set_object_base_box ( BaseBox ::from_concrete ( activity ) ? ) ? ;
. set_context ( context ( ) )
. set_id ( Url ::parse ( & id ) ? )
. set_to ( public ( ) )
. set_many_ccs ( vec! [ community . get_followers_url ( ) ] ) ;
insert_activity ( community . creator_id , announce . clone ( ) , true , pool ) . await ? ;
@ -470,7 +439,7 @@ where
// this seems to be the "easiest" stable alternative for remove_item()
to . retain ( | x | * x ! = sender . get_shared_inbox_url ( ) ) ;
send_activity ( client , & announce , community , to ) . await ? ;
send_activity ( client , & announce .into_any_base ( ) ? , community , to ) . await ? ;
Ok ( HttpResponse ::Ok ( ) . finish ( ) )
}