mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-09-02 03:03:57 +00:00
Federation refactoring (#5855)
* refactor federation http responses * Rename Activity * test fixes * library release
This commit is contained in:
parent
7fb11c36fa
commit
a8a407ca6d
52 changed files with 277 additions and 457 deletions
72
Cargo.lock
generated
72
Cargo.lock
generated
|
@ -10,9 +10,9 @@ checksum = "8f27d075294830fcab6f66e320dab524bc6d048f4a151698e153205559113772"
|
|||
|
||||
[[package]]
|
||||
name = "activitypub_federation"
|
||||
version = "0.7.0-beta.4"
|
||||
version = "0.7.0-beta.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91fb4c19ede0a628977cdc5d1ec7d1fb3e3e3e5e9de955bd0d5fed0c8cd5260d"
|
||||
checksum = "e58f584c183501d7865b18d8b94c9477f750051ce99d54a399a2f4180667574c"
|
||||
dependencies = [
|
||||
"activitystreams-kinds",
|
||||
"actix-web",
|
||||
|
@ -4056,7 +4056,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.53.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -7976,29 +7976,13 @@ dependencies = [
|
|||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm 0.52.6",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.53.0",
|
||||
"windows_aarch64_msvc 0.53.0",
|
||||
"windows_i686_gnu 0.53.0",
|
||||
"windows_i686_gnullvm 0.53.0",
|
||||
"windows_i686_msvc 0.53.0",
|
||||
"windows_x86_64_gnu 0.53.0",
|
||||
"windows_x86_64_gnullvm 0.53.0",
|
||||
"windows_x86_64_msvc 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-threading"
|
||||
version = "0.1.0"
|
||||
|
@ -8020,12 +8004,6 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
|
@ -8038,12 +8016,6 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
|
@ -8056,24 +8028,12 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
|
@ -8086,12 +8046,6 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
|
@ -8104,12 +8058,6 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
|
@ -8122,12 +8070,6 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
|
@ -8140,12 +8082,6 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.10"
|
||||
|
|
|
@ -140,7 +140,7 @@ lemmy_db_views_reports = { version = "=1.0.0-alpha.5", path = "./crates/db_views
|
|||
lemmy_db_views_search_combined = { version = "=1.0.0-alpha.5", path = "./crates/db_views/search_combined" }
|
||||
lemmy_db_views_site = { version = "=1.0.0-alpha.5", path = "./crates/db_views/site" }
|
||||
lemmy_db_views_vote = { version = "=1.0.0-alpha.5", path = "./crates/db_views/vote" }
|
||||
activitypub_federation = { version = "0.7.0-beta.4", default-features = false, features = [
|
||||
activitypub_federation = { version = "0.7.0-beta.5", default-features = false, features = [
|
||||
"actix-web",
|
||||
] }
|
||||
diesel = { version = "2.2.10", features = [
|
||||
|
|
|
@ -18,6 +18,9 @@ doctest = false
|
|||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
full = []
|
||||
|
||||
[dependencies]
|
||||
lemmy_db_views_comment = { workspace = true, features = ["full"] }
|
||||
lemmy_db_views_community = { workspace = true, features = ["full"] }
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
|||
use activitypub_federation::{
|
||||
config::Data,
|
||||
kinds::activity::BlockType,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Actor, Object},
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
use lemmy_api_utils::{
|
||||
|
@ -48,11 +48,11 @@ impl BlockUser {
|
|||
) -> LemmyResult<BlockUser> {
|
||||
let to = to(target)?;
|
||||
Ok(BlockUser {
|
||||
actor: mod_.id().into(),
|
||||
actor: mod_.id().clone().into(),
|
||||
to,
|
||||
object: user.id().into(),
|
||||
object: user.id().clone().into(),
|
||||
cc: generate_cc(target, &mut context.pool()).await?,
|
||||
target: target.id(),
|
||||
target: target.id().clone().into(),
|
||||
kind: BlockType::Block,
|
||||
remove_data,
|
||||
summary: reason,
|
||||
|
@ -82,11 +82,11 @@ impl BlockUser {
|
|||
.await?;
|
||||
|
||||
match target {
|
||||
SiteOrCommunity::Site(_) => {
|
||||
SiteOrCommunity::Left(_) => {
|
||||
let inboxes = ActivitySendTargets::to_all_instances();
|
||||
send_lemmy_activity(context, block, mod_, inboxes, false).await
|
||||
}
|
||||
SiteOrCommunity::Community(c) => {
|
||||
SiteOrCommunity::Right(c) => {
|
||||
let activity = AnnouncableActivities::BlockUser(block);
|
||||
let inboxes = ActivitySendTargets::to_inbox(user.shared_inbox_or_inbox());
|
||||
send_activity_in_community(activity, mod_, c, inboxes, true, context).await
|
||||
|
@ -96,7 +96,7 @@ impl BlockUser {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for BlockUser {
|
||||
impl Activity for BlockUser {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
@ -110,10 +110,10 @@ impl ActivityHandler for BlockUser {
|
|||
|
||||
async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
||||
match self.target.dereference(context).await? {
|
||||
SiteOrCommunity::Site(_site) => {
|
||||
SiteOrCommunity::Left(_site) => {
|
||||
verify_is_public(&self.to, &self.cc)?;
|
||||
}
|
||||
SiteOrCommunity::Community(community) => {
|
||||
SiteOrCommunity::Right(community) => {
|
||||
verify_visibility(&self.to, &self.cc, &community)?;
|
||||
verify_person_in_community(&self.actor, &community, context).await?;
|
||||
verify_mod_action(&self.actor, &community, context).await?;
|
||||
|
@ -130,7 +130,7 @@ impl ActivityHandler for BlockUser {
|
|||
let reason = self.summary;
|
||||
let pool = &mut context.pool();
|
||||
match target {
|
||||
SiteOrCommunity::Site(site) => {
|
||||
SiteOrCommunity::Left(site) => {
|
||||
let form = InstanceBanForm::new(blocked_person.id, site.instance_id, expires_at);
|
||||
InstanceActions::ban(pool, &form).await?;
|
||||
|
||||
|
@ -155,7 +155,7 @@ impl ActivityHandler for BlockUser {
|
|||
};
|
||||
ModBan::create(&mut context.pool(), &form).await?;
|
||||
}
|
||||
SiteOrCommunity::Community(community) => {
|
||||
SiteOrCommunity::Right(community) => {
|
||||
let community_user_ban_form = CommunityPersonBanForm {
|
||||
ban_expires_at: Some(expires_at),
|
||||
..CommunityPersonBanForm::new(community.id, blocked_person.id)
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
use crate::protocol::activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser};
|
||||
use activitypub_federation::{
|
||||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
kinds::public,
|
||||
traits::{Actor, Object},
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
use activitypub_federation::{config::Data, kinds::public, traits::Object};
|
||||
use either::Either;
|
||||
use lemmy_api_utils::{context::LemmyContext, utils::check_expire_time};
|
||||
use lemmy_apub_objects::{
|
||||
objects::{community::ApubCommunity, instance::ApubSite},
|
||||
protocol::{group::Group, instance::Instance},
|
||||
utils::functions::generate_to,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
|
@ -19,106 +13,22 @@ use lemmy_db_schema::{
|
|||
utils::DbPool,
|
||||
};
|
||||
use lemmy_db_views_community::api::BanFromCommunity;
|
||||
use lemmy_utils::error::{LemmyError, LemmyResult};
|
||||
use serde::Deserialize;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
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(Box<Instance>),
|
||||
Group(Box<Group>),
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Object for SiteOrCommunity {
|
||||
type DataType = LemmyContext;
|
||||
type Kind = InstanceOrGroup;
|
||||
type Error = LemmyError;
|
||||
|
||||
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
||||
Some(match self {
|
||||
SiteOrCommunity::Site(i) => i.last_refreshed_at,
|
||||
SiteOrCommunity::Community(c) => c.last_refreshed_at,
|
||||
})
|
||||
}
|
||||
|
||||
async fn read_from_id(object_id: Url, data: &Data<Self::DataType>) -> LemmyResult<Option<Self>>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let site = ApubSite::read_from_id(object_id.clone(), data).await?;
|
||||
Ok(match site {
|
||||
Some(o) => Some(SiteOrCommunity::Site(o)),
|
||||
None => ApubCommunity::read_from_id(object_id, data)
|
||||
.await?
|
||||
.map(SiteOrCommunity::Community),
|
||||
})
|
||||
}
|
||||
|
||||
async fn delete(self, data: &Data<Self::DataType>) -> LemmyResult<()> {
|
||||
match self {
|
||||
SiteOrCommunity::Site(i) => i.delete(data).await,
|
||||
SiteOrCommunity::Community(c) => c.delete(data).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn into_json(self, data: &Data<Self::DataType>) -> LemmyResult<Self::Kind> {
|
||||
Ok(match self {
|
||||
SiteOrCommunity::Site(i) => InstanceOrGroup::Instance(Box::new(i.into_json(data).await?)),
|
||||
SiteOrCommunity::Community(c) => InstanceOrGroup::Group(Box::new(c.into_json(data).await?)),
|
||||
})
|
||||
}
|
||||
|
||||
async fn verify(
|
||||
apub: &Self::Kind,
|
||||
expected_domain: &Url,
|
||||
data: &Data<Self::DataType>,
|
||||
) -> LemmyResult<()> {
|
||||
match apub {
|
||||
InstanceOrGroup::Instance(i) => ApubSite::verify(i, expected_domain, data).await,
|
||||
InstanceOrGroup::Group(g) => ApubCommunity::verify(g, expected_domain, data).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn from_json(apub: Self::Kind, data: &Data<Self::DataType>) -> LemmyResult<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ok(match apub {
|
||||
InstanceOrGroup::Instance(p) => SiteOrCommunity::Site(ApubSite::from_json(*p, data).await?),
|
||||
InstanceOrGroup::Group(n) => {
|
||||
SiteOrCommunity::Community(ApubCommunity::from_json(*n, data).await?)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl SiteOrCommunity {
|
||||
fn id(&self) -> ObjectId<SiteOrCommunity> {
|
||||
match self {
|
||||
SiteOrCommunity::Site(s) => ObjectId::from(s.ap_id.clone()),
|
||||
SiteOrCommunity::Community(c) => ObjectId::from(c.ap_id.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type SiteOrCommunity = Either<ApubSite, ApubCommunity>;
|
||||
|
||||
async fn generate_cc(target: &SiteOrCommunity, pool: &mut DbPool<'_>) -> LemmyResult<Vec<Url>> {
|
||||
Ok(match target {
|
||||
SiteOrCommunity::Site(_) => Site::read_remote_sites(pool)
|
||||
SiteOrCommunity::Left(_) => Site::read_remote_sites(pool)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|s| s.ap_id.into())
|
||||
.collect(),
|
||||
SiteOrCommunity::Community(c) => vec![c.id()],
|
||||
SiteOrCommunity::Right(c) => vec![c.id().clone()],
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -131,7 +41,7 @@ pub(crate) async fn send_ban_from_site(
|
|||
expires: Option<i64>,
|
||||
context: Data<LemmyContext>,
|
||||
) -> LemmyResult<()> {
|
||||
let site = SiteOrCommunity::Site(Site::read_local(&mut context.pool()).await?.into());
|
||||
let site = SiteOrCommunity::Left(Site::read_local(&mut context.pool()).await?.into());
|
||||
let expires = check_expire_time(expires)?;
|
||||
|
||||
if ban {
|
||||
|
@ -172,7 +82,7 @@ pub(crate) async fn send_ban_from_community(
|
|||
|
||||
if data.ban {
|
||||
BlockUser::send(
|
||||
&SiteOrCommunity::Community(community),
|
||||
&SiteOrCommunity::Right(community),
|
||||
&banned_person.into(),
|
||||
&mod_.into(),
|
||||
data.remove_or_restore_data.unwrap_or(false),
|
||||
|
@ -183,7 +93,7 @@ pub(crate) async fn send_ban_from_community(
|
|||
.await
|
||||
} else {
|
||||
UndoBlockUser::send(
|
||||
&SiteOrCommunity::Community(community),
|
||||
&SiteOrCommunity::Right(community),
|
||||
&banned_person.into(),
|
||||
&mod_.into(),
|
||||
data.remove_or_restore_data.unwrap_or(false),
|
||||
|
@ -195,7 +105,7 @@ pub(crate) async fn send_ban_from_community(
|
|||
}
|
||||
|
||||
fn to(target: &SiteOrCommunity) -> LemmyResult<Vec<Url>> {
|
||||
Ok(if let SiteOrCommunity::Community(c) = target {
|
||||
Ok(if let SiteOrCommunity::Right(c) = target {
|
||||
generate_to(c)?
|
||||
} else {
|
||||
vec![public()]
|
||||
|
|
|
@ -13,7 +13,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
kinds::activity::UndoType,
|
||||
protocol::verification::verify_domains_match,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Actor, Object},
|
||||
};
|
||||
use lemmy_api_utils::{
|
||||
context::LemmyContext,
|
||||
|
@ -49,7 +49,7 @@ impl UndoBlockUser {
|
|||
|
||||
let id = generate_activity_id(UndoType::Undo, context)?;
|
||||
let undo = UndoBlockUser {
|
||||
actor: mod_.id().into(),
|
||||
actor: mod_.id().clone().into(),
|
||||
to,
|
||||
object: block,
|
||||
cc: generate_cc(target, &mut context.pool()).await?,
|
||||
|
@ -60,11 +60,11 @@ impl UndoBlockUser {
|
|||
|
||||
let mut inboxes = ActivitySendTargets::to_inbox(user.shared_inbox_or_inbox());
|
||||
match target {
|
||||
SiteOrCommunity::Site(_) => {
|
||||
SiteOrCommunity::Left(_) => {
|
||||
inboxes.set_all_instances();
|
||||
send_lemmy_activity(context, undo, mod_, inboxes, false).await
|
||||
}
|
||||
SiteOrCommunity::Community(c) => {
|
||||
SiteOrCommunity::Right(c) => {
|
||||
let activity = AnnouncableActivities::UndoBlockUser(undo);
|
||||
send_activity_in_community(activity, mod_, c, inboxes, true, context).await
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ impl UndoBlockUser {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for UndoBlockUser {
|
||||
impl Activity for UndoBlockUser {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
@ -97,7 +97,7 @@ impl ActivityHandler for UndoBlockUser {
|
|||
let blocked_person = self.object.object.dereference(context).await?;
|
||||
let pool = &mut context.pool();
|
||||
match self.object.target.dereference(context).await? {
|
||||
SiteOrCommunity::Site(site) => {
|
||||
SiteOrCommunity::Left(site) => {
|
||||
verify_is_public(&self.to, &self.cc)?;
|
||||
let form = InstanceBanForm::new(blocked_person.id, site.instance_id, expires_at);
|
||||
InstanceActions::unban(pool, &form).await?;
|
||||
|
@ -123,7 +123,7 @@ impl ActivityHandler for UndoBlockUser {
|
|||
};
|
||||
ModBan::create(&mut context.pool(), &form).await?;
|
||||
}
|
||||
SiteOrCommunity::Community(community) => {
|
||||
SiteOrCommunity::Right(community) => {
|
||||
verify_visibility(&self.to, &self.cc, &community)?;
|
||||
let community_user_ban_form = CommunityPersonBanForm::new(community.id, blocked_person.id);
|
||||
CommunityActions::unban(&mut context.pool(), &community_user_ban_form).await?;
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
use activitypub_federation::{
|
||||
config::Data,
|
||||
kinds::activity::AnnounceType,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Object},
|
||||
};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_apub_objects::{
|
||||
|
@ -25,7 +25,7 @@ use serde_json::Value;
|
|||
use url::Url;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for RawAnnouncableActivities {
|
||||
impl Activity for RawAnnouncableActivities {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
@ -70,6 +70,12 @@ impl ActivityHandler for RawAnnouncableActivities {
|
|||
}
|
||||
}
|
||||
|
||||
impl Id for RawAnnouncableActivities {
|
||||
fn id(&self) -> &Url {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl AnnounceActivity {
|
||||
pub(crate) fn new(
|
||||
object: RawAnnouncableActivities,
|
||||
|
@ -84,7 +90,7 @@ impl AnnounceActivity {
|
|||
let id =
|
||||
generate_announce_activity_id(inner_kind, &context.settings().get_protocol_and_hostname())?;
|
||||
Ok(AnnounceActivity {
|
||||
actor: community.id().into(),
|
||||
actor: community.id().clone().into(),
|
||||
to: generate_to(community)?,
|
||||
object: IdOrNestedObject::NestedObject(object),
|
||||
cc: community
|
||||
|
@ -129,7 +135,7 @@ impl AnnounceActivity {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for AnnounceActivity {
|
||||
impl Activity for AnnounceActivity {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
@ -163,12 +169,6 @@ impl ActivityHandler for AnnounceActivity {
|
|||
}
|
||||
}
|
||||
|
||||
impl Id for RawAnnouncableActivities {
|
||||
fn object_id(&self) -> &Url {
|
||||
ActivityHandler::id(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RawAnnouncableActivities> for AnnouncableActivities {
|
||||
type Error = serde_json::error::Error;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
kinds::activity::AddType,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Actor, Object},
|
||||
};
|
||||
use lemmy_api_utils::{
|
||||
context::LemmyContext,
|
||||
|
@ -47,11 +47,11 @@ impl CollectionAdd {
|
|||
) -> LemmyResult<()> {
|
||||
let id = generate_activity_id(AddType::Add, context)?;
|
||||
let add = CollectionAdd {
|
||||
actor: actor.id().into(),
|
||||
actor: actor.id().clone().into(),
|
||||
to: generate_to(community)?,
|
||||
object: added_mod.id(),
|
||||
object: added_mod.id().clone(),
|
||||
target: generate_moderators_url(&community.ap_id)?.into(),
|
||||
cc: vec![community.id()],
|
||||
cc: vec![community.id().clone()],
|
||||
kind: AddType::Add,
|
||||
id: id.clone(),
|
||||
};
|
||||
|
@ -69,11 +69,11 @@ impl CollectionAdd {
|
|||
) -> LemmyResult<()> {
|
||||
let id = generate_activity_id(AddType::Add, context)?;
|
||||
let add = CollectionAdd {
|
||||
actor: actor.id().into(),
|
||||
actor: actor.id().clone().into(),
|
||||
to: generate_to(community)?,
|
||||
object: featured_post.ap_id.clone().into(),
|
||||
target: generate_featured_url(&community.ap_id)?.into(),
|
||||
cc: vec![community.id()],
|
||||
cc: vec![community.id().clone()],
|
||||
kind: AddType::Add,
|
||||
id: id.clone(),
|
||||
};
|
||||
|
@ -91,7 +91,7 @@ impl CollectionAdd {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for CollectionAdd {
|
||||
impl Activity for CollectionAdd {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
kinds::activity::RemoveType,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Actor, Object},
|
||||
};
|
||||
use lemmy_api_utils::{
|
||||
context::LemmyContext,
|
||||
|
@ -42,12 +42,12 @@ impl CollectionRemove {
|
|||
) -> LemmyResult<()> {
|
||||
let id = generate_activity_id(RemoveType::Remove, context)?;
|
||||
let remove = CollectionRemove {
|
||||
actor: actor.id().into(),
|
||||
actor: actor.id().clone().into(),
|
||||
to: generate_to(community)?,
|
||||
object: removed_mod.id(),
|
||||
object: removed_mod.id().clone(),
|
||||
target: generate_moderators_url(&community.ap_id)?.into(),
|
||||
id: id.clone(),
|
||||
cc: vec![community.id()],
|
||||
cc: vec![community.id().clone()],
|
||||
kind: RemoveType::Remove,
|
||||
};
|
||||
|
||||
|
@ -64,11 +64,11 @@ impl CollectionRemove {
|
|||
) -> LemmyResult<()> {
|
||||
let id = generate_activity_id(RemoveType::Remove, context)?;
|
||||
let remove = CollectionRemove {
|
||||
actor: actor.id().into(),
|
||||
actor: actor.id().clone().into(),
|
||||
to: generate_to(community)?,
|
||||
object: featured_post.ap_id.clone().into(),
|
||||
target: generate_featured_url(&community.ap_id)?.into(),
|
||||
cc: vec![community.id()],
|
||||
cc: vec![community.id().clone()],
|
||||
kind: RemoveType::Remove,
|
||||
id: id.clone(),
|
||||
};
|
||||
|
@ -86,7 +86,7 @@ impl CollectionRemove {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for CollectionRemove {
|
||||
impl Activity for CollectionRemove {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
kinds::activity::UndoType,
|
||||
traits::ActivityHandler,
|
||||
traits::Activity,
|
||||
};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_apub_objects::{
|
||||
|
@ -36,7 +36,7 @@ use lemmy_utils::error::{LemmyError, LemmyResult};
|
|||
use url::Url;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for LockPage {
|
||||
impl Activity for LockPage {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
@ -80,7 +80,7 @@ impl ActivityHandler for LockPage {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for UndoLockPage {
|
||||
impl Activity for UndoLockPage {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
kinds::activity::FlagType,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Object},
|
||||
};
|
||||
use either::Either;
|
||||
use lemmy_api_utils::{
|
||||
|
@ -54,8 +54,8 @@ impl Report {
|
|||
let kind = FlagType::Flag;
|
||||
let id = generate_activity_id(kind.clone(), context)?;
|
||||
Ok(Report {
|
||||
actor: actor.id().into(),
|
||||
to: [receiver.id().into()],
|
||||
actor: actor.id().clone().into(),
|
||||
to: [receiver.id().clone().into()],
|
||||
object: ReportObject::Lemmy(object_id.clone()),
|
||||
summary: reason,
|
||||
content: None,
|
||||
|
@ -79,7 +79,7 @@ impl Report {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for Report {
|
||||
impl Activity for Report {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
protocol::verification::verify_urls_match,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Object},
|
||||
};
|
||||
use either::Either;
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
|
@ -49,8 +49,8 @@ impl ResolveReport {
|
|||
let id = generate_activity_id(kind.clone(), &context)?;
|
||||
let object = Report::new(&object_id, report_creator, receiver, None, &context)?;
|
||||
let resolve = ResolveReport {
|
||||
actor: actor.id().into(),
|
||||
to: [receiver.id().into()],
|
||||
actor: actor.id().clone().into(),
|
||||
to: [receiver.id().clone().into()],
|
||||
object,
|
||||
kind,
|
||||
id: id.clone(),
|
||||
|
@ -62,7 +62,7 @@ impl ResolveReport {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for ResolveReport {
|
||||
impl Activity for ResolveReport {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
use activitypub_federation::{
|
||||
config::Data,
|
||||
kinds::{activity::UpdateType, public},
|
||||
traits::{ActivityHandler, Actor, Object},
|
||||
traits::{Activity, Object},
|
||||
};
|
||||
use either::Either;
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
|
@ -44,10 +44,10 @@ pub(crate) async fn send_update_community(
|
|||
let actor: ApubPerson = actor.into();
|
||||
let id = generate_activity_id(UpdateType::Update, &context)?;
|
||||
let update = Update {
|
||||
actor: actor.id().into(),
|
||||
actor: actor.id().clone().into(),
|
||||
to: generate_to(&community)?,
|
||||
object: Either::Left(community.clone().into_json(&context).await?),
|
||||
cc: vec![community.id()],
|
||||
cc: vec![community.id().clone()],
|
||||
kind: UpdateType::Update,
|
||||
id: id.clone(),
|
||||
};
|
||||
|
@ -73,7 +73,7 @@ pub(crate) async fn send_update_multi_community(
|
|||
let actor: ApubPerson = actor.into();
|
||||
let id = generate_activity_id(UpdateType::Update, &context)?;
|
||||
let update = Update {
|
||||
actor: actor.id().into(),
|
||||
actor: actor.id().clone().into(),
|
||||
to: vec![multi.ap_id.clone().into(), public()],
|
||||
object: Either::Right(multi.clone().into_json(&context).await?),
|
||||
cc: vec![],
|
||||
|
@ -88,7 +88,7 @@ pub(crate) async fn send_update_multi_community(
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for Update {
|
||||
impl Activity for Update {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
protocol::verification::{verify_domains_match, verify_urls_match},
|
||||
traits::{ActivityHandler, Actor, Object},
|
||||
traits::{Activity, Actor, Object},
|
||||
};
|
||||
use lemmy_api_utils::{
|
||||
build_response::send_local_notifs,
|
||||
|
@ -65,7 +65,7 @@ impl CreateOrUpdateNote {
|
|||
let note = ApubComment(comment).into_json(&context).await?;
|
||||
|
||||
let create_or_update = CreateOrUpdateNote {
|
||||
actor: person.id().into(),
|
||||
actor: person.id().clone().into(),
|
||||
to: generate_to(&community)?,
|
||||
cc: note.cc.clone(),
|
||||
tag: note.tag.clone(),
|
||||
|
@ -103,7 +103,7 @@ impl CreateOrUpdateNote {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for CreateOrUpdateNote {
|
||||
impl Activity for CreateOrUpdateNote {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::protocol::activities::create_or_update::{
|
|||
note_wrapper::CreateOrUpdateNoteWrapper,
|
||||
private_message::CreateOrUpdatePrivateMessage,
|
||||
};
|
||||
use activitypub_federation::{config::Data, traits::ActivityHandler};
|
||||
use activitypub_federation::{config::Data, traits::Activity};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_apub_objects::{objects::community::ApubCommunity, utils::protocol::InCommunity};
|
||||
use lemmy_utils::error::{LemmyError, LemmyResult};
|
||||
|
@ -14,7 +14,7 @@ use url::Url;
|
|||
/// makes it difficult to distinguish them. This wrapper handles receiving of both types, and
|
||||
/// routes them to the correct handler.
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for CreateOrUpdateNoteWrapper {
|
||||
impl Activity for CreateOrUpdateNoteWrapper {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
use activitypub_federation::{
|
||||
config::Data,
|
||||
protocol::verification::{verify_domains_match, verify_urls_match},
|
||||
traits::{ActivityHandler, Actor, Object},
|
||||
traits::{Activity, Object},
|
||||
};
|
||||
use lemmy_api_utils::{build_response::send_local_notifs, context::LemmyContext};
|
||||
use lemmy_apub_objects::{
|
||||
|
@ -47,10 +47,10 @@ impl CreateOrUpdatePage {
|
|||
) -> LemmyResult<CreateOrUpdatePage> {
|
||||
let id = generate_activity_id(kind.clone(), context)?;
|
||||
Ok(CreateOrUpdatePage {
|
||||
actor: actor.id().into(),
|
||||
actor: actor.id().clone().into(),
|
||||
to: generate_to(community)?,
|
||||
object: post.into_json(context).await?,
|
||||
cc: vec![community.id()],
|
||||
cc: vec![community.id().clone()],
|
||||
kind,
|
||||
id: id.clone(),
|
||||
})
|
||||
|
@ -85,7 +85,7 @@ impl CreateOrUpdatePage {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for CreateOrUpdatePage {
|
||||
impl Activity for CreateOrUpdatePage {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
use activitypub_federation::{
|
||||
config::Data,
|
||||
protocol::verification::{verify_domains_match, verify_urls_match},
|
||||
traits::{ActivityHandler, Actor, Object},
|
||||
traits::{Activity, Actor, Object},
|
||||
};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_apub_objects::objects::{person::ApubPerson, private_message::ApubPrivateMessage};
|
||||
|
@ -28,8 +28,8 @@ pub(crate) async fn send_create_or_update_pm(
|
|||
let id = generate_activity_id(kind.clone(), &context)?;
|
||||
let create_or_update = CreateOrUpdatePrivateMessage {
|
||||
id: id.clone(),
|
||||
actor: actor.id().into(),
|
||||
to: [recipient.id().into()],
|
||||
actor: actor.id().clone().into(),
|
||||
to: [recipient.id().clone().into()],
|
||||
object: ApubPrivateMessage(pm_view.private_message.clone())
|
||||
.into_json(&context)
|
||||
.await?,
|
||||
|
@ -40,7 +40,7 @@ pub(crate) async fn send_create_or_update_pm(
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for CreateOrUpdatePrivateMessage {
|
||||
impl Activity for CreateOrUpdatePrivateMessage {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
},
|
||||
protocol::{activities::deletion::delete::Delete, IdOrNestedObject},
|
||||
};
|
||||
use activitypub_federation::{config::Data, kinds::activity::DeleteType, traits::ActivityHandler};
|
||||
use activitypub_federation::{config::Data, kinds::activity::DeleteType, traits::Activity};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_apub_objects::objects::person::ApubPerson;
|
||||
use lemmy_db_schema::{
|
||||
|
@ -31,7 +31,7 @@ use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResul
|
|||
use url::Url;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for Delete {
|
||||
impl Activity for Delete {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
@ -91,7 +91,7 @@ impl Delete {
|
|||
Ok(Delete {
|
||||
actor: actor.ap_id.clone().into(),
|
||||
to,
|
||||
object: IdOrNestedObject::Id(object.id()),
|
||||
object: IdOrNestedObject::Id(object.id().clone()),
|
||||
cc: cc.into_iter().collect(),
|
||||
kind: DeleteType::Delete,
|
||||
summary,
|
||||
|
|
|
@ -93,10 +93,24 @@ pub(crate) async fn send_apub_delete_private_message(
|
|||
let deletable = DeletableObjects::PrivateMessage(pm.into());
|
||||
let inbox = ActivitySendTargets::to_inbox(recipient.shared_inbox_or_inbox());
|
||||
if deleted {
|
||||
let delete: Delete = Delete::new(actor, deletable, vec![recipient.id()], None, None, &context)?;
|
||||
let delete: Delete = Delete::new(
|
||||
actor,
|
||||
deletable,
|
||||
vec![recipient.id().clone()],
|
||||
None,
|
||||
None,
|
||||
&context,
|
||||
)?;
|
||||
send_lemmy_activity(&context, delete, actor, inbox, true).await?;
|
||||
} else {
|
||||
let undo = UndoDelete::new(actor, deletable, vec![recipient.id()], None, None, &context)?;
|
||||
let undo = UndoDelete::new(
|
||||
actor,
|
||||
deletable,
|
||||
vec![recipient.id().clone()],
|
||||
None,
|
||||
None,
|
||||
&context,
|
||||
)?;
|
||||
send_lemmy_activity(&context, undo, actor, inbox, true).await?;
|
||||
};
|
||||
Ok(())
|
||||
|
@ -150,13 +164,13 @@ impl DeletableObjects {
|
|||
Err(diesel::NotFound.into())
|
||||
}
|
||||
|
||||
pub(crate) fn id(&self) -> Url {
|
||||
pub(crate) fn id(&self) -> &Url {
|
||||
match self {
|
||||
DeletableObjects::Community(c) => c.id(),
|
||||
DeletableObjects::Person(p) => p.id(),
|
||||
DeletableObjects::Comment(c) => c.ap_id.clone().into(),
|
||||
DeletableObjects::Post(p) => p.ap_id.clone().into(),
|
||||
DeletableObjects::PrivateMessage(p) => p.ap_id.clone().into(),
|
||||
DeletableObjects::Comment(c) => c.ap_id.inner(),
|
||||
DeletableObjects::Post(p) => p.ap_id.inner(),
|
||||
DeletableObjects::PrivateMessage(p) => p.ap_id.inner(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
},
|
||||
protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||
};
|
||||
use activitypub_federation::{config::Data, kinds::activity::UndoType, traits::ActivityHandler};
|
||||
use activitypub_federation::{config::Data, kinds::activity::UndoType, traits::Activity};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_apub_objects::objects::person::ApubPerson;
|
||||
use lemmy_db_schema::{
|
||||
|
@ -28,7 +28,7 @@ use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResul
|
|||
use url::Url;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for UndoDelete {
|
||||
impl Activity for UndoDelete {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
kinds::activity::AcceptType,
|
||||
protocol::verification::verify_urls_match,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Actor, Object},
|
||||
};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_db_schema::{
|
||||
|
@ -21,8 +21,8 @@ impl AcceptFollow {
|
|||
let target = follow.object.dereference_local(context).await?;
|
||||
let person = follow.actor.clone().dereference(context).await?;
|
||||
let accept = AcceptFollow {
|
||||
actor: target.id().into(),
|
||||
to: Some([person.id().into()]),
|
||||
actor: target.id().clone().into(),
|
||||
to: Some([person.id().clone().into()]),
|
||||
object: follow,
|
||||
kind: AcceptType::Accept,
|
||||
id: generate_activity_id(AcceptType::Accept, context)?,
|
||||
|
@ -34,7 +34,7 @@ impl AcceptFollow {
|
|||
|
||||
/// Handle accepted follows
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for AcceptFollow {
|
||||
impl Activity for AcceptFollow {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
kinds::activity::FollowType,
|
||||
protocol::verification::verify_urls_match,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Actor, Object},
|
||||
};
|
||||
use either::Either::*;
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
|
@ -35,9 +35,9 @@ impl Follow {
|
|||
context: &Data<LemmyContext>,
|
||||
) -> LemmyResult<Follow> {
|
||||
Ok(Follow {
|
||||
actor: actor.id().into(),
|
||||
object: target.id().into(),
|
||||
to: Some([target.id().into()]),
|
||||
actor: actor.id().clone().into(),
|
||||
object: target.id().clone().into(),
|
||||
to: Some([target.id().clone().into()]),
|
||||
kind: FollowType::Follow,
|
||||
id: generate_activity_id(FollowType::Follow, context)?,
|
||||
})
|
||||
|
@ -55,7 +55,7 @@ impl Follow {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for Follow {
|
||||
impl Activity for Follow {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::protocol::activities::following::{
|
|||
reject::RejectFollow,
|
||||
undo_follow::UndoFollow,
|
||||
};
|
||||
use activitypub_federation::{config::Data, kinds::activity::FollowType, traits::ActivityHandler};
|
||||
use activitypub_federation::{config::Data, kinds::activity::FollowType, traits::Activity};
|
||||
use either::Either::*;
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_apub_objects::objects::{person::ApubPerson, CommunityOrMulti, UserOrCommunityOrMulti};
|
||||
|
@ -60,14 +60,14 @@ pub async fn send_accept_or_reject_follow(
|
|||
}
|
||||
|
||||
/// Wrapper type which is needed because we cant implement ActorT for Either.
|
||||
async fn send_activity_from_user_or_community_or_multi<Activity>(
|
||||
async fn send_activity_from_user_or_community_or_multi<A>(
|
||||
context: &Data<LemmyContext>,
|
||||
activity: Activity,
|
||||
activity: A,
|
||||
target: UserOrCommunityOrMulti,
|
||||
send_targets: ActivitySendTargets,
|
||||
) -> LemmyResult<()>
|
||||
where
|
||||
Activity: ActivityHandler + Serialize + Send + Sync + Clone + ActivityHandler<Error = LemmyError>,
|
||||
A: Activity + Serialize + Send + Sync + Clone + Activity<Error = LemmyError>,
|
||||
{
|
||||
match target {
|
||||
Left(user) => send_lemmy_activity(context, activity, &user, send_targets, true).await,
|
||||
|
|
|
@ -7,7 +7,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
kinds::activity::RejectType,
|
||||
protocol::verification::verify_urls_match,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Actor, Object},
|
||||
};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_db_schema::{
|
||||
|
@ -22,8 +22,8 @@ impl RejectFollow {
|
|||
let user_or_community = follow.object.dereference_local(context).await?;
|
||||
let person = follow.actor.clone().dereference(context).await?;
|
||||
let reject = RejectFollow {
|
||||
actor: user_or_community.id().into(),
|
||||
to: Some([person.id().into()]),
|
||||
actor: user_or_community.id().clone().into(),
|
||||
to: Some([person.id().clone().into()]),
|
||||
object: follow,
|
||||
kind: RejectType::Reject,
|
||||
id: generate_activity_id(RejectType::Reject, context)?,
|
||||
|
@ -35,7 +35,7 @@ impl RejectFollow {
|
|||
|
||||
/// Handle rejected follows
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for RejectFollow {
|
||||
impl Activity for RejectFollow {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
kinds::activity::UndoType,
|
||||
protocol::verification::verify_urls_match,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Actor, Object},
|
||||
};
|
||||
use either::Either::*;
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
|
@ -31,8 +31,8 @@ impl UndoFollow {
|
|||
) -> LemmyResult<()> {
|
||||
let object = Follow::new(actor, target, context)?;
|
||||
let undo = UndoFollow {
|
||||
actor: actor.id().into(),
|
||||
to: Some([target.id().into()]),
|
||||
actor: actor.id().clone().into(),
|
||||
to: Some([target.id().clone().into()]),
|
||||
object,
|
||||
kind: UndoType::Undo,
|
||||
id: generate_activity_id(UndoType::Undo, context)?,
|
||||
|
@ -43,7 +43,7 @@ impl UndoFollow {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for UndoFollow {
|
||||
impl Activity for UndoFollow {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
kinds::activity::AnnounceType,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Actor},
|
||||
};
|
||||
use either::Either;
|
||||
use following::send_accept_or_reject_follow;
|
||||
|
@ -137,15 +137,15 @@ fn generate_announce_activity_id(
|
|||
Url::parse(&id)
|
||||
}
|
||||
|
||||
async fn send_lemmy_activity<Activity, ActorT>(
|
||||
async fn send_lemmy_activity<A, ActorT>(
|
||||
data: &Data<LemmyContext>,
|
||||
activity: Activity,
|
||||
activity: A,
|
||||
actor: &ActorT,
|
||||
send_targets: ActivitySendTargets,
|
||||
sensitive: bool,
|
||||
) -> LemmyResult<()>
|
||||
where
|
||||
Activity: ActivityHandler + Serialize + Send + Sync + Clone + ActivityHandler<Error = LemmyError>,
|
||||
A: Activity + Serialize + Send + Sync + Clone + Activity<Error = LemmyError>,
|
||||
ActorT: Actor + GetActorType,
|
||||
{
|
||||
info!("Saving outgoing activity to queue {}", activity.id());
|
||||
|
@ -162,7 +162,7 @@ where
|
|||
send_all_instances: send_targets.all_instances,
|
||||
send_community_followers_of: send_targets.community_followers_of.map(|e| e.0),
|
||||
actor_type: actor.actor_type(),
|
||||
actor_apub_id: actor.id().into(),
|
||||
actor_apub_id: actor.id().clone().into(),
|
||||
};
|
||||
SentActivity::create(&mut data.pool(), form).await?;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
kinds::activity::UndoType,
|
||||
protocol::verification::verify_urls_match,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Object},
|
||||
};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_apub_objects::{
|
||||
|
@ -26,7 +26,7 @@ impl UndoVote {
|
|||
context: &Data<LemmyContext>,
|
||||
) -> LemmyResult<Self> {
|
||||
Ok(UndoVote {
|
||||
actor: actor.id().into(),
|
||||
actor: actor.id().clone().into(),
|
||||
object: vote,
|
||||
kind: UndoType::Undo,
|
||||
id: generate_activity_id(UndoType::Undo, context)?,
|
||||
|
@ -35,7 +35,7 @@ impl UndoVote {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for UndoVote {
|
||||
impl Activity for UndoVote {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
use activitypub_federation::{
|
||||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
traits::{ActivityHandler, Actor},
|
||||
traits::{Activity, Object},
|
||||
};
|
||||
use lemmy_api_utils::{context::LemmyContext, utils::check_bot_account};
|
||||
use lemmy_apub_objects::{
|
||||
|
@ -28,7 +28,7 @@ impl Vote {
|
|||
context: &Data<LemmyContext>,
|
||||
) -> LemmyResult<Vote> {
|
||||
Ok(Vote {
|
||||
actor: actor.id().into(),
|
||||
actor: actor.id().clone().into(),
|
||||
object: object_id,
|
||||
kind: kind.clone(),
|
||||
id: generate_activity_id(kind, context)?,
|
||||
|
@ -37,7 +37,7 @@ impl Vote {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for Vote {
|
||||
impl Activity for Vote {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ use crate::protocol::activities::{
|
|||
},
|
||||
voting::{undo_vote::UndoVote, vote::Vote},
|
||||
};
|
||||
use activitypub_federation::{config::Data, traits::ActivityHandler};
|
||||
use activitypub_federation::{config::Data, traits::Activity};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_apub_objects::{
|
||||
objects::community::ApubCommunity,
|
||||
|
@ -37,7 +37,7 @@ use url::Url;
|
|||
/// are handled correctly.
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
#[enum_delegate::implement(ActivityHandler)]
|
||||
#[enum_delegate::implement(Activity)]
|
||||
pub(crate) enum SharedInboxActivities {
|
||||
Follow(Follow),
|
||||
AcceptFollow(AcceptFollow),
|
||||
|
@ -52,7 +52,7 @@ pub(crate) enum SharedInboxActivities {
|
|||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
#[enum_delegate::implement(ActivityHandler)]
|
||||
#[enum_delegate::implement(Activity)]
|
||||
pub enum AnnouncableActivities {
|
||||
CreateOrUpdateNoteWrapper(CreateOrUpdateNoteWrapper),
|
||||
CreateOrUpdatePost(CreateOrUpdatePage),
|
||||
|
|
|
@ -13,7 +13,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
kinds::collection::OrderedCollectionType,
|
||||
protocol::verification::verify_domains_match,
|
||||
traits::{ActivityHandler, Collection},
|
||||
traits::{Activity, Collection},
|
||||
};
|
||||
use futures::future::join_all;
|
||||
use lemmy_api_utils::{context::LemmyContext, utils::generate_outbox_url};
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use super::check_community_content_fetchable;
|
||||
use crate::http::{create_apub_response, create_apub_tombstone_response, redirect_remote_object};
|
||||
use activitypub_federation::{config::Data, traits::Object};
|
||||
use actix_web::{web::Path, HttpRequest, HttpResponse};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
|
@ -9,7 +8,7 @@ use lemmy_db_schema::{
|
|||
source::{comment::Comment, community::Community, post::Post},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
use lemmy_utils::{error::LemmyResult, FEDERATION_CONTEXT};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -30,11 +29,5 @@ pub(crate) async fn get_apub_comment(
|
|||
let community = Community::read(&mut context.pool(), post.community_id).await?;
|
||||
check_community_content_fetchable(&community, &request, &context).await?;
|
||||
|
||||
if !comment.local {
|
||||
Ok(redirect_remote_object(&comment.ap_id))
|
||||
} else if !comment.deleted && !comment.removed {
|
||||
create_apub_response(&comment.into_json(&context).await?)
|
||||
} else {
|
||||
create_apub_tombstone_response(comment.ap_id.clone())
|
||||
}
|
||||
comment.http_response(&FEDERATION_CONTEXT, &context).await
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@ use crate::{
|
|||
community_outbox::ApubCommunityOutbox,
|
||||
},
|
||||
fetcher::get_instance_id,
|
||||
http::{check_community_fetchable, create_apub_response, create_apub_tombstone_response},
|
||||
http::check_community_fetchable,
|
||||
};
|
||||
use activitypub_federation::{
|
||||
actix_web::signing_actor,
|
||||
actix_web::{response::create_http_response, signing_actor},
|
||||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
traits::{Collection, Object},
|
||||
|
@ -33,7 +33,10 @@ use lemmy_db_schema::{
|
|||
};
|
||||
use lemmy_db_schema_file::enums::CommunityVisibility;
|
||||
use lemmy_db_views_community_follower::CommunityFollowerView;
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyErrorType, LemmyResult},
|
||||
FEDERATION_CONTEXT,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
|
@ -57,13 +60,9 @@ pub(crate) async fn get_apub_community_http(
|
|||
.ok_or(LemmyErrorType::NotFound)?
|
||||
.into();
|
||||
|
||||
if community.deleted || community.removed {
|
||||
return create_apub_tombstone_response(community.ap_id.clone());
|
||||
}
|
||||
check_community_fetchable(&community)?;
|
||||
|
||||
let apub = community.into_json(&context).await?;
|
||||
create_apub_response(&apub)
|
||||
community.http_response(&FEDERATION_CONTEXT, &context).await
|
||||
}
|
||||
|
||||
/// Returns an empty followers collection, only populating the size (for privacy).
|
||||
|
@ -81,7 +80,7 @@ pub(crate) async fn get_apub_community_followers(
|
|||
}
|
||||
check_community_fetchable(&community)?;
|
||||
let followers = ApubCommunityFollower::read_local(&community.into(), &context).await?;
|
||||
create_apub_response(&followers)
|
||||
Ok(create_http_response(followers, &FEDERATION_CONTEXT)?)
|
||||
}
|
||||
|
||||
/// Checks if a given actor follows the private community. Returns status 200 if true.
|
||||
|
@ -132,7 +131,7 @@ pub(crate) async fn get_apub_community_outbox(
|
|||
.into();
|
||||
check_community_content_fetchable(&community, &request, &context).await?;
|
||||
let outbox = ApubCommunityOutbox::read_local(&community, &context).await?;
|
||||
create_apub_response(&outbox)
|
||||
Ok(create_http_response(outbox, &FEDERATION_CONTEXT)?)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_apub_community_moderators(
|
||||
|
@ -146,7 +145,7 @@ pub(crate) async fn get_apub_community_moderators(
|
|||
.into();
|
||||
check_community_fetchable(&community)?;
|
||||
let moderators = ApubCommunityModerators::read_local(&community, &context).await?;
|
||||
create_apub_response(&moderators)
|
||||
Ok(create_http_response(moderators, &FEDERATION_CONTEXT)?)
|
||||
}
|
||||
|
||||
/// Returns collection of featured (stickied) posts.
|
||||
|
@ -162,7 +161,7 @@ pub(crate) async fn get_apub_community_featured(
|
|||
.into();
|
||||
check_community_content_fetchable(&community, &request, &context).await?;
|
||||
let featured = ApubCommunityFeatured::read_local(&community, &context).await?;
|
||||
create_apub_response(&featured)
|
||||
Ok(create_http_response(featured, &FEDERATION_CONTEXT)?)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -179,7 +178,7 @@ pub(crate) async fn get_apub_person_multi_community(
|
|||
.await?
|
||||
.into();
|
||||
|
||||
create_apub_response(&multi.into_json(&context).await?)
|
||||
multi.http_response(&FEDERATION_CONTEXT, &context).await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_apub_person_multi_community_follows(
|
||||
|
@ -191,15 +190,16 @@ pub(crate) async fn get_apub_person_multi_community_follows(
|
|||
.into();
|
||||
|
||||
let collection = ApubFeedCollection::read_local(&multi, &context).await?;
|
||||
create_apub_response(&collection)
|
||||
Ok(create_http_response(collection, &FEDERATION_CONTEXT)?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
|
||||
use super::*;
|
||||
use activitypub_federation::protocol::tombstone::Tombstone;
|
||||
use actix_web::{body::to_bytes, test::TestRequest};
|
||||
use lemmy_apub_objects::protocol::{group::Group, tombstone::Tombstone};
|
||||
use lemmy_apub_objects::protocol::group::Group;
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
community::CommunityInsertForm,
|
||||
|
@ -211,6 +211,7 @@ pub(crate) mod tests {
|
|||
};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serial_test::serial;
|
||||
use url::Url;
|
||||
|
||||
async fn init(
|
||||
deleted: bool,
|
||||
|
@ -221,6 +222,7 @@ pub(crate) mod tests {
|
|||
|
||||
let community_form = CommunityInsertForm {
|
||||
deleted: Some(deleted),
|
||||
ap_id: Some(Url::parse("http://lemmy-alpha")?.into()),
|
||||
visibility: Some(visibility),
|
||||
..CommunityInsertForm::new(
|
||||
data.instance.id,
|
||||
|
@ -308,7 +310,6 @@ pub(crate) mod tests {
|
|||
let res = get_apub_community_outbox(path, context.clone(), request).await;
|
||||
assert!(res.is_err());
|
||||
|
||||
//Community::delete(&mut context.pool(), community.id).await?;
|
||||
data.delete(&mut context.pool()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -2,30 +2,22 @@ use crate::{activity_lists::SharedInboxActivities, fetcher::get_instance_id};
|
|||
use activitypub_federation::{
|
||||
actix_web::{
|
||||
inbox::{receive_activity_with_hook, ReceiveActivityHook},
|
||||
response::create_http_response,
|
||||
signing_actor,
|
||||
},
|
||||
config::Data,
|
||||
protocol::context::WithContext,
|
||||
traits::{ActivityHandler, Actor},
|
||||
FEDERATION_CONTENT_TYPE,
|
||||
traits::{Activity, Object},
|
||||
};
|
||||
use actix_web::{
|
||||
http::header::VARY,
|
||||
web::{self, Bytes},
|
||||
HttpRequest,
|
||||
HttpResponse,
|
||||
};
|
||||
use lemmy_api_utils::{context::LemmyContext, plugins::plugin_hook_after};
|
||||
use lemmy_apub_objects::{
|
||||
objects::{SiteOrMultiOrCommunityOrUser, UserOrCommunity},
|
||||
protocol::tombstone::Tombstone,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
newtypes::DbUrl,
|
||||
source::{
|
||||
activity::{ReceivedActivity, SentActivity},
|
||||
community::Community,
|
||||
},
|
||||
use lemmy_apub_objects::objects::{SiteOrMultiOrCommunityOrUser, UserOrCommunity};
|
||||
use lemmy_db_schema::source::{
|
||||
activity::{ReceivedActivity, SentActivity},
|
||||
community::Community,
|
||||
};
|
||||
use lemmy_db_schema_file::enums::CommunityVisibility;
|
||||
use lemmy_db_views_community_follower::CommunityFollowerView;
|
||||
|
@ -33,8 +25,8 @@ use lemmy_utils::{
|
|||
error::{FederationError, LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||
FEDERATION_CONTEXT,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{ops::Deref, time::Duration};
|
||||
use serde::Deserialize;
|
||||
use std::time::Duration;
|
||||
use tokio::time::timeout;
|
||||
use tracing::debug;
|
||||
use url::Url;
|
||||
|
@ -91,46 +83,6 @@ impl ReceiveActivityHook<SharedInboxActivities, UserOrCommunity, LemmyContext> f
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub
|
||||
/// headers.
|
||||
///
|
||||
/// actix-web doesn't allow pretty-print for json so we need to do this manually.
|
||||
fn create_apub_response<T>(data: &T) -> LemmyResult<HttpResponse>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let json = serde_json::to_string_pretty(&WithContext::new(data, FEDERATION_CONTEXT.clone()))?;
|
||||
|
||||
Ok(
|
||||
HttpResponse::Ok()
|
||||
.content_type(FEDERATION_CONTENT_TYPE)
|
||||
.insert_header((VARY, "Accept"))
|
||||
.body(json),
|
||||
)
|
||||
}
|
||||
|
||||
fn create_apub_tombstone_response<T: Into<Url>>(id: T) -> LemmyResult<HttpResponse> {
|
||||
let tombstone = Tombstone::new(id.into());
|
||||
let json = serde_json::to_string_pretty(&WithContext::new(
|
||||
tombstone,
|
||||
FEDERATION_CONTEXT.deref().clone(),
|
||||
))?;
|
||||
|
||||
Ok(
|
||||
HttpResponse::Gone()
|
||||
.content_type(FEDERATION_CONTENT_TYPE)
|
||||
.status(actix_web::http::StatusCode::GONE)
|
||||
.insert_header((VARY, "Accept"))
|
||||
.body(json),
|
||||
)
|
||||
}
|
||||
|
||||
fn redirect_remote_object(url: &DbUrl) -> HttpResponse {
|
||||
let mut res = HttpResponse::PermanentRedirect();
|
||||
res.insert_header((actix_web::http::header::LOCATION, url.as_str()));
|
||||
res.finish()
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ActivityQuery {
|
||||
type_: String,
|
||||
|
@ -140,7 +92,7 @@ pub struct ActivityQuery {
|
|||
/// Return the ActivityPub json representation of a local activity over HTTP.
|
||||
pub(crate) async fn get_activity(
|
||||
info: web::Path<ActivityQuery>,
|
||||
context: web::Data<LemmyContext>,
|
||||
context: Data<LemmyContext>,
|
||||
) -> LemmyResult<HttpResponse> {
|
||||
let settings = context.settings();
|
||||
let activity_id = Url::parse(&format!(
|
||||
|
@ -156,13 +108,12 @@ pub(crate) async fn get_activity(
|
|||
if sensitive {
|
||||
Ok(HttpResponse::Forbidden().finish())
|
||||
} else {
|
||||
create_apub_response(&activity.data)
|
||||
Ok(create_http_response(&activity.data, &FEDERATION_CONTEXT)?)
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensure that the community is public and not removed/deleted.
|
||||
fn check_community_fetchable(community: &Community) -> LemmyResult<()> {
|
||||
check_community_removed_or_deleted(community)?;
|
||||
if !community.visibility.can_federate() {
|
||||
return Err(LemmyErrorType::NotFound.into());
|
||||
}
|
||||
|
@ -176,7 +127,6 @@ async fn check_community_content_fetchable(
|
|||
context: &Data<LemmyContext>,
|
||||
) -> LemmyResult<()> {
|
||||
use CommunityVisibility::*;
|
||||
check_community_removed_or_deleted(community)?;
|
||||
match community.visibility {
|
||||
Public | Unlisted => Ok(()),
|
||||
Private => {
|
||||
|
@ -207,10 +157,3 @@ async fn check_community_content_fetchable(
|
|||
LocalOnlyPublic | LocalOnlyPrivate => Err(LemmyErrorType::NotFound.into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_community_removed_or_deleted(community: &Community) -> LemmyResult<()> {
|
||||
if community.deleted || community.removed {
|
||||
Err(LemmyErrorType::Deleted)?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
use crate::{
|
||||
http::{create_apub_response, create_apub_tombstone_response},
|
||||
protocol::collections::empty_outbox::EmptyOutbox,
|
||||
use crate::protocol::collections::empty_outbox::EmptyOutbox;
|
||||
use activitypub_federation::{
|
||||
actix_web::response::create_http_response,
|
||||
config::Data,
|
||||
traits::Object,
|
||||
};
|
||||
use activitypub_federation::{config::Data, traits::Object};
|
||||
use actix_web::{web::Path, HttpResponse};
|
||||
use lemmy_api_utils::{context::LemmyContext, utils::generate_outbox_url};
|
||||
use lemmy_apub_objects::objects::person::ApubPerson;
|
||||
use lemmy_db_schema::{source::person::Person, traits::ApubActor};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyErrorType, LemmyResult},
|
||||
FEDERATION_CONTEXT,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -21,19 +25,13 @@ pub(crate) async fn get_apub_person_http(
|
|||
context: Data<LemmyContext>,
|
||||
) -> LemmyResult<HttpResponse> {
|
||||
let user_name = info.into_inner().user_name;
|
||||
// TODO: this needs to be able to read deleted persons, so that it can send tombstones
|
||||
// This needs to be able to read deleted persons, so that it can send tombstones
|
||||
let person: ApubPerson = Person::read_from_name(&mut context.pool(), &user_name, true)
|
||||
.await?
|
||||
.ok_or(LemmyErrorType::NotFound)?
|
||||
.into();
|
||||
|
||||
if !person.deleted {
|
||||
let apub = person.into_json(&context).await?;
|
||||
|
||||
create_apub_response(&apub)
|
||||
} else {
|
||||
create_apub_tombstone_response(person.ap_id.clone())
|
||||
}
|
||||
person.http_response(&FEDERATION_CONTEXT, &context).await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_apub_person_outbox(
|
||||
|
@ -45,5 +43,5 @@ pub(crate) async fn get_apub_person_outbox(
|
|||
.ok_or(LemmyErrorType::NotFound)?;
|
||||
let outbox_id = generate_outbox_url(&person.ap_id)?.into();
|
||||
let outbox = EmptyOutbox::new(outbox_id)?;
|
||||
create_apub_response(&outbox)
|
||||
Ok(create_http_response(outbox, &FEDERATION_CONTEXT)?)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use super::check_community_content_fetchable;
|
||||
use crate::http::{create_apub_response, create_apub_tombstone_response, redirect_remote_object};
|
||||
use activitypub_federation::{config::Data, traits::Object};
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
|
@ -9,7 +8,7 @@ use lemmy_db_schema::{
|
|||
source::{community::Community, post::Post},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
use lemmy_utils::{error::LemmyResult, FEDERATION_CONTEXT};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -30,11 +29,5 @@ pub(crate) async fn get_apub_post(
|
|||
|
||||
check_community_content_fetchable(&community, &request, &context).await?;
|
||||
|
||||
if !post.local {
|
||||
Ok(redirect_remote_object(&post.ap_id))
|
||||
} else if !post.deleted && !post.removed {
|
||||
create_apub_response(&post.into_json(&context).await?)
|
||||
} else {
|
||||
create_apub_tombstone_response(post.ap_id.clone())
|
||||
}
|
||||
post.http_response(&FEDERATION_CONTEXT, &context).await
|
||||
}
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
use crate::{http::create_apub_response, protocol::collections::empty_outbox::EmptyOutbox};
|
||||
use activitypub_federation::{config::Data, traits::Object};
|
||||
use crate::protocol::collections::empty_outbox::EmptyOutbox;
|
||||
use activitypub_federation::{
|
||||
actix_web::response::create_http_response,
|
||||
config::Data,
|
||||
traits::Object,
|
||||
};
|
||||
use actix_web::HttpResponse;
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_apub_objects::objects::instance::ApubSite;
|
||||
use lemmy_db_schema::source::site::Site;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
use lemmy_utils::{error::LemmyResult, FEDERATION_CONTEXT};
|
||||
use url::Url;
|
||||
|
||||
pub(crate) async fn get_apub_site_http(context: Data<LemmyContext>) -> LemmyResult<HttpResponse> {
|
||||
let site: ApubSite = Site::read_local(&mut context.pool()).await?.into();
|
||||
|
||||
let apub = site.into_json(&context).await?;
|
||||
create_apub_response(&apub)
|
||||
site.http_response(&FEDERATION_CONTEXT, &context).await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_apub_site_outbox(context: Data<LemmyContext>) -> LemmyResult<HttpResponse> {
|
||||
|
@ -20,5 +23,5 @@ pub(crate) async fn get_apub_site_outbox(context: Data<LemmyContext>) -> LemmyRe
|
|||
context.settings().get_protocol_and_hostname()
|
||||
);
|
||||
let outbox = EmptyOutbox::new(Url::parse(&outbox_id)?)?;
|
||||
create_apub_response(&outbox)
|
||||
Ok(create_http_response(outbox, &FEDERATION_CONTEXT)?)
|
||||
}
|
||||
|
|
|
@ -44,8 +44,8 @@ impl InCommunity for BlockUser {
|
|||
async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<ApubCommunity> {
|
||||
let target = self.target.dereference(context).await?;
|
||||
let community = match target {
|
||||
SiteOrCommunity::Community(c) => c,
|
||||
SiteOrCommunity::Site(_) => return Err(anyhow!("activity is not in community").into()),
|
||||
SiteOrCommunity::Right(c) => c,
|
||||
SiteOrCommunity::Left(_) => return Err(anyhow!("activity is not in community").into()),
|
||||
};
|
||||
Ok(community)
|
||||
}
|
||||
|
|
|
@ -3,13 +3,12 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
kinds::activity::DeleteType,
|
||||
protocol::helpers::deserialize_one_or_many,
|
||||
protocol::{helpers::deserialize_one_or_many, tombstone::Tombstone},
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_apub_objects::{
|
||||
objects::{community::ApubCommunity, person::ApubPerson},
|
||||
protocol::tombstone::Tombstone,
|
||||
utils::protocol::InCommunity,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
|
|
|
@ -3,16 +3,11 @@ use lemmy_api_utils::context::LemmyContext;
|
|||
use lemmy_apub_objects::utils::protocol::Id;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use url::Url;
|
||||
|
||||
pub mod activities;
|
||||
pub(crate) mod collections;
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Unparsed(HashMap<String, serde_json::Value>);
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub(crate) enum IdOrNestedObject<Kind: Id> {
|
||||
|
@ -24,7 +19,7 @@ impl<Kind: Id + DeserializeOwned + Send> IdOrNestedObject<Kind> {
|
|||
pub(crate) fn id(&self) -> &Url {
|
||||
match self {
|
||||
IdOrNestedObject::Id(i) => i,
|
||||
IdOrNestedObject::NestedObject(n) => n.object_id(),
|
||||
IdOrNestedObject::NestedObject(n) => n.id(),
|
||||
}
|
||||
}
|
||||
pub(crate) async fn object(self, context: &Data<LemmyContext>) -> LemmyResult<Kind> {
|
||||
|
|
|
@ -18,6 +18,9 @@ doctest = false
|
|||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
full = []
|
||||
|
||||
[dependencies]
|
||||
lemmy_db_views_community_moderator = { workspace = true, features = ["full"] }
|
||||
lemmy_db_views_community_person_ban = { workspace = true, features = ["full"] }
|
||||
|
@ -25,7 +28,7 @@ lemmy_db_views_local_user = { workspace = true, features = ["full"] }
|
|||
lemmy_db_views_site = { workspace = true, features = ["full"] }
|
||||
lemmy_utils = { workspace = true, features = ["full"] }
|
||||
lemmy_db_schema = { workspace = true, features = ["full"] }
|
||||
lemmy_api_utils = { workspace = true }
|
||||
lemmy_api_utils = { workspace = true, features = ["full"] }
|
||||
activitypub_federation = { workspace = true }
|
||||
lemmy_db_schema_file = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
|
|
|
@ -74,8 +74,8 @@ impl Object for ApubComment {
|
|||
type Kind = Note;
|
||||
type Error = LemmyError;
|
||||
|
||||
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
||||
None
|
||||
fn id(&self) -> &Url {
|
||||
self.ap_id.inner()
|
||||
}
|
||||
|
||||
async fn read_from_id(
|
||||
|
@ -100,6 +100,10 @@ impl Object for ApubComment {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn is_deleted(&self) -> bool {
|
||||
self.removed || self.deleted
|
||||
}
|
||||
|
||||
async fn into_json(self, context: &Data<Self::DataType>) -> LemmyResult<Note> {
|
||||
let creator_id = self.creator_id;
|
||||
let creator = Person::read(&mut context.pool(), creator_id).await?;
|
||||
|
@ -113,7 +117,7 @@ impl Object for ApubComment {
|
|||
let parent_comment = Comment::read(&mut context.pool(), comment_id).await?;
|
||||
parent_comment.ap_id.into()
|
||||
} else {
|
||||
post.ap_id.into()
|
||||
post.ap_id.clone().into()
|
||||
};
|
||||
let language = Some(LanguageTag::new_single(self.language_id, &mut context.pool()).await?);
|
||||
let maa = collect_non_local_mentions(&self, context).await?;
|
||||
|
|
|
@ -81,6 +81,10 @@ impl Object for ApubCommunity {
|
|||
type Kind = Group;
|
||||
type Error = LemmyError;
|
||||
|
||||
fn id(&self) -> &Url {
|
||||
self.ap_id.inner()
|
||||
}
|
||||
|
||||
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
||||
Some(self.last_refreshed_at)
|
||||
}
|
||||
|
@ -105,6 +109,10 @@ impl Object for ApubCommunity {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn is_deleted(&self) -> bool {
|
||||
self.removed || self.deleted
|
||||
}
|
||||
|
||||
async fn into_json(self, data: &Data<Self::DataType>) -> LemmyResult<Group> {
|
||||
let community_id = self.id;
|
||||
let langs = CommunityLanguage::read(&mut data.pool(), community_id).await?;
|
||||
|
@ -112,7 +120,7 @@ impl Object for ApubCommunity {
|
|||
|
||||
let group = Group {
|
||||
kind: GroupType::Group,
|
||||
id: self.id().into(),
|
||||
id: self.id().clone().into(),
|
||||
preferred_username: self.name.clone(),
|
||||
name: Some(self.title.clone()),
|
||||
content: self.sidebar.as_ref().map(|d| markdown_to_html(d)),
|
||||
|
@ -243,10 +251,6 @@ impl Object for ApubCommunity {
|
|||
}
|
||||
|
||||
impl Actor for ApubCommunity {
|
||||
fn id(&self) -> Url {
|
||||
self.ap_id.inner().clone()
|
||||
}
|
||||
|
||||
fn public_key_pem(&self) -> &str {
|
||||
&self.public_key
|
||||
}
|
||||
|
|
|
@ -69,6 +69,10 @@ impl Object for ApubSite {
|
|||
type Kind = Instance;
|
||||
type Error = LemmyError;
|
||||
|
||||
fn id(&self) -> &Url {
|
||||
self.ap_id.inner()
|
||||
}
|
||||
|
||||
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
||||
Some(self.last_refreshed_at)
|
||||
}
|
||||
|
@ -92,7 +96,7 @@ impl Object for ApubSite {
|
|||
|
||||
let instance = Instance {
|
||||
kind: ApplicationType::Application,
|
||||
id: self.id().into(),
|
||||
id: self.id().clone().into(),
|
||||
name: self.name.clone(),
|
||||
preferred_username: Some(data.domain().to_string()),
|
||||
content: self.sidebar.as_ref().map(|d| markdown_to_html(d)),
|
||||
|
@ -169,10 +173,6 @@ impl Object for ApubSite {
|
|||
}
|
||||
|
||||
impl Actor for ApubSite {
|
||||
fn id(&self) -> Url {
|
||||
self.ap_id.inner().clone()
|
||||
}
|
||||
|
||||
fn public_key_pem(&self) -> &str {
|
||||
&self.public_key
|
||||
}
|
||||
|
|
|
@ -43,6 +43,10 @@ impl Object for ApubMultiCommunity {
|
|||
type Kind = Feed;
|
||||
type Error = LemmyError;
|
||||
|
||||
fn id(&self) -> &Url {
|
||||
self.ap_id.inner()
|
||||
}
|
||||
|
||||
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
||||
Some(self.last_refreshed_at)
|
||||
}
|
||||
|
@ -62,6 +66,10 @@ impl Object for ApubMultiCommunity {
|
|||
Err(LemmyErrorType::NotFound.into())
|
||||
}
|
||||
|
||||
fn is_deleted(&self) -> bool {
|
||||
self.deleted
|
||||
}
|
||||
|
||||
async fn into_json(self, context: &Data<Self::DataType>) -> LemmyResult<Self::Kind> {
|
||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
||||
let site = ApubSite(site_view.site.clone());
|
||||
|
@ -115,10 +123,6 @@ impl Object for ApubMultiCommunity {
|
|||
}
|
||||
|
||||
impl Actor for ApubMultiCommunity {
|
||||
fn id(&self) -> Url {
|
||||
self.ap_id.inner().clone()
|
||||
}
|
||||
|
||||
fn public_key_pem(&self) -> &str {
|
||||
&self.public_key
|
||||
}
|
||||
|
|
|
@ -65,6 +65,10 @@ impl Object for ApubPerson {
|
|||
type Kind = Person;
|
||||
type Error = LemmyError;
|
||||
|
||||
fn id(&self) -> &Url {
|
||||
self.ap_id.inner()
|
||||
}
|
||||
|
||||
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
||||
Some(self.last_refreshed_at)
|
||||
}
|
||||
|
@ -89,6 +93,10 @@ impl Object for ApubPerson {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn is_deleted(&self) -> bool {
|
||||
self.deleted
|
||||
}
|
||||
|
||||
async fn into_json(self, _context: &Data<Self::DataType>) -> LemmyResult<Person> {
|
||||
let kind = if self.bot_account {
|
||||
UserTypes::Service
|
||||
|
@ -181,10 +189,6 @@ impl Object for ApubPerson {
|
|||
}
|
||||
|
||||
impl Actor for ApubPerson {
|
||||
fn id(&self) -> Url {
|
||||
self.ap_id.inner().clone()
|
||||
}
|
||||
|
||||
fn public_key_pem(&self) -> &str {
|
||||
&self.public_key
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ use activitypub_federation::{
|
|||
traits::Object,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use chrono::{DateTime, Utc};
|
||||
use chrono::Utc;
|
||||
use html2text::{from_read_with_decorator, render::TrivialDecorator};
|
||||
use lemmy_api_utils::{
|
||||
context::LemmyContext,
|
||||
|
@ -82,8 +82,8 @@ impl Object for ApubPost {
|
|||
type Kind = Page;
|
||||
type Error = LemmyError;
|
||||
|
||||
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
||||
None
|
||||
fn id(&self) -> &Url {
|
||||
self.ap_id.inner()
|
||||
}
|
||||
|
||||
async fn read_from_id(
|
||||
|
@ -108,6 +108,10 @@ impl Object for ApubPost {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn is_deleted(&self) -> bool {
|
||||
self.removed || self.deleted
|
||||
}
|
||||
|
||||
// Turn a Lemmy post into an ActivityPub page that can be sent out over the network.
|
||||
|
||||
async fn into_json(self, context: &Data<Self::DataType>) -> LemmyResult<Page> {
|
||||
|
|
|
@ -14,7 +14,7 @@ use activitypub_federation::{
|
|||
},
|
||||
traits::Object,
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
use chrono::Utc;
|
||||
use lemmy_api_utils::{
|
||||
context::LemmyContext,
|
||||
plugins::{plugin_hook_after, plugin_hook_before},
|
||||
|
@ -59,8 +59,8 @@ impl Object for ApubPrivateMessage {
|
|||
type Kind = PrivateMessage;
|
||||
type Error = LemmyError;
|
||||
|
||||
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
||||
None
|
||||
fn id(&self) -> &Url {
|
||||
self.ap_id.inner()
|
||||
}
|
||||
|
||||
async fn read_from_id(
|
||||
|
@ -79,6 +79,10 @@ impl Object for ApubPrivateMessage {
|
|||
Err(LemmyErrorType::NotFound.into())
|
||||
}
|
||||
|
||||
fn is_deleted(&self) -> bool {
|
||||
self.removed || self.deleted
|
||||
}
|
||||
|
||||
async fn into_json(self, context: &Data<Self::DataType>) -> LemmyResult<PrivateMessage> {
|
||||
let creator_id = self.creator_id;
|
||||
let creator = Person::read(&mut context.pool(), creator_id).await?;
|
||||
|
|
|
@ -5,7 +5,6 @@ pub mod note;
|
|||
pub mod page;
|
||||
pub mod person;
|
||||
pub mod private_message;
|
||||
pub mod tombstone;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
@ -16,9 +15,9 @@ mod tests {
|
|||
page::Page,
|
||||
person::Person,
|
||||
private_message::PrivateMessage,
|
||||
tombstone::Tombstone,
|
||||
};
|
||||
use crate::utils::test::{test_json, test_parse_lemmy_item};
|
||||
use activitypub_federation::protocol::tombstone::Tombstone;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -20,7 +20,7 @@ use activitypub_federation::{
|
|||
helpers::{deserialize_one_or_many, deserialize_skip_error},
|
||||
values::MediaTypeMarkdownOrHtml,
|
||||
},
|
||||
traits::{ActivityHandler, Object},
|
||||
traits::{Activity, Object},
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
use itertools::Itertools;
|
||||
|
@ -200,7 +200,7 @@ impl Attachment {
|
|||
|
||||
// Used for community outbox, so that it can be compatible with Pleroma/Mastodon.
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for Page {
|
||||
impl Activity for Page {
|
||||
type DataType = LemmyContext;
|
||||
type Error = LemmyError;
|
||||
fn id(&self) -> &Url {
|
||||
|
|
|
@ -3,7 +3,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
fetch::webfinger::webfinger_resolve_actor,
|
||||
kinds::link::MentionType,
|
||||
traits::Actor,
|
||||
traits::Object,
|
||||
};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_db_schema::{
|
||||
|
@ -47,7 +47,7 @@ pub async fn collect_non_local_mentions(
|
|||
context: &Data<LemmyContext>,
|
||||
) -> LemmyResult<MentionsAndAddresses> {
|
||||
let parent_creator = get_comment_parent_creator(&mut context.pool(), comment).await?;
|
||||
let mut addressed_ccs: Vec<Url> = vec![parent_creator.id()];
|
||||
let mut addressed_ccs: Vec<Url> = vec![parent_creator.id().clone()];
|
||||
|
||||
// Add the mention tag
|
||||
let parent_creator_tag = Mention {
|
||||
|
@ -77,7 +77,7 @@ pub async fn collect_non_local_mentions(
|
|||
addressed_ccs.push(person.ap_id.to_string().parse()?);
|
||||
|
||||
let mention_tag = Mention {
|
||||
href: person.id(),
|
||||
href: person.id().clone(),
|
||||
name: Some(mention.full_name()),
|
||||
kind: MentionType::Mention,
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ use activitypub_federation::{
|
|||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
kinds::object::ImageType,
|
||||
protocol::values::MediaTypeMarkdown,
|
||||
protocol::{tombstone::Tombstone, values::MediaTypeMarkdown},
|
||||
};
|
||||
use lemmy_api_utils::context::LemmyContext;
|
||||
use lemmy_db_schema::{
|
||||
|
@ -198,5 +198,11 @@ pub struct Endpoints {
|
|||
}
|
||||
|
||||
pub trait Id {
|
||||
fn object_id(&self) -> &Url;
|
||||
fn id(&self) -> &Url;
|
||||
}
|
||||
|
||||
impl Id for Tombstone {
|
||||
fn id(&self) -> &Url {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use activitypub_federation::{
|
|||
activity_sending::SendActivityTask,
|
||||
config::Data,
|
||||
protocol::context::WithContext,
|
||||
traits::ActivityHandler,
|
||||
traits::Activity,
|
||||
};
|
||||
use anyhow::{Context, Result};
|
||||
use chrono::{DateTime, Utc};
|
||||
|
@ -166,7 +166,7 @@ struct DummyActivity {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ActivityHandler for DummyActivity {
|
||||
impl Activity for DummyActivity {
|
||||
type DataType = LemmyContext;
|
||||
|
||||
type Error = LemmyError;
|
||||
|
|
Loading…
Reference in a new issue