Remove DeletableApubObject trait

refactor-apub
Felix Ableitner 2021-10-16 13:14:02 +02:00
parent e9d9bc82d8
commit d206aad282
11 changed files with 69 additions and 123 deletions

View File

@ -1,99 +0,0 @@
use crate::fetcher::post_or_comment::PostOrComment;
use lemmy_api_common::blocking;
use lemmy_db_queries::source::{
comment::Comment_,
community::Community_,
person::Person_,
post::Post_,
};
use lemmy_db_schema::source::{
comment::Comment,
community::Community,
person::Person,
post::Post,
private_message::PrivateMessage,
};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
// TODO: merge this trait with ApubObject (means that db_schema needs to depend on apub_lib)
#[async_trait::async_trait(?Send)]
pub trait DeletableApubObject {
// TODO: pass in tombstone with summary field, to decide between remove/delete
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError>;
}
#[async_trait::async_trait(?Send)]
impl DeletableApubObject for Community {
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
let id = self.id;
blocking(context.pool(), move |conn| {
Community::update_deleted(conn, id, true)
})
.await??;
Ok(())
}
}
#[async_trait::async_trait(?Send)]
impl DeletableApubObject for Person {
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
let id = self.id;
blocking(context.pool(), move |conn| Person::delete_account(conn, id)).await??;
Ok(())
}
}
#[async_trait::async_trait(?Send)]
impl DeletableApubObject for Post {
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
let id = self.id;
blocking(context.pool(), move |conn| {
Post::update_deleted(conn, id, true)
})
.await??;
Ok(())
}
}
#[async_trait::async_trait(?Send)]
impl DeletableApubObject for Comment {
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
let id = self.id;
blocking(context.pool(), move |conn| {
Comment::update_deleted(conn, id, true)
})
.await??;
Ok(())
}
}
#[async_trait::async_trait(?Send)]
impl DeletableApubObject for PostOrComment {
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
match self {
PostOrComment::Comment(c) => {
blocking(context.pool(), move |conn| {
Comment::update_deleted(conn, c.id, true)
})
.await??;
}
PostOrComment::Post(p) => {
blocking(context.pool(), move |conn| {
Post::update_deleted(conn, p.id, true)
})
.await??;
}
}
Ok(())
}
}
#[async_trait::async_trait(?Send)]
impl DeletableApubObject for PrivateMessage {
async fn delete(self, _context: &LemmyContext) -> Result<(), LemmyError> {
// do nothing, because pm can't be fetched over http
unimplemented!()
}
}

View File

@ -1,5 +1,4 @@
pub mod community; pub mod community;
pub mod deletable_apub_object;
mod fetch; mod fetch;
pub mod object_id; pub mod object_id;
pub mod post_or_comment; pub mod post_or_comment;

View File

