* Ignore old federated post edits (ref #4529) * use filter on insert * coalesce(updated, published) * avoid comment conflict clause --------- Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com>
This commit is contained in:
parent
99d585b7be
commit
0203b62a6d
8 changed files with 136 additions and 42 deletions
|
@ -29,6 +29,7 @@ use lemmy_db_schema::{
|
||||||
post::Post,
|
post::Post,
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
|
utils::naive_now,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyError, LemmyErrorType},
|
error::{LemmyError, LemmyErrorType},
|
||||||
|
@ -141,6 +142,7 @@ impl Object for ApubComment {
|
||||||
check_apub_id_valid_with_strictness(note.id.inner(), community.local, context).await?;
|
check_apub_id_valid_with_strictness(note.id.inner(), community.local, context).await?;
|
||||||
verify_is_remote_object(note.id.inner(), context.settings())?;
|
verify_is_remote_object(note.id.inner(), context.settings())?;
|
||||||
verify_person_in_community(¬e.attributed_to, &community, context).await?;
|
verify_person_in_community(¬e.attributed_to, &community, context).await?;
|
||||||
|
|
||||||
let (post, _) = note.get_parents(context).await?;
|
let (post, _) = note.get_parents(context).await?;
|
||||||
let creator = note.attributed_to.dereference(context).await?;
|
let creator = note.attributed_to.dereference(context).await?;
|
||||||
let is_mod_or_admin = is_mod_or_admin(&mut context.pool(), &creator, community.id)
|
let is_mod_or_admin = is_mod_or_admin(&mut context.pool(), &creator, community.id)
|
||||||
|
@ -184,7 +186,14 @@ impl Object for ApubComment {
|
||||||
language_id,
|
language_id,
|
||||||
};
|
};
|
||||||
let parent_comment_path = parent_comment.map(|t| t.0.path);
|
let parent_comment_path = parent_comment.map(|t| t.0.path);
|
||||||
let comment = Comment::create(&mut context.pool(), &form, parent_comment_path.as_ref()).await?;
|
let timestamp: DateTime<Utc> = note.updated.or(note.published).unwrap_or_else(naive_now);
|
||||||
|
let comment = Comment::insert_apub(
|
||||||
|
&mut context.pool(),
|
||||||
|
Some(timestamp),
|
||||||
|
&form,
|
||||||
|
parent_comment_path.as_ref(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
Ok(comment.into())
|
Ok(comment.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,7 +175,8 @@ impl Object for ApubCommunity {
|
||||||
let languages =
|
let languages =
|
||||||
LanguageTag::to_language_id_multiple(group.language, &mut context.pool()).await?;
|
LanguageTag::to_language_id_multiple(group.language, &mut context.pool()).await?;
|
||||||
|
|
||||||
let community = Community::create(&mut context.pool(), &form).await?;
|
let timestamp = group.updated.or(group.published).unwrap_or_else(naive_now);
|
||||||
|
let community = Community::insert_apub(&mut context.pool(), timestamp, &form).await?;
|
||||||
CommunityLanguage::update(&mut context.pool(), languages, community.id).await?;
|
CommunityLanguage::update(&mut context.pool(), languages, community.id).await?;
|
||||||
|
|
||||||
let community: ApubCommunity = community.into();
|
let community: ApubCommunity = community.into();
|
||||||
|
|
|
@ -41,6 +41,7 @@ use lemmy_db_schema::{
|
||||||
post::{Post, PostInsertForm, PostUpdateForm},
|
post::{Post, PostInsertForm, PostUpdateForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
|
utils::naive_now,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::CommunityModeratorView;
|
use lemmy_db_views_actor::structs::CommunityModeratorView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -270,7 +271,8 @@ impl Object for ApubPost {
|
||||||
.build()
|
.build()
|
||||||
};
|
};
|
||||||
|
|
||||||
let post = Post::create(&mut context.pool(), &form).await?;
|
let timestamp = page.updated.or(page.published).unwrap_or_else(naive_now);
|
||||||
|
let post = Post::insert_apub(&mut context.pool(), timestamp, &form).await?;
|
||||||
|
|
||||||
generate_post_link_metadata(
|
generate_post_link_metadata(
|
||||||
post.clone(),
|
post.clone(),
|
||||||
|
|
|
@ -23,6 +23,7 @@ use lemmy_db_schema::{
|
||||||
private_message::{PrivateMessage, PrivateMessageInsertForm},
|
private_message::{PrivateMessage, PrivateMessageInsertForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
|
utils::naive_now,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyError, LemmyErrorType},
|
error::{LemmyError, LemmyErrorType},
|
||||||
|
@ -142,7 +143,8 @@ impl Object for ApubPrivateMessage {
|
||||||
ap_id: Some(note.id.into()),
|
ap_id: Some(note.id.into()),
|
||||||
local: Some(false),
|
local: Some(false),
|
||||||
};
|
};
|
||||||
let pm = PrivateMessage::create(&mut context.pool(), &form).await?;
|
let timestamp = note.updated.or(note.published).unwrap_or_else(naive_now);
|
||||||
|
let pm = PrivateMessage::insert_apub(&mut context.pool(), timestamp, &form).await?;
|
||||||
Ok(pm.into())
|
Ok(pm.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
diesel::DecoratableTarget,
|
||||||
newtypes::{CommentId, DbUrl, PersonId},
|
newtypes::{CommentId, DbUrl, PersonId},
|
||||||
schema::comment,
|
schema::comment,
|
||||||
source::comment::{
|
source::comment::{
|
||||||
|
@ -11,8 +12,9 @@ use crate::{
|
||||||
CommentUpdateForm,
|
CommentUpdateForm,
|
||||||
},
|
},
|
||||||
traits::{Crud, Likeable, Saveable},
|
traits::{Crud, Likeable, Saveable},
|
||||||
utils::{get_conn, naive_now, DbPool, DELETED_REPLACEMENT_TEXT},
|
utils::{functions::coalesce, get_conn, naive_now, DbPool, DELETED_REPLACEMENT_TEXT},
|
||||||
};
|
};
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
dsl::{insert_into, sql_query},
|
dsl::{insert_into, sql_query},
|
||||||
result::Error,
|
result::Error,
|
||||||
|
@ -59,6 +61,15 @@ impl Comment {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
comment_form: &CommentInsertForm,
|
comment_form: &CommentInsertForm,
|
||||||
parent_path: Option<&Ltree>,
|
parent_path: Option<&Ltree>,
|
||||||
|
) -> Result<Comment, Error> {
|
||||||
|
Self::insert_apub(pool, None, comment_form, parent_path).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn insert_apub(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
timestamp: Option<DateTime<Utc>>,
|
||||||
|
comment_form: &CommentInsertForm,
|
||||||
|
parent_path: Option<&Ltree>,
|
||||||
) -> Result<Comment, Error> {
|
) -> Result<Comment, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
|
@ -67,13 +78,21 @@ impl Comment {
|
||||||
.run(|conn| {
|
.run(|conn| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// Insert, to get the id
|
// Insert, to get the id
|
||||||
let inserted_comment = insert_into(comment::table)
|
let inserted_comment = if let Some(timestamp) = timestamp {
|
||||||
|
insert_into(comment::table)
|
||||||
.values(comment_form)
|
.values(comment_form)
|
||||||
.on_conflict(comment::ap_id)
|
.on_conflict(comment::ap_id)
|
||||||
|
.filter_target(coalesce(comment::updated, comment::published).lt(timestamp))
|
||||||
.do_update()
|
.do_update()
|
||||||
.set(comment_form)
|
.set(comment_form)
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
.await?;
|
.await?
|
||||||
|
} else {
|
||||||
|
insert_into(comment::table)
|
||||||
|
.values(comment_form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
.await?
|
||||||
|
};
|
||||||
|
|
||||||
let comment_id = inserted_comment.id;
|
let comment_id = inserted_comment.id;
|
||||||
|
|
||||||
|
@ -129,6 +148,7 @@ where ca.comment_id = c.id"
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_from_apub_id(
|
pub async fn read_from_apub_id(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
object_id: Url,
|
object_id: Url,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
diesel::DecoratableTarget,
|
||||||
newtypes::{CommunityId, DbUrl, PersonId},
|
newtypes::{CommunityId, DbUrl, PersonId},
|
||||||
schema::{community, community_follower, instance},
|
schema::{community, community_follower, instance},
|
||||||
source::{
|
source::{
|
||||||
|
@ -17,9 +18,14 @@ use crate::{
|
||||||
post::Post,
|
post::Post,
|
||||||
},
|
},
|
||||||
traits::{ApubActor, Bannable, Crud, Followable, Joinable},
|
traits::{ApubActor, Bannable, Crud, Followable, Joinable},
|
||||||
utils::{functions::lower, get_conn, DbPool},
|
utils::{
|
||||||
|
functions::{coalesce, lower},
|
||||||
|
get_conn,
|
||||||
|
DbPool,
|
||||||
|
},
|
||||||
SubscribedType,
|
SubscribedType,
|
||||||
};
|
};
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
deserialize,
|
deserialize,
|
||||||
dsl,
|
dsl,
|
||||||
|
@ -44,25 +50,15 @@ impl Crud for Community {
|
||||||
type IdType = CommunityId;
|
type IdType = CommunityId;
|
||||||
|
|
||||||
async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
|
async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
|
||||||
let is_new_community = match &form.actor_id {
|
|
||||||
Some(id) => Community::read_from_apub_id(pool, id).await?.is_none(),
|
|
||||||
None => true,
|
|
||||||
};
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
// Can't do separate insert/update commands because InsertForm/UpdateForm aren't convertible
|
|
||||||
let community_ = insert_into(community::table)
|
let community_ = insert_into(community::table)
|
||||||
.values(form)
|
.values(form)
|
||||||
.on_conflict(community::actor_id)
|
|
||||||
.do_update()
|
|
||||||
.set(form)
|
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Initialize languages for new community
|
// Initialize languages for new community
|
||||||
if is_new_community {
|
|
||||||
CommunityLanguage::update(pool, vec![], community_.id).await?;
|
CommunityLanguage::update(pool, vec![], community_.id).await?;
|
||||||
}
|
|
||||||
|
|
||||||
Ok(community_)
|
Ok(community_)
|
||||||
}
|
}
|
||||||
|
@ -116,6 +112,35 @@ pub enum CollectionType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Community {
|
impl Community {
|
||||||
|
pub async fn insert_apub(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
timestamp: DateTime<Utc>,
|
||||||
|
form: &CommunityInsertForm,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let is_new_community = match &form.actor_id {
|
||||||
|
Some(id) => Community::read_from_apub_id(pool, id).await?.is_none(),
|
||||||
|
None => true,
|
||||||
|
};
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
|
// Can't do separate insert/update commands because InsertForm/UpdateForm aren't convertible
|
||||||
|
let community_ = insert_into(community::table)
|
||||||
|
.values(form)
|
||||||
|
.on_conflict(community::actor_id)
|
||||||
|
.filter_target(coalesce(community::updated, community::published).lt(timestamp))
|
||||||
|
.do_update()
|
||||||
|
.set(form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Initialize languages for new community
|
||||||
|
if is_new_community {
|
||||||
|
CommunityLanguage::update(pool, vec![], community_.id).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(community_)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the community which has a given moderators or featured url, also return the collection type
|
/// Get the community which has a given moderators or featured url, also return the collection type
|
||||||
pub async fn get_by_collection_url(
|
pub async fn get_by_collection_url(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
|
|
|
@ -27,8 +27,15 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use ::url::Url;
|
use ::url::Url;
|
||||||
use chrono::Utc;
|
use chrono::{DateTime, Utc};
|
||||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl, TextExpressionMethods};
|
use diesel::{
|
||||||
|
dsl::insert_into,
|
||||||
|
result::Error,
|
||||||
|
DecoratableTarget,
|
||||||
|
ExpressionMethods,
|
||||||
|
QueryDsl,
|
||||||
|
TextExpressionMethods,
|
||||||
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
@ -42,9 +49,6 @@ impl Crud for Post {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
insert_into(post::table)
|
insert_into(post::table)
|
||||||
.values(form)
|
.values(form)
|
||||||
.on_conflict(post::ap_id)
|
|
||||||
.do_update()
|
|
||||||
.set(form)
|
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -63,6 +67,22 @@ impl Crud for Post {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Post {
|
impl Post {
|
||||||
|
pub async fn insert_apub(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
timestamp: DateTime<Utc>,
|
||||||
|
form: &PostInsertForm,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
insert_into(post::table)
|
||||||
|
.values(form)
|
||||||
|
.on_conflict(post::ap_id)
|
||||||
|
.filter_target(coalesce(post::updated, post::published).lt(timestamp))
|
||||||
|
.do_update()
|
||||||
|
.set(form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn list_for_community(
|
pub async fn list_for_community(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
the_community_id: CommunityId,
|
the_community_id: CommunityId,
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
diesel::DecoratableTarget,
|
||||||
newtypes::{DbUrl, PersonId, PrivateMessageId},
|
newtypes::{DbUrl, PersonId, PrivateMessageId},
|
||||||
schema::private_message::dsl::{ap_id, private_message, read, recipient_id},
|
schema::private_message,
|
||||||
source::private_message::{PrivateMessage, PrivateMessageInsertForm, PrivateMessageUpdateForm},
|
source::private_message::{PrivateMessage, PrivateMessageInsertForm, PrivateMessageUpdateForm},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::{get_conn, DbPool},
|
utils::{functions::coalesce, get_conn, DbPool},
|
||||||
};
|
};
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
|
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
|
@ -18,11 +20,8 @@ impl Crud for PrivateMessage {
|
||||||
|
|
||||||
async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
|
async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
insert_into(private_message)
|
insert_into(private_message::table)
|
||||||
.values(form)
|
.values(form)
|
||||||
.on_conflict(ap_id)
|
|
||||||
.do_update()
|
|
||||||
.set(form)
|
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -33,7 +32,7 @@ impl Crud for PrivateMessage {
|
||||||
form: &Self::UpdateForm,
|
form: &Self::UpdateForm,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::update(private_message.find(private_message_id))
|
diesel::update(private_message::table.find(private_message_id))
|
||||||
.set(form)
|
.set(form)
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
|
@ -41,17 +40,33 @@ impl Crud for PrivateMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrivateMessage {
|
impl PrivateMessage {
|
||||||
|
pub async fn insert_apub(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
timestamp: DateTime<Utc>,
|
||||||
|
form: &PrivateMessageInsertForm,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
insert_into(private_message::table)
|
||||||
|
.values(form)
|
||||||
|
.on_conflict(private_message::ap_id)
|
||||||
|
.filter_target(coalesce(private_message::updated, private_message::published).lt(timestamp))
|
||||||
|
.do_update()
|
||||||
|
.set(form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn mark_all_as_read(
|
pub async fn mark_all_as_read(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
for_recipient_id: PersonId,
|
for_recipient_id: PersonId,
|
||||||
) -> Result<Vec<PrivateMessage>, Error> {
|
) -> Result<Vec<PrivateMessage>, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::update(
|
diesel::update(
|
||||||
private_message
|
private_message::table
|
||||||
.filter(recipient_id.eq(for_recipient_id))
|
.filter(private_message::recipient_id.eq(for_recipient_id))
|
||||||
.filter(read.eq(false)),
|
.filter(private_message::read.eq(false)),
|
||||||
)
|
)
|
||||||
.set(read.eq(true))
|
.set(private_message::read.eq(true))
|
||||||
.get_results::<Self>(conn)
|
.get_results::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -63,8 +78,8 @@ impl PrivateMessage {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
let object_id: DbUrl = object_id.into();
|
let object_id: DbUrl = object_id.into();
|
||||||
Ok(
|
Ok(
|
||||||
private_message
|
private_message::table
|
||||||
.filter(ap_id.eq(object_id))
|
.filter(private_message::ap_id.eq(object_id))
|
||||||
.first::<PrivateMessage>(conn)
|
.first::<PrivateMessage>(conn)
|
||||||
.await
|
.await
|
||||||
.ok()
|
.ok()
|
||||||
|
|
Loading…
Reference in a new issue