handle deletion in new fetcher

rewrite-fetcher
Felix Ableitner 2021-09-23 18:17:33 +02:00
parent 13eca1b106
commit 64619d7eb1
3 changed files with 108 additions and 23 deletions

View File

@ -0,0 +1,85 @@
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};
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(())
}
}

View File

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

View File

@ -1,4 +1,8 @@
use crate::{fetcher::should_refetch_actor, objects::FromApub, APUB_JSON_CONTENT_TYPE};
use crate::{
fetcher::{deletable_apub_object::DeletableApubObject, should_refetch_actor},
objects::FromApub,
APUB_JSON_CONTENT_TYPE,
};
use anyhow::anyhow;
use diesel::NotFound;
use lemmy_api_common::blocking;
@ -23,18 +27,18 @@ static REQUEST_LIMIT: i32 = 25;
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
pub struct ObjectId<Kind>(Url, #[serde(skip)] PhantomData<Kind>)
where
Kind: FromApub + ApubObject + Send + 'static,
Kind: FromApub + ApubObject + DeletableApubObject + Send + 'static,
for<'de2> <Kind as FromApub>::ApubType: serde::Deserialize<'de2>;
impl<Kind> ObjectId<Kind>
where
Kind: FromApub + ApubObject + Send + 'static,
Kind: FromApub + ApubObject + DeletableApubObject + Send + 'static,
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
{
pub fn new<K, T>(url: T) -> ObjectId<K>
where
T: Into<Url>,
K: FromApub + ApubObject + Send + 'static,
K: FromApub + ApubObject + DeletableApubObject + Send + 'static,
for<'de> <K as FromApub>::ApubType: serde::Deserialize<'de>,
{
ObjectId(url.into(), PhantomData::<K>)
@ -64,13 +68,17 @@ where
// TODO: rename to should_refetch_object()
if should_refetch_actor(last_refreshed_at) {
debug!("Refetching remote object {}", self.0.as_str());
return self.dereference_remotely(context, request_counter).await;
return self
.dereference_remotely(context, request_counter, Some(object))
.await;
}
}
Ok(object)
} else {
debug!("Fetching remote object {}", self.0.as_str());
self.dereference_remotely(context, request_counter).await
self
.dereference_remotely(context, request_counter, None)
.await
}
}
@ -89,6 +97,7 @@ where
&self,
context: &LemmyContext,
request_counter: &mut i32,
db_object: Option<Kind>,
) -> Result<Kind, LemmyError> {
// dont fetch local objects this way
debug_assert!(self.0.domain() != Some(&Settings::get().hostname));
@ -109,31 +118,21 @@ where
.await?;
if res.status() == StatusCode::GONE {
self.mark_object_deleted(context).await?;
return Err(
anyhow!(
"Fetched remote object {} which was deleted",
self.0.as_str()
)
.into(),
);
if let Some(db_object) = db_object {
db_object.delete(context).await?;
}
return Err(anyhow!("Fetched remote object {} which was deleted", self).into());
}
let res2: Kind::ApubType = res.json().await?;
Ok(Kind::from_apub(&res2, context, self.inner(), request_counter).await?)
}
async fn mark_object_deleted(&self, _context: &LemmyContext) -> Result<(), LemmyError> {
// TODO: need to move methods update_deleted, update_removed etc into a trait to use them here.
// also, how do we know if the object was deleted vs removed?
todo!()
}
}
impl<Kind> Display for ObjectId<Kind>
where
Kind: FromApub + ApubObject + Send + 'static,
Kind: FromApub + ApubObject + DeletableApubObject + Send + 'static,
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
@ -143,7 +142,7 @@ where
impl<Kind> From<ObjectId<Kind>> for Url
where
Kind: FromApub + ApubObject + Send + 'static,
Kind: FromApub + ApubObject + DeletableApubObject + Send + 'static,
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
{
fn from(id: ObjectId<Kind>) -> Self {
@ -153,7 +152,7 @@ where
impl<Kind> From<ObjectId<Kind>> for DbUrl
where
Kind: FromApub + ApubObject + Send + 'static,
Kind: FromApub + ApubObject + DeletableApubObject + Send + 'static,
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
{
fn from(id: ObjectId<Kind>) -> Self {