@ -1,7 +1,4 @@
use crate::{ use crate::{fetcher::should_refetch_actor, objects::FromApub};
fetcher::{deletable_apub_object::DeletableApubObject, should_refetch_actor},
objects::FromApub,
};
use anyhow::anyhow; use anyhow::anyhow;
use diesel::{NotFound, PgConnection}; use diesel::{NotFound, PgConnection};
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
@ -26,12 +23,12 @@ static REQUEST_LIMIT: i32 = 25;
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)] #[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
pub struct ObjectId<Kind>(Url, #[serde(skip)] PhantomData<Kind>) pub struct ObjectId<Kind>(Url, #[serde(skip)] PhantomData<Kind>)
where where
Kind: FromApub + ApubObject<DataType = PgConnection> + DeletableApubObject + Send + 'static, Kind: FromApub + ApubObject<DataType = PgConnection> + Send + 'static,
for<'de2> <Kind as FromApub>::ApubType: serde::Deserialize<'de2>; for<'de2> <Kind as FromApub>::ApubType: serde::Deserialize<'de2>;
impl<Kind> ObjectId<Kind> impl<Kind> ObjectId<Kind>
where where
Kind: FromApub + ApubObject<DataType = PgConnection> + DeletableApubObject + Send + 'static, Kind: FromApub + ApubObject<DataType = PgConnection> + Send + 'static,
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>, for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
{ {
pub fn new<T>(url: T) -> Self pub fn new<T>(url: T) -> Self
@ -117,7 +114,7 @@ where
if res.status() == StatusCode::GONE { if res.status() == StatusCode::GONE {
if let Some(db_object) = db_object { if let Some(db_object) = db_object {
db_object.delete(context).await?; blocking(context.pool(), move |conn| db_object.delete(conn)).await??;
} }
return Err(anyhow!("Fetched remote object {} which was deleted", self).into()); return Err(anyhow!("Fetched remote object {} which was deleted", self).into());
} }
@ -130,7 +127,7 @@ where
impl<Kind> Display for ObjectId<Kind> impl<Kind> Display for ObjectId<Kind>
where where
Kind: FromApub + ApubObject<DataType = PgConnection> + DeletableApubObject + Send + 'static, Kind: FromApub + ApubObject<DataType = PgConnection> + Send + 'static,
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>, for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
@ -140,7 +137,7 @@ where
impl<Kind> From<ObjectId<Kind>> for Url impl<Kind> From<ObjectId<Kind>> for Url
where where
Kind: FromApub + ApubObject<DataType = PgConnection> + DeletableApubObject + Send + 'static, Kind: FromApub + ApubObject<DataType = PgConnection> + Send + 'static,
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>, for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
{ {
fn from(id: ObjectId<Kind>) -> Self { fn from(id: ObjectId<Kind>) -> Self {
@ -150,7 +147,7 @@ where
impl<Kind> From<ObjectId<Kind>> for DbUrl impl<Kind> From<ObjectId<Kind>> for DbUrl
where where
Kind: FromApub + ApubObject<DataType = PgConnection> + DeletableApubObject + Send + 'static, Kind: FromApub + ApubObject<DataType = PgConnection> + Send + 'static,
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>, for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
{ {
fn from(id: ObjectId<Kind>) -> Self { fn from(id: ObjectId<Kind>) -> Self {

View File

@ -48,6 +48,13 @@ impl ApubObject for PostOrComment {
None => Comment::read_from_apub_id(conn, object_id)?.map(PostOrComment::Comment), None => Comment::read_from_apub_id(conn, object_id)?.map(PostOrComment::Comment),
}) })
} }
fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> {
match self {
PostOrComment::Post(p) => p.delete(data),
PostOrComment::Comment(c) => c.delete(data),
}
}
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
fetcher::{deletable_apub_object::DeletableApubObject, object_id::ObjectId}, fetcher::object_id::ObjectId,
objects::{comment::Note, community::Group, person::Person as ApubPerson, post::Page, FromApub}, objects::{comment::Note, community::Group, person::Person as ApubPerson, post::Page, FromApub},
}; };
use activitystreams::chrono::NaiveDateTime; use activitystreams::chrono::NaiveDateTime;
@ -136,6 +136,15 @@ impl ApubObject for SearchableObjects {
} }
Ok(None) Ok(None)
} }
fn delete(self, conn: &Self::DataType) -> Result<(), LemmyError> {
match self {
SearchableObjects::Person(p) => p.delete(conn),
SearchableObjects::Community(c) => c.delete(conn),
SearchableObjects::Post(p) => p.delete(conn),
SearchableObjects::Comment(c) => c.delete(conn),
}
}
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
@ -158,15 +167,3 @@ impl FromApub for SearchableObjects {
}) })
} }
} }
#[async_trait::async_trait(?Send)]
impl DeletableApubObject for SearchableObjects {
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
match self {
SearchableObjects::Person(p) => p.delete(context).await,
SearchableObjects::Community(c) => c.delete(context).await,
SearchableObjects::Post(p) => p.delete(context).await,
SearchableObjects::Comment(c) => c.delete(context).await,
}
}
}

View File

