mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-02-27 16:16:36 +00:00
wip: make site bans federate
This commit is contained in:
parent
95ac570a24
commit
136e1aee46
25 changed files with 381 additions and 110 deletions
|
@ -10,14 +10,11 @@ use lemmy_api_common::{
|
||||||
is_mod_or_admin,
|
is_mod_or_admin,
|
||||||
};
|
};
|
||||||
use lemmy_apub::{
|
use lemmy_apub::{
|
||||||
|
activities::block::SiteOrCommunity,
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
protocol::activities::{
|
protocol::activities::{
|
||||||
community::{
|
block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
|
||||||
add_mod::AddMod,
|
community::{add_mod::AddMod, remove_mod::RemoveMod},
|
||||||
block_user::BlockUserFromCommunity,
|
|
||||||
remove_mod::RemoveMod,
|
|
||||||
undo_block_user::UndoBlockUserFromCommunity,
|
|
||||||
},
|
|
||||||
following::{follow::FollowCommunity as FollowCommunityApub, undo_follow::UndoFollowCommunity},
|
following::{follow::FollowCommunity as FollowCommunityApub, undo_follow::UndoFollowCommunity},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -213,6 +210,7 @@ impl Perform for BanFromCommunity {
|
||||||
|
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
let banned_person_id = data.person_id;
|
let banned_person_id = data.person_id;
|
||||||
|
let remove_data = data.remove_data.unwrap_or(false);
|
||||||
let expires = data.expires.map(naive_from_unix);
|
let expires = data.expires.map(naive_from_unix);
|
||||||
|
|
||||||
// Verify that only mods or admins can ban
|
// Verify that only mods or admins can ban
|
||||||
|
@ -254,10 +252,11 @@ impl Perform for BanFromCommunity {
|
||||||
.await?
|
.await?
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
BlockUserFromCommunity::send(
|
BlockUser::send(
|
||||||
&community,
|
&SiteOrCommunity::Community(community),
|
||||||
&banned_person,
|
&banned_person,
|
||||||
&local_user_view.person.clone().into(),
|
&local_user_view.person.clone().into(),
|
||||||
|
remove_data,
|
||||||
expires,
|
expires,
|
||||||
context,
|
context,
|
||||||
)
|
)
|
||||||
|
@ -268,8 +267,8 @@ impl Perform for BanFromCommunity {
|
||||||
.await?
|
.await?
|
||||||
.map_err(LemmyError::from)
|
.map_err(LemmyError::from)
|
||||||
.map_err(|e| e.with_message("community_user_already_banned"))?;
|
.map_err(|e| e.with_message("community_user_already_banned"))?;
|
||||||
UndoBlockUserFromCommunity::send(
|
UndoBlockUser::send(
|
||||||
&community,
|
&SiteOrCommunity::Community(community),
|
||||||
&banned_person,
|
&banned_person,
|
||||||
&local_user_view.person.clone().into(),
|
&local_user_view.person.clone().into(),
|
||||||
context,
|
context,
|
||||||
|
@ -278,7 +277,7 @@ impl Perform for BanFromCommunity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove/Restore their data if that's desired
|
// Remove/Restore their data if that's desired
|
||||||
if data.remove_data.unwrap_or(false) {
|
if remove_data {
|
||||||
// Posts
|
// Posts
|
||||||
blocking(context.pool(), move |conn: &'_ _| {
|
blocking(context.pool(), move |conn: &'_ _| {
|
||||||
Post::update_removed_for_creator(conn, banned_person_id, Some(community_id), true)
|
Post::update_removed_for_creator(conn, banned_person_id, Some(community_id), true)
|
||||||
|
|
|
@ -14,6 +14,10 @@ use lemmy_api_common::{
|
||||||
send_password_reset_email,
|
send_password_reset_email,
|
||||||
send_verification_email,
|
send_verification_email,
|
||||||
};
|
};
|
||||||
|
use lemmy_apub::{
|
||||||
|
activities::block::SiteOrCommunity,
|
||||||
|
protocol::activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
|
||||||
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
diesel_option_overwrite,
|
diesel_option_overwrite,
|
||||||
diesel_option_overwrite_to_url,
|
diesel_option_overwrite_to_url,
|
||||||
|
@ -443,13 +447,14 @@ impl Perform for BanPerson {
|
||||||
let expires = data.expires.map(naive_from_unix);
|
let expires = data.expires.map(naive_from_unix);
|
||||||
|
|
||||||
let ban_person = move |conn: &'_ _| Person::ban_person(conn, banned_person_id, ban, expires);
|
let ban_person = move |conn: &'_ _| Person::ban_person(conn, banned_person_id, ban, expires);
|
||||||
blocking(context.pool(), ban_person)
|
let person = blocking(context.pool(), ban_person)
|
||||||
.await?
|
.await?
|
||||||
.map_err(LemmyError::from)
|
.map_err(LemmyError::from)
|
||||||
.map_err(|e| e.with_message("couldnt_update_user"))?;
|
.map_err(|e| e.with_message("couldnt_update_user"))?;
|
||||||
|
|
||||||
// Remove their data if that's desired
|
// Remove their data if that's desired
|
||||||
if data.remove_data.unwrap_or(false) {
|
let remove_data = data.remove_data.unwrap_or(false);
|
||||||
|
if remove_data {
|
||||||
// Posts
|
// Posts
|
||||||
blocking(context.pool(), move |conn: &'_ _| {
|
blocking(context.pool(), move |conn: &'_ _| {
|
||||||
Post::update_removed_for_creator(conn, banned_person_id, None, true)
|
Post::update_removed_for_creator(conn, banned_person_id, None, true)
|
||||||
|
@ -501,6 +506,31 @@ impl Perform for BanPerson {
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
let site = SiteOrCommunity::Site(
|
||||||
|
blocking(context.pool(), Site::read_local_site)
|
||||||
|
.await??
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
if ban {
|
||||||
|
BlockUser::send(
|
||||||
|
&site,
|
||||||
|
&person.into(),
|
||||||
|
&local_user_view.person.into(),
|
||||||
|
remove_data,
|
||||||
|
expires,
|
||||||
|
context,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
} else {
|
||||||
|
UndoBlockUser::send(
|
||||||
|
&site,
|
||||||
|
&person.into(),
|
||||||
|
&local_user_view.person.into(),
|
||||||
|
context,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
let res = BanPersonResponse {
|
let res = BanPersonResponse {
|
||||||
person_view,
|
person_view,
|
||||||
banned: data.ban,
|
banned: data.ban,
|
||||||
|
|
|
@ -35,7 +35,6 @@ use lemmy_utils::{
|
||||||
LemmyError,
|
LemmyError,
|
||||||
Sensitive,
|
Sensitive,
|
||||||
};
|
};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
pub async fn blocking<F, T>(pool: &DbPool, f: F) -> Result<T, LemmyError>
|
pub async fn blocking<F, T>(pool: &DbPool, f: F) -> Result<T, LemmyError>
|
||||||
where
|
where
|
||||||
|
@ -311,7 +310,7 @@ pub async fn build_federated_instances(
|
||||||
|
|
||||||
let mut linked = distinct_communities
|
let mut linked = distinct_communities
|
||||||
.iter()
|
.iter()
|
||||||
.map(|actor_id| Ok(Url::parse(actor_id)?.host_str().unwrap_or("").to_string()))
|
.map(|actor_id| Ok(actor_id.host_str().unwrap_or("").to_string()))
|
||||||
.collect::<Result<Vec<String>, LemmyError>>()?;
|
.collect::<Result<Vec<String>, LemmyError>>()?;
|
||||||
|
|
||||||
if let Some(allowed) = allowed.as_ref() {
|
if let Some(allowed) = allowed.as_ref() {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use lemmy_api_common::{
|
||||||
site::*,
|
site::*,
|
||||||
site_description_length_check,
|
site_description_length_check,
|
||||||
};
|
};
|
||||||
use lemmy_apub::generate_inbox_url;
|
use lemmy_apub::generate_site_inbox_url;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
diesel_option_overwrite,
|
diesel_option_overwrite,
|
||||||
diesel_option_overwrite_to_url,
|
diesel_option_overwrite_to_url,
|
||||||
|
@ -75,7 +75,7 @@ impl PerformCrud for CreateSite {
|
||||||
enable_nsfw: data.enable_nsfw,
|
enable_nsfw: data.enable_nsfw,
|
||||||
community_creation_admin_only: data.community_creation_admin_only,
|
community_creation_admin_only: data.community_creation_admin_only,
|
||||||
last_refreshed_at: Some(naive_now()),
|
last_refreshed_at: Some(naive_now()),
|
||||||
inbox_url: Some(generate_inbox_url(&actor_id)?),
|
inbox_url: Some(generate_site_inbox_url(&actor_id)?),
|
||||||
private_key: Some(Some(keypair.private_key)),
|
private_key: Some(Some(keypair.private_key)),
|
||||||
public_key: Some(keypair.public_key),
|
public_key: Some(keypair.public_key),
|
||||||
..SiteForm::default()
|
..SiteForm::default()
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
|
block::{generate_cc, generate_instance_inboxes, SiteOrCommunity},
|
||||||
community::{announce::GetCommunity, send_activity_in_community},
|
community::{announce::GetCommunity, send_activity_in_community},
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
|
send_lemmy_activity,
|
||||||
verify_activity,
|
verify_activity,
|
||||||
verify_is_public,
|
verify_is_public,
|
||||||
verify_mod_action,
|
verify_mod_action,
|
||||||
|
@ -9,9 +11,10 @@ use crate::{
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
protocol::activities::community::block_user::BlockUserFromCommunity,
|
protocol::activities::block::block_user::BlockUser,
|
||||||
};
|
};
|
||||||
use activitystreams_kinds::{activity::BlockType, public};
|
use activitystreams_kinds::{activity::BlockType, public};
|
||||||
|
use anyhow::anyhow;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{
|
use lemmy_apub_lib::{
|
||||||
|
@ -31,21 +34,23 @@ use lemmy_db_schema::{
|
||||||
use lemmy_utils::{utils::convert_datetime, LemmyError};
|
use lemmy_utils::{utils::convert_datetime, LemmyError};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
|
|
||||||
impl BlockUserFromCommunity {
|
impl BlockUser {
|
||||||
pub(in crate::activities::community) fn new(
|
pub(in crate::activities::block) async fn new(
|
||||||
community: &ApubCommunity,
|
target: &SiteOrCommunity,
|
||||||
target: &ApubPerson,
|
user: &ApubPerson,
|
||||||
actor: &ApubPerson,
|
mod_: &ApubPerson,
|
||||||
|
remove_data: Option<bool>,
|
||||||
expires: Option<NaiveDateTime>,
|
expires: Option<NaiveDateTime>,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> Result<BlockUserFromCommunity, LemmyError> {
|
) -> Result<BlockUser, LemmyError> {
|
||||||
Ok(BlockUserFromCommunity {
|
Ok(BlockUser {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(mod_.actor_id()),
|
||||||
to: vec![public()],
|
to: vec![public()],
|
||||||
object: ObjectId::new(target.actor_id()),
|
object: ObjectId::new(user.actor_id()),
|
||||||
cc: vec![community.actor_id()],
|
cc: generate_cc(target, context.pool()).await?,
|
||||||
target: ObjectId::new(community.actor_id()),
|
target: target.id(),
|
||||||
kind: BlockType::Block,
|
kind: BlockType::Block,
|
||||||
|
remove_data,
|
||||||
id: generate_activity_id(
|
id: generate_activity_id(
|
||||||
BlockType::Block,
|
BlockType::Block,
|
||||||
&context.settings().get_protocol_and_hostname(),
|
&context.settings().get_protocol_and_hostname(),
|
||||||
|
@ -57,23 +62,32 @@ impl BlockUserFromCommunity {
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn send(
|
pub async fn send(
|
||||||
community: &ApubCommunity,
|
target: &SiteOrCommunity,
|
||||||
target: &ApubPerson,
|
user: &ApubPerson,
|
||||||
actor: &ApubPerson,
|
mod_: &ApubPerson,
|
||||||
|
remove_data: bool,
|
||||||
expires: Option<NaiveDateTime>,
|
expires: Option<NaiveDateTime>,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let block = BlockUserFromCommunity::new(community, target, actor, expires, context)?;
|
let block = BlockUser::new(target, user, mod_, Some(remove_data), expires, context).await?;
|
||||||
let block_id = block.id.clone();
|
let block_id = block.id.clone();
|
||||||
|
|
||||||
let activity = AnnouncableActivities::BlockUserFromCommunity(block);
|
match target {
|
||||||
let inboxes = vec![target.shared_inbox_or_inbox_url()];
|
SiteOrCommunity::Site(_) => {
|
||||||
send_activity_in_community(activity, &block_id, actor, community, inboxes, context).await
|
let inboxes = generate_instance_inboxes(user, context.pool()).await?;
|
||||||
|
send_lemmy_activity(context, &block, &block_id, mod_, inboxes, false).await
|
||||||
|
}
|
||||||
|
SiteOrCommunity::Community(c) => {
|
||||||
|
let activity = AnnouncableActivities::BlockUser(block);
|
||||||
|
let inboxes = vec![user.shared_inbox_or_inbox_url()];
|
||||||
|
send_activity_in_community(activity, &block_id, mod_, c, inboxes, context).await
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl ActivityHandler for BlockUserFromCommunity {
|
impl ActivityHandler for BlockUser {
|
||||||
type DataType = LemmyContext;
|
type DataType = LemmyContext;
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
|
@ -130,16 +144,20 @@ impl ActivityHandler for BlockUserFromCommunity {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl GetCommunity for BlockUserFromCommunity {
|
impl GetCommunity for BlockUser {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn get_community(
|
async fn get_community(
|
||||||
&self,
|
&self,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<ApubCommunity, LemmyError> {
|
) -> Result<ApubCommunity, LemmyError> {
|
||||||
self
|
let target = self
|
||||||
.target
|
.target
|
||||||
.dereference(context, context.client(), request_counter)
|
.dereference(context, context.client(), request_counter)
|
||||||
.await
|
.await?;
|
||||||
|
match target {
|
||||||
|
SiteOrCommunity::Community(c) => Ok(c),
|
||||||
|
SiteOrCommunity::Site(_) => Err(anyhow!("Calling get_community() on site activity").into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
144
crates/apub/src/activities/block/mod.rs
Normal file
144
crates/apub/src/activities/block/mod.rs
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
use crate::{
|
||||||
|
objects::{community::ApubCommunity, instance::ApubSite, person::ApubPerson},
|
||||||
|
protocol::objects::{group::Group, instance::Instance},
|
||||||
|
};
|
||||||
|
use chrono::NaiveDateTime;
|
||||||
|
use lemmy_api_common::blocking;
|
||||||
|
use lemmy_apub_lib::{
|
||||||
|
object_id::ObjectId,
|
||||||
|
traits::{ActorType, ApubObject},
|
||||||
|
};
|
||||||
|
use lemmy_db_schema::{source::site::Site, DbPool};
|
||||||
|
use lemmy_utils::LemmyError;
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
pub mod block_user;
|
||||||
|
pub mod undo_block_user;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum SiteOrCommunity {
|
||||||
|
Site(ApubSite),
|
||||||
|
Community(ApubCommunity),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum InstanceOrGroup {
|
||||||
|
Instance(Instance),
|
||||||
|
Group(Group),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl ApubObject for SiteOrCommunity {
|
||||||
|
type DataType = LemmyContext;
|
||||||
|
type ApubType = InstanceOrGroup;
|
||||||
|
type TombstoneType = ();
|
||||||
|
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
|
||||||
|
Some(match self {
|
||||||
|
SiteOrCommunity::Site(i) => i.last_refreshed_at,
|
||||||
|
SiteOrCommunity::Community(c) => c.last_refreshed_at,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
async fn read_from_apub_id(
|
||||||
|
object_id: Url,
|
||||||
|
data: &Self::DataType,
|
||||||
|
) -> Result<Option<Self>, LemmyError>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let site = ApubSite::read_from_apub_id(object_id.clone(), data).await?;
|
||||||
|
Ok(match site {
|
||||||
|
Some(o) => Some(SiteOrCommunity::Site(o)),
|
||||||
|
None => ApubCommunity::read_from_apub_id(object_id, data)
|
||||||
|
.await?
|
||||||
|
.map(SiteOrCommunity::Community),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete(self, _data: &Self::DataType) -> Result<(), LemmyError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn into_apub(self, _data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_tombstone(&self) -> Result<Self::TombstoneType, LemmyError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
async fn verify(
|
||||||
|
apub: &Self::ApubType,
|
||||||
|
expected_domain: &Url,
|
||||||
|
data: &Self::DataType,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
match apub {
|
||||||
|
InstanceOrGroup::Instance(i) => {
|
||||||
|
ApubSite::verify(i, expected_domain, data, request_counter).await
|
||||||
|
}
|
||||||
|
InstanceOrGroup::Group(g) => {
|
||||||
|
ApubCommunity::verify(g, expected_domain, data, request_counter).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
async fn from_apub(
|
||||||
|
apub: Self::ApubType,
|
||||||
|
data: &Self::DataType,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<Self, LemmyError>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Ok(match apub {
|
||||||
|
InstanceOrGroup::Instance(p) => {
|
||||||
|
SiteOrCommunity::Site(ApubSite::from_apub(p, data, request_counter).await?)
|
||||||
|
}
|
||||||
|
InstanceOrGroup::Group(n) => {
|
||||||
|
SiteOrCommunity::Community(ApubCommunity::from_apub(n, data, request_counter).await?)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SiteOrCommunity {
|
||||||
|
fn id(&self) -> ObjectId<SiteOrCommunity> {
|
||||||
|
match self {
|
||||||
|
SiteOrCommunity::Site(s) => ObjectId::new(s.actor_id.clone()),
|
||||||
|
SiteOrCommunity::Community(c) => ObjectId::new(c.actor_id.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn generate_cc(target: &SiteOrCommunity, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
|
||||||
|
Ok(match target {
|
||||||
|
SiteOrCommunity::Site(_) => blocking(pool, Site::read_remote_sites)
|
||||||
|
.await??
|
||||||
|
.into_iter()
|
||||||
|
.map(|s| s.actor_id.into())
|
||||||
|
.collect(),
|
||||||
|
SiteOrCommunity::Community(c) => vec![c.actor_id()],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn generate_instance_inboxes(
|
||||||
|
blocked_user: &ApubPerson,
|
||||||
|
pool: &DbPool,
|
||||||
|
) -> Result<Vec<Url>, LemmyError> {
|
||||||
|
let mut inboxes: Vec<Url> = blocking(pool, Site::read_remote_sites)
|
||||||
|
.await??
|
||||||
|
.into_iter()
|
||||||
|
.map(|s| s.inbox_url.into())
|
||||||
|
.collect();
|
||||||
|
inboxes.push(blocked_user.shared_inbox_or_inbox_url());
|
||||||
|
Ok(inboxes)
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
|
block::{generate_cc, generate_instance_inboxes, SiteOrCommunity},
|
||||||
community::{announce::GetCommunity, send_activity_in_community},
|
community::{announce::GetCommunity, send_activity_in_community},
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
|
send_lemmy_activity,
|
||||||
verify_activity,
|
verify_activity,
|
||||||
verify_is_public,
|
verify_is_public,
|
||||||
verify_mod_action,
|
verify_mod_action,
|
||||||
|
@ -9,10 +11,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
protocol::activities::community::{
|
protocol::activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
|
||||||
block_user::BlockUserFromCommunity,
|
|
||||||
undo_block_user::UndoBlockUserFromCommunity,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use activitystreams_kinds::{activity::UndoType, public};
|
use activitystreams_kinds::{activity::UndoType, public};
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
|
@ -28,38 +27,46 @@ use lemmy_db_schema::{
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
|
|
||||||
impl UndoBlockUserFromCommunity {
|
impl UndoBlockUser {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn send(
|
pub async fn send(
|
||||||
community: &ApubCommunity,
|
target: &SiteOrCommunity,
|
||||||
target: &ApubPerson,
|
user: &ApubPerson,
|
||||||
actor: &ApubPerson,
|
mod_: &ApubPerson,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let block = BlockUserFromCommunity::new(community, target, actor, None, context)?;
|
let block = BlockUser::new(target, user, mod_, None, None, context).await?;
|
||||||
|
|
||||||
let id = generate_activity_id(
|
let id = generate_activity_id(
|
||||||
UndoType::Undo,
|
UndoType::Undo,
|
||||||
&context.settings().get_protocol_and_hostname(),
|
&context.settings().get_protocol_and_hostname(),
|
||||||
)?;
|
)?;
|
||||||
let undo = UndoBlockUserFromCommunity {
|
let undo = UndoBlockUser {
|
||||||
actor: ObjectId::new(actor.actor_id()),
|
actor: ObjectId::new(mod_.actor_id()),
|
||||||
to: vec![public()],
|
to: vec![public()],
|
||||||
object: block,
|
object: block,
|
||||||
cc: vec![community.actor_id()],
|
cc: generate_cc(target, context.pool()).await?,
|
||||||
kind: UndoType::Undo,
|
kind: UndoType::Undo,
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
unparsed: Default::default(),
|
unparsed: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let activity = AnnouncableActivities::UndoBlockUserFromCommunity(undo);
|
let inboxes = vec![user.shared_inbox_or_inbox_url()];
|
||||||
let inboxes = vec![target.shared_inbox_or_inbox_url()];
|
match target {
|
||||||
send_activity_in_community(activity, &id, actor, community, inboxes, context).await
|
SiteOrCommunity::Site(_) => {
|
||||||
|
let inboxes = generate_instance_inboxes(user, context.pool()).await?;
|
||||||
|
send_lemmy_activity(context, &undo, &id, mod_, inboxes, false).await
|
||||||
|
}
|
||||||
|
SiteOrCommunity::Community(c) => {
|
||||||
|
let activity = AnnouncableActivities::UndoBlockUser(undo);
|
||||||
|
send_activity_in_community(activity, &id, mod_, c, inboxes, context).await
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl ActivityHandler for UndoBlockUserFromCommunity {
|
impl ActivityHandler for UndoBlockUser {
|
||||||
type DataType = LemmyContext;
|
type DataType = LemmyContext;
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
|
@ -106,7 +113,7 @@ impl ActivityHandler for UndoBlockUserFromCommunity {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl GetCommunity for UndoBlockUserFromCommunity {
|
impl GetCommunity for UndoBlockUser {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn get_community(
|
async fn get_community(
|
||||||
&self,
|
&self,
|
|
@ -11,10 +11,8 @@ use url::Url;
|
||||||
|
|
||||||
pub mod add_mod;
|
pub mod add_mod;
|
||||||
pub mod announce;
|
pub mod announce;
|
||||||
pub mod block_user;
|
|
||||||
pub mod remove_mod;
|
pub mod remove_mod;
|
||||||
pub mod report;
|
pub mod report;
|
||||||
pub mod undo_block_user;
|
|
||||||
pub mod update;
|
pub mod update;
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
|
|
|
@ -25,6 +25,7 @@ use tracing::info;
|
||||||
use url::{ParseError, Url};
|
use url::{ParseError, Url};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
pub mod block;
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
pub mod community;
|
pub mod community;
|
||||||
pub mod deletion;
|
pub mod deletion;
|
||||||
|
|
|
@ -3,13 +3,12 @@ use crate::{
|
||||||
objects::community::ApubCommunity,
|
objects::community::ApubCommunity,
|
||||||
protocol::{
|
protocol::{
|
||||||
activities::{
|
activities::{
|
||||||
|
block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
|
||||||
community::{
|
community::{
|
||||||
add_mod::AddMod,
|
add_mod::AddMod,
|
||||||
announce::AnnounceActivity,
|
announce::AnnounceActivity,
|
||||||
block_user::BlockUserFromCommunity,
|
|
||||||
remove_mod::RemoveMod,
|
remove_mod::RemoveMod,
|
||||||
report::Report,
|
report::Report,
|
||||||
undo_block_user::UndoBlockUserFromCommunity,
|
|
||||||
update::UpdateCommunity,
|
update::UpdateCommunity,
|
||||||
},
|
},
|
||||||
create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost},
|
create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost},
|
||||||
|
@ -78,14 +77,22 @@ pub enum AnnouncableActivities {
|
||||||
Delete(Delete),
|
Delete(Delete),
|
||||||
UndoDelete(UndoDelete),
|
UndoDelete(UndoDelete),
|
||||||
UpdateCommunity(UpdateCommunity),
|
UpdateCommunity(UpdateCommunity),
|
||||||
BlockUserFromCommunity(BlockUserFromCommunity),
|
BlockUser(BlockUser),
|
||||||
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
|
UndoBlockUser(UndoBlockUser),
|
||||||
AddMod(AddMod),
|
AddMod(AddMod),
|
||||||
RemoveMod(RemoveMod),
|
RemoveMod(RemoveMod),
|
||||||
// For compatibility with Pleroma/Mastodon (send only)
|
// For compatibility with Pleroma/Mastodon (send only)
|
||||||
Page(Page),
|
Page(Page),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
#[activity_handler(LemmyContext)]
|
||||||
|
pub enum SiteInboxActivities {
|
||||||
|
BlockUser(BlockUser),
|
||||||
|
UndoBlockUser(UndoBlockUser),
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl GetCommunity for AnnouncableActivities {
|
impl GetCommunity for AnnouncableActivities {
|
||||||
#[tracing::instrument(skip(self, context))]
|
#[tracing::instrument(skip(self, context))]
|
||||||
|
@ -103,8 +110,8 @@ impl GetCommunity for AnnouncableActivities {
|
||||||
Delete(a) => a.get_community(context, request_counter).await?,
|
Delete(a) => a.get_community(context, request_counter).await?,
|
||||||
UndoDelete(a) => a.get_community(context, request_counter).await?,
|
UndoDelete(a) => a.get_community(context, request_counter).await?,
|
||||||
UpdateCommunity(a) => a.get_community(context, request_counter).await?,
|
UpdateCommunity(a) => a.get_community(context, request_counter).await?,
|
||||||
BlockUserFromCommunity(a) => a.get_community(context, request_counter).await?,
|
BlockUser(a) => a.get_community(context, request_counter).await?,
|
||||||
UndoBlockUserFromCommunity(a) => a.get_community(context, request_counter).await?,
|
UndoBlockUser(a) => a.get_community(context, request_counter).await?,
|
||||||
AddMod(a) => a.get_community(context, request_counter).await?,
|
AddMod(a) => a.get_community(context, request_counter).await?,
|
||||||
RemoveMod(a) => a.get_community(context, request_counter).await?,
|
RemoveMod(a) => a.get_community(context, request_counter).await?,
|
||||||
Page(_) => unimplemented!(),
|
Page(_) => unimplemented!(),
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::http::{
|
||||||
person::{get_apub_person_http, get_apub_person_outbox, person_inbox},
|
person::{get_apub_person_http, get_apub_person_outbox, person_inbox},
|
||||||
post::get_apub_post,
|
post::get_apub_post,
|
||||||
shared_inbox,
|
shared_inbox,
|
||||||
site::get_apub_site_http,
|
site::{get_apub_site_http, get_apub_site_inbox, get_apub_site_outbox},
|
||||||
};
|
};
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
guard::{Guard, GuardContext},
|
guard::{Guard, GuardContext},
|
||||||
|
@ -28,7 +28,8 @@ pub fn config(cfg: &mut web::ServiceConfig, settings: &Settings) {
|
||||||
|
|
||||||
cfg
|
cfg
|
||||||
.route("/", web::get().to(get_apub_site_http))
|
.route("/", web::get().to(get_apub_site_http))
|
||||||
.route("/site_outbox", web::get().to(get_apub_site_http))
|
.route("/site_outbox", web::get().to(get_apub_site_outbox))
|
||||||
|
.route("/site_inbox", web::get().to(get_apub_site_inbox))
|
||||||
.route(
|
.route(
|
||||||
"/c/{community_name}",
|
"/c/{community_name}",
|
||||||
web::get().to(get_apub_community_http),
|
web::get().to(get_apub_community_http),
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
http::create_apub_response,
|
activity_lists::SiteInboxActivities,
|
||||||
|
context::WithContext,
|
||||||
|
http::{create_apub_response, payload_to_string, receive_activity, ActivityCommonFields},
|
||||||
objects::instance::ApubSite,
|
objects::instance::ApubSite,
|
||||||
protocol::collections::empty_outbox::EmptyOutbox,
|
protocol::collections::empty_outbox::EmptyOutbox,
|
||||||
};
|
};
|
||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{web, web::Payload, HttpRequest, HttpResponse};
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::traits::ApubObject;
|
use lemmy_apub_lib::traits::ApubObject;
|
||||||
use lemmy_db_schema::source::site::Site;
|
use lemmy_db_schema::source::site::Site;
|
||||||
use lemmy_utils::{settings::structs::Settings, LemmyError};
|
use lemmy_utils::{settings::structs::Settings, LemmyError};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
|
use tracing::info;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub(crate) async fn get_apub_site_http(
|
pub(crate) async fn get_apub_site_http(
|
||||||
|
@ -31,3 +34,17 @@ pub(crate) async fn get_apub_site_outbox() -> Result<HttpResponse, LemmyError> {
|
||||||
let outbox = EmptyOutbox::new(Url::parse(&outbox_id)?).await?;
|
let outbox = EmptyOutbox::new(Url::parse(&outbox_id)?).await?;
|
||||||
Ok(create_apub_response(&outbox))
|
Ok(create_apub_response(&outbox))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
pub async fn get_apub_site_inbox(
|
||||||
|
request: HttpRequest,
|
||||||
|
payload: Payload,
|
||||||
|
_path: web::Path<String>,
|
||||||
|
context: web::Data<LemmyContext>,
|
||||||
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
|
let unparsed = payload_to_string(payload).await?;
|
||||||
|
info!("Received site inbox activity {}", unparsed);
|
||||||
|
let activity_data: ActivityCommonFields = serde_json::from_str(&unparsed)?;
|
||||||
|
let activity = serde_json::from_str::<WithContext<SiteInboxActivities>>(&unparsed)?;
|
||||||
|
receive_activity(request, activity.inner(), activity_data, &context).await
|
||||||
|
}
|
||||||
|
|
|
@ -164,6 +164,10 @@ pub fn generate_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
|
||||||
Ok(Url::parse(&format!("{}/inbox", actor_id))?.into())
|
Ok(Url::parse(&format!("{}/inbox", actor_id))?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_site_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
|
||||||
|
Ok(Url::parse(&format!("{}/site_inbox", actor_id))?.into())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate_shared_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, LemmyError> {
|
pub fn generate_shared_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, LemmyError> {
|
||||||
let actor_id: Url = actor_id.clone().into();
|
let actor_id: Url = actor_id.clone().into();
|
||||||
let url = format!(
|
let url = format!(
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
collections::{community_moderators::ApubCommunityModerators, CommunityContext},
|
collections::{community_moderators::ApubCommunityModerators, CommunityContext},
|
||||||
generate_moderators_url,
|
generate_moderators_url,
|
||||||
generate_outbox_url,
|
generate_outbox_url,
|
||||||
objects::instance::{instance_actor_id_from_url, ApubSite},
|
objects::instance::fetch_instance_actor_for_object,
|
||||||
protocol::{
|
protocol::{
|
||||||
objects::{group::Group, tombstone::Tombstone, Endpoints},
|
objects::{group::Group, tombstone::Tombstone, Endpoints},
|
||||||
ImageObject,
|
ImageObject,
|
||||||
|
@ -26,7 +26,7 @@ use lemmy_utils::{
|
||||||
};
|
};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use tracing::{debug, info};
|
use tracing::debug;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -153,14 +153,7 @@ impl ApubObject for ApubCommunity {
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to fetch the instance actor (to make things like instance rules available)
|
fetch_instance_actor_for_object(community.actor_id(), context, request_counter).await;
|
||||||
let instance_id = instance_actor_id_from_url(community.actor_id.clone().into());
|
|
||||||
let site = ObjectId::<ApubSite>::new(instance_id.clone())
|
|
||||||
.dereference(context, context.client(), request_counter)
|
|
||||||
.await;
|
|
||||||
if let Err(e) = site {
|
|
||||||
info!("Failed to dereference site for {}: {}", instance_id, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(community)
|
Ok(community)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
check_is_apub_id_valid,
|
check_is_apub_id_valid,
|
||||||
generate_outbox_url,
|
|
||||||
objects::get_summary_from_string_or_source,
|
objects::get_summary_from_string_or_source,
|
||||||
protocol::{objects::instance::Instance, ImageObject, Source, Unparsed},
|
protocol::{objects::instance::Instance, ImageObject, Source, Unparsed},
|
||||||
};
|
};
|
||||||
|
@ -23,6 +22,7 @@ use lemmy_utils::{
|
||||||
};
|
};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
use tracing::debug;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -82,7 +82,7 @@ impl ApubObject for ApubSite {
|
||||||
icon: self.icon.clone().map(ImageObject::new),
|
icon: self.icon.clone().map(ImageObject::new),
|
||||||
image: self.banner.clone().map(ImageObject::new),
|
image: self.banner.clone().map(ImageObject::new),
|
||||||
inbox: self.inbox_url.clone().into(),
|
inbox: self.inbox_url.clone().into(),
|
||||||
outbox: generate_outbox_url(&self.actor_id)?.into(),
|
outbox: Url::parse(&format!("{}/site_outbox", self.actor_id))?,
|
||||||
public_key: self.get_public_key()?,
|
public_key: self.get_public_key()?,
|
||||||
published: convert_datetime(self.published),
|
published: convert_datetime(self.published),
|
||||||
updated: self.updated.map(convert_datetime),
|
updated: self.updated.map(convert_datetime),
|
||||||
|
@ -167,6 +167,22 @@ pub fn instance_actor_id_from_url(mut url: Url) -> Url {
|
||||||
url
|
url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// try to fetch the instance actor (to make things like instance rules available)
|
||||||
|
pub(in crate::objects) async fn fetch_instance_actor_for_object(
|
||||||
|
object_id: Url,
|
||||||
|
context: &LemmyContext,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) {
|
||||||
|
// try to fetch the instance actor (to make things like instance rules available)
|
||||||
|
let instance_id = instance_actor_id_from_url(object_id);
|
||||||
|
let site = ObjectId::<ApubSite>::new(instance_id.clone())
|
||||||
|
.dereference(context, context.client(), request_counter)
|
||||||
|
.await;
|
||||||
|
if let Err(e) = site {
|
||||||
|
debug!("Failed to dereference site for {}: {}", instance_id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
check_is_apub_id_valid,
|
check_is_apub_id_valid,
|
||||||
generate_outbox_url,
|
generate_outbox_url,
|
||||||
objects::get_summary_from_string_or_source,
|
objects::{get_summary_from_string_or_source, instance::fetch_instance_actor_for_object},
|
||||||
protocol::{
|
protocol::{
|
||||||
objects::{
|
objects::{
|
||||||
person::{Person, UserTypes},
|
person::{Person, UserTypes},
|
||||||
|
@ -137,7 +137,7 @@ impl ApubObject for ApubPerson {
|
||||||
async fn from_apub(
|
async fn from_apub(
|
||||||
person: Person,
|
person: Person,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
_request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<ApubPerson, LemmyError> {
|
) -> Result<ApubPerson, LemmyError> {
|
||||||
let person_form = PersonForm {
|
let person_form = PersonForm {
|
||||||
name: person.preferred_username,
|
name: person.preferred_username,
|
||||||
|
@ -168,6 +168,10 @@ impl ApubObject for ApubPerson {
|
||||||
DbPerson::upsert(conn, &person_form)
|
DbPerson::upsert(conn, &person_form)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
let actor_id = person.actor_id.clone().into();
|
||||||
|
fetch_instance_actor_for_object(actor_id, context, request_counter).await;
|
||||||
|
|
||||||
Ok(person.into())
|
Ok(person.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
use crate::{
|
use crate::{activities::block::SiteOrCommunity, objects::person::ApubPerson, protocol::Unparsed};
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
|
||||||
protocol::Unparsed,
|
|
||||||
};
|
|
||||||
use activitystreams_kinds::activity::BlockType;
|
use activitystreams_kinds::activity::BlockType;
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
use lemmy_apub_lib::object_id::ObjectId;
|
use lemmy_apub_lib::object_id::ObjectId;
|
||||||
|
@ -10,16 +7,19 @@ use url::Url;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct BlockUserFromCommunity {
|
pub struct BlockUser {
|
||||||
pub(crate) actor: ObjectId<ApubPerson>,
|
pub(crate) actor: ObjectId<ApubPerson>,
|
||||||
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
|
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
|
||||||
pub(crate) to: Vec<Url>,
|
pub(crate) to: Vec<Url>,
|
||||||
pub(crate) object: ObjectId<ApubPerson>,
|
pub(crate) object: ObjectId<ApubPerson>,
|
||||||
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
|
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
|
||||||
pub(crate) cc: Vec<Url>,
|
pub(crate) cc: Vec<Url>,
|
||||||
pub(crate) target: ObjectId<ApubCommunity>,
|
pub(crate) target: ObjectId<SiteOrCommunity>,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub(crate) kind: BlockType,
|
pub(crate) kind: BlockType,
|
||||||
|
/// Quick and dirty solution.
|
||||||
|
/// TODO: send a separate Delete activity instead
|
||||||
|
pub(crate) remove_data: Option<bool>,
|
||||||
pub(crate) id: Url,
|
pub(crate) id: Url,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub(crate) unparsed: Unparsed,
|
pub(crate) unparsed: Unparsed,
|
20
crates/apub/src/protocol/activities/block/mod.rs
Normal file
20
crates/apub/src/protocol/activities/block/mod.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
pub mod block_user;
|
||||||
|
pub mod undo_block_user;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::protocol::{
|
||||||
|
activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
|
||||||
|
tests::test_parse_lemmy_item,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_parse_lemmy_block() {
|
||||||
|
test_parse_lemmy_item::<BlockUser>("assets/lemmy/activities/community/block_user.json")
|
||||||
|
.unwrap();
|
||||||
|
test_parse_lemmy_item::<UndoBlockUser>(
|
||||||
|
"assets/lemmy/activities/community/undo_block_user.json",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::person::ApubPerson,
|
objects::person::ApubPerson,
|
||||||
protocol::{activities::community::block_user::BlockUserFromCommunity, Unparsed},
|
protocol::{activities::block::block_user::BlockUser, Unparsed},
|
||||||
};
|
};
|
||||||
use activitystreams_kinds::activity::UndoType;
|
use activitystreams_kinds::activity::UndoType;
|
||||||
use lemmy_apub_lib::object_id::ObjectId;
|
use lemmy_apub_lib::object_id::ObjectId;
|
||||||
|
@ -9,11 +9,11 @@ use url::Url;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UndoBlockUserFromCommunity {
|
pub struct UndoBlockUser {
|
||||||
pub(crate) actor: ObjectId<ApubPerson>,
|
pub(crate) actor: ObjectId<ApubPerson>,
|
||||||
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
|
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
|
||||||
pub(crate) to: Vec<Url>,
|
pub(crate) to: Vec<Url>,
|
||||||
pub(crate) object: BlockUserFromCommunity,
|
pub(crate) object: BlockUser,
|
||||||
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
|
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
|
||||||
pub(crate) cc: Vec<Url>,
|
pub(crate) cc: Vec<Url>,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
|
@ -1,22 +1,21 @@
|
||||||
pub mod add_mod;
|
pub mod add_mod;
|
||||||
pub mod announce;
|
pub mod announce;
|
||||||
pub mod block_user;
|
|
||||||
pub mod remove_mod;
|
pub mod remove_mod;
|
||||||
pub mod report;
|
pub mod report;
|
||||||
pub mod undo_block_user;
|
|
||||||
pub mod update;
|
pub mod update;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
activities::community::{
|
activities::{
|
||||||
add_mod::AddMod,
|
block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
|
||||||
announce::AnnounceActivity,
|
community::{
|
||||||
block_user::BlockUserFromCommunity,
|
add_mod::AddMod,
|
||||||
remove_mod::RemoveMod,
|
announce::AnnounceActivity,
|
||||||
report::Report,
|
remove_mod::RemoveMod,
|
||||||
undo_block_user::UndoBlockUserFromCommunity,
|
report::Report,
|
||||||
update::UpdateCommunity,
|
update::UpdateCommunity,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
tests::test_parse_lemmy_item,
|
tests::test_parse_lemmy_item,
|
||||||
};
|
};
|
||||||
|
@ -32,11 +31,9 @@ mod tests {
|
||||||
test_parse_lemmy_item::<RemoveMod>("assets/lemmy/activities/community/remove_mod.json")
|
test_parse_lemmy_item::<RemoveMod>("assets/lemmy/activities/community/remove_mod.json")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
test_parse_lemmy_item::<BlockUserFromCommunity>(
|
test_parse_lemmy_item::<BlockUser>("assets/lemmy/activities/community/block_user.json")
|
||||||
"assets/lemmy/activities/community/block_user.json",
|
.unwrap();
|
||||||
)
|
test_parse_lemmy_item::<UndoBlockUser>(
|
||||||
.unwrap();
|
|
||||||
test_parse_lemmy_item::<UndoBlockUserFromCommunity>(
|
|
||||||
"assets/lemmy/activities/community/undo_block_user.json",
|
"assets/lemmy/activities/community/undo_block_user.json",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use strum_macros::Display;
|
use strum_macros::Display;
|
||||||
|
|
||||||
|
pub mod block;
|
||||||
pub mod community;
|
pub mod community;
|
||||||
pub mod create_or_update;
|
pub mod create_or_update;
|
||||||
pub mod deletion;
|
pub mod deletion;
|
||||||
|
|
|
@ -122,9 +122,9 @@ impl Community {
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn distinct_federated_communities(conn: &PgConnection) -> Result<Vec<String>, Error> {
|
pub fn distinct_federated_communities(conn: &PgConnection) -> Result<Vec<DbUrl>, Error> {
|
||||||
use crate::schema::community::dsl::*;
|
use crate::schema::community::dsl::*;
|
||||||
community.select(actor_id).distinct().load::<String>(conn)
|
community.select(actor_id).distinct().load::<DbUrl>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upsert(conn: &PgConnection, community_form: &CommunityForm) -> Result<Community, Error> {
|
pub fn upsert(conn: &PgConnection, community_form: &CommunityForm) -> Result<Community, Error> {
|
||||||
|
|
|
@ -54,4 +54,9 @@ impl Site {
|
||||||
.map(Into::into),
|
.map(Into::into),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_remote_sites(conn: &PgConnection) -> Result<Vec<Self>, Error> {
|
||||||
|
use crate::schema::site::dsl::*;
|
||||||
|
site.order_by(id).offset(1).get_results::<Self>(conn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use std::{
|
||||||
fmt,
|
fmt,
|
||||||
fmt::{Display, Formatter},
|
fmt::{Display, Formatter},
|
||||||
io::Write,
|
io::Write,
|
||||||
|
ops::Deref,
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -125,3 +126,11 @@ where
|
||||||
DbUrl(id.into())
|
DbUrl(id.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Deref for DbUrl {
|
||||||
|
type Target = Url;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use lemmy_apub::{
|
||||||
generate_inbox_url,
|
generate_inbox_url,
|
||||||
generate_local_apub_endpoint,
|
generate_local_apub_endpoint,
|
||||||
generate_shared_inbox_url,
|
generate_shared_inbox_url,
|
||||||
|
generate_site_inbox_url,
|
||||||
EndpointType,
|
EndpointType,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -304,7 +305,7 @@ fn instance_actor_2022_01_28(
|
||||||
name: site.name,
|
name: site.name,
|
||||||
actor_id: Some(actor_id.clone().into()),
|
actor_id: Some(actor_id.clone().into()),
|
||||||
last_refreshed_at: Some(naive_now()),
|
last_refreshed_at: Some(naive_now()),
|
||||||
inbox_url: Some(generate_inbox_url(&actor_id.into())?),
|
inbox_url: Some(generate_site_inbox_url(&actor_id.into())?),
|
||||||
private_key: Some(Some(key_pair.private_key)),
|
private_key: Some(Some(key_pair.private_key)),
|
||||||
public_key: Some(key_pair.public_key),
|
public_key: Some(key_pair.public_key),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
Loading…
Reference in a new issue