@ -36,6 +36,8 @@ pub trait ApubObject {
fn read_from_apub_id(data: &Self::DataType, object_id: Url) -> Result<Option<Self>, LemmyError> fn read_from_apub_id(data: &Self::DataType, object_id: Url) -> Result<Option<Self>, LemmyError>
where where
Self: Sized; Self: Sized;
/// Marks the object as deleted in local db. Called when a tombstone is received.
fn delete(self, data: &Self::DataType) -> Result<(), LemmyError>;
} }
/// Common methods provided by ActivityPub actors (community and person). Not all methods are /// Common methods provided by ActivityPub actors (community and person). Not all methods are

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
naive_now,
schema::{comment, comment_alias_1, comment_like, comment_saved}, schema::{comment, comment_alias_1, comment_like, comment_saved},
source::post::Post, source::post::Post,
CommentId, CommentId,
@ -126,4 +127,14 @@ impl ApubObject for Comment {
let object_id: DbUrl = object_id.into(); let object_id: DbUrl = object_id.into();
Ok(comment.filter(ap_id.eq(object_id)).first::<Self>(conn).ok()) Ok(comment.filter(ap_id.eq(object_id)).first::<Self>(conn).ok())
} }
// TODO: duplicate code from Comment::update_deleted(), we should really move all impls to
// this crate so we can call that function from here
fn delete(self, conn: &PgConnection) -> Result<(), LemmyError> {
use crate::schema::comment::dsl::*;
diesel::update(comment.find(self.id))
.set((deleted.eq(true), updated.eq(naive_now())))
.get_result::<Self>(conn)?;
Ok(())
}
} }

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
naive_now,
schema::{community, community_follower, community_moderator, community_person_ban}, schema::{community, community_follower, community_moderator, community_person_ban},
CommunityId, CommunityId,
DbUrl, DbUrl,
@ -147,6 +148,14 @@ impl ApubObject for Community {
.ok(), .ok(),
) )
} }
fn delete(self, conn: &PgConnection) -> Result<(), LemmyError> {
use crate::schema::community::dsl::*;
diesel::update(community.find(self.id))
.set((deleted.eq(true), updated.eq(naive_now())))
.get_result::<Self>(conn)?;
Ok(())
}
} }
impl ActorType for Community { impl ActorType for Community {

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
naive_now,
schema::{person, person_alias_1, person_alias_2}, schema::{person, person_alias_1, person_alias_2},
DbUrl, DbUrl,
PersonId, PersonId,
@ -194,6 +195,14 @@ impl ApubObject for Person {
.ok(), .ok(),
) )
} }
fn delete(self, conn: &PgConnection) -> Result<(), LemmyError> {
use crate::schema::person::dsl::*;
diesel::update(person.find(self.id))
.set((deleted.eq(true), updated.eq(naive_now())))
.get_result::<Self>(conn)?;
Ok(())
}
} }
impl ActorType for Person { impl ActorType for Person {

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
naive_now,
schema::{post, post_like, post_read, post_saved}, schema::{post, post_like, post_read, post_saved},
CommunityId, CommunityId,
DbUrl, DbUrl,
@ -124,4 +125,12 @@ impl ApubObject for Post {
let object_id: DbUrl = object_id.into(); let object_id: DbUrl = object_id.into();
Ok(post.filter(ap_id.eq(object_id)).first::<Self>(conn).ok()) Ok(post.filter(ap_id.eq(object_id)).first::<Self>(conn).ok())
} }
fn delete(self, conn: &PgConnection) -> Result<(), LemmyError> {
use crate::schema::post::dsl::*;
diesel::update(post.find(self.id))
.set((deleted.eq(true), updated.eq(naive_now())))
.get_result::<Self>(conn)?;
Ok(())
}
} }

View File

@ -54,4 +54,9 @@ impl ApubObject for PrivateMessage {
.ok(), .ok(),
) )
} }
fn delete(self, _conn: &PgConnection) -> Result<(), LemmyError> {
// do nothing, because pm can't be fetched over http
unimplemented!()
}
} }