mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-27 03:41:02 +00:00
Apub local object handling (#1297)
* Limit visibility of some traits and methods * WIP: alternative way to handle non-local object parsing * finish this * cleanup * Move check for locked post into Comment::from_apub() * Mark user as updated after fetching * Should set last_refreshed_at, not updated * Add ApubObject trait in DB, with method read_from_apub_id() * Create shared, generic implementation for `FromApub`, prefer local data * Check for community ban when parsing post/comment (fixes #1287) * Fix tests (changes in get_object_from_apub() prevented `Update` from working) * Support parsing `like.object` either as URL or object * Send out like.object as URL, instead of full object (fixes #1283) * add todo
This commit is contained in:
parent
5e57f1bcad
commit
9cc1cfc973
37 changed files with 580 additions and 532 deletions
|
@ -438,7 +438,7 @@ Sent to: Community
|
||||||
"cc": [
|
"cc": [
|
||||||
"https://ds9.lemmy.ml/c/main/"
|
"https://ds9.lemmy.ml/c/main/"
|
||||||
],
|
],
|
||||||
"object": ...
|
"object": "https://enterprise.lemmy.ml/p/123"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -465,7 +465,7 @@ Sent to: Community
|
||||||
"cc": [
|
"cc": [
|
||||||
"https://ds9.lemmy.ml/c/main/"
|
"https://ds9.lemmy.ml/c/main/"
|
||||||
],
|
],
|
||||||
"object": ...
|
"object": "https://enterprise.lemmy.ml/p/123"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ use lemmy_db::{
|
||||||
post::Post,
|
post::Post,
|
||||||
site::*,
|
site::*,
|
||||||
user_view::*,
|
user_view::*,
|
||||||
|
ApubObject,
|
||||||
Bannable,
|
Bannable,
|
||||||
Crud,
|
Crud,
|
||||||
Followable,
|
Followable,
|
||||||
|
@ -129,7 +130,7 @@ impl Perform for CreateCommunity {
|
||||||
let actor_id = make_apub_endpoint(EndpointType::Community, &data.name).to_string();
|
let actor_id = make_apub_endpoint(EndpointType::Community, &data.name).to_string();
|
||||||
let actor_id_cloned = actor_id.to_owned();
|
let actor_id_cloned = actor_id.to_owned();
|
||||||
let community_dupe = blocking(context.pool(), move |conn| {
|
let community_dupe = blocking(context.pool(), move |conn| {
|
||||||
Community::read_from_actor_id(conn, &actor_id_cloned)
|
Community::read_from_apub_id(conn, &actor_id_cloned)
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
if community_dupe.is_ok() {
|
if community_dupe.is_ok() {
|
||||||
|
|
|
@ -1,20 +1,13 @@
|
||||||
use crate::{
|
use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, NoteExt};
|
||||||
activities::receive::get_actor_as_user,
|
|
||||||
fetcher::get_or_fetch_and_insert_comment,
|
|
||||||
ActorType,
|
|
||||||
FromApub,
|
|
||||||
NoteExt,
|
|
||||||
};
|
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{ActorAndObjectRefExt, Create, Dislike, Like, Remove, Update},
|
activity::{ActorAndObjectRefExt, Create, Dislike, Like, Remove, Update},
|
||||||
base::ExtendsExt,
|
base::ExtendsExt,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
|
comment::{Comment, CommentLike, CommentLikeForm},
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
post::Post,
|
post::Post,
|
||||||
Crud,
|
|
||||||
Likeable,
|
Likeable,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs};
|
use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs};
|
||||||
|
@ -30,36 +23,22 @@ pub(crate) async fn receive_create_comment(
|
||||||
let note = NoteExt::from_any_base(create.object().to_owned().one().context(location_info!())?)?
|
let note = NoteExt::from_any_base(create.object().to_owned().one().context(location_info!())?)?
|
||||||
.context(location_info!())?;
|
.context(location_info!())?;
|
||||||
|
|
||||||
let comment =
|
let comment = Comment::from_apub(¬e, context, user.actor_id()?, request_counter).await?;
|
||||||
CommentForm::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?;
|
|
||||||
|
|
||||||
let post_id = comment.post_id;
|
let post_id = comment.post_id;
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
||||||
if post.locked {
|
|
||||||
return Err(anyhow!("Post is locked").into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let inserted_comment =
|
|
||||||
blocking(context.pool(), move |conn| Comment::upsert(conn, &comment)).await??;
|
|
||||||
|
|
||||||
// Note:
|
// Note:
|
||||||
// Although mentions could be gotten from the post tags (they are included there), or the ccs,
|
// Although mentions could be gotten from the post tags (they are included there), or the ccs,
|
||||||
// Its much easier to scrape them from the comment body, since the API has to do that
|
// Its much easier to scrape them from the comment body, since the API has to do that
|
||||||
// anyway.
|
// anyway.
|
||||||
let mentions = scrape_text_for_mentions(&inserted_comment.content);
|
let mentions = scrape_text_for_mentions(&comment.content);
|
||||||
let recipient_ids = send_local_notifs(
|
let recipient_ids =
|
||||||
mentions,
|
send_local_notifs(mentions, comment.clone(), &user, post, context.pool(), true).await?;
|
||||||
inserted_comment.clone(),
|
|
||||||
&user,
|
|
||||||
post,
|
|
||||||
context.pool(),
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Refetch the view
|
// Refetch the view
|
||||||
let comment_view = blocking(context.pool(), move |conn| {
|
let comment_view = blocking(context.pool(), move |conn| {
|
||||||
CommentView::read(conn, inserted_comment.id, None)
|
CommentView::read(conn, comment.id, None)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
@ -87,36 +66,19 @@ pub(crate) async fn receive_update_comment(
|
||||||
.context(location_info!())?;
|
.context(location_info!())?;
|
||||||
let user = get_actor_as_user(&update, context, request_counter).await?;
|
let user = get_actor_as_user(&update, context, request_counter).await?;
|
||||||
|
|
||||||
let comment =
|
let comment = Comment::from_apub(¬e, context, user.actor_id()?, request_counter).await?;
|
||||||
CommentForm::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?;
|
|
||||||
|
|
||||||
let original_comment_id =
|
let comment_id = comment.id;
|
||||||
get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter)
|
let post_id = comment.post_id;
|
||||||
.await?
|
|
||||||
.id;
|
|
||||||
|
|
||||||
let updated_comment = blocking(context.pool(), move |conn| {
|
|
||||||
Comment::update(conn, original_comment_id, &comment)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let post_id = updated_comment.post_id;
|
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
||||||
|
|
||||||
let mentions = scrape_text_for_mentions(&updated_comment.content);
|
let mentions = scrape_text_for_mentions(&comment.content);
|
||||||
let recipient_ids = send_local_notifs(
|
let recipient_ids =
|
||||||
mentions,
|
send_local_notifs(mentions, comment, &user, post, context.pool(), false).await?;
|
||||||
updated_comment,
|
|
||||||
&user,
|
|
||||||
post,
|
|
||||||
context.pool(),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Refetch the view
|
// Refetch the view
|
||||||
let comment_view = blocking(context.pool(), move |conn| {
|
let comment_view = blocking(context.pool(), move |conn| {
|
||||||
CommentView::read(conn, original_comment_id, None)
|
CommentView::read(conn, comment_id, None)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
@ -137,19 +99,13 @@ pub(crate) async fn receive_update_comment(
|
||||||
|
|
||||||
pub(crate) async fn receive_like_comment(
|
pub(crate) async fn receive_like_comment(
|
||||||
like: Like,
|
like: Like,
|
||||||
|
comment: Comment,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let note = NoteExt::from_any_base(like.object().to_owned().one().context(location_info!())?)?
|
|
||||||
.context(location_info!())?;
|
|
||||||
let user = get_actor_as_user(&like, context, request_counter).await?;
|
let user = get_actor_as_user(&like, context, request_counter).await?;
|
||||||
|
|
||||||
let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?;
|
let comment_id = comment.id;
|
||||||
|
|
||||||
let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter)
|
|
||||||
.await?
|
|
||||||
.id;
|
|
||||||
|
|
||||||
let like_form = CommentLikeForm {
|
let like_form = CommentLikeForm {
|
||||||
comment_id,
|
comment_id,
|
||||||
post_id: comment.post_id,
|
post_id: comment.post_id,
|
||||||
|
@ -188,25 +144,13 @@ pub(crate) async fn receive_like_comment(
|
||||||
|
|
||||||
pub(crate) async fn receive_dislike_comment(
|
pub(crate) async fn receive_dislike_comment(
|
||||||
dislike: Dislike,
|
dislike: Dislike,
|
||||||
|
comment: Comment,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let note = NoteExt::from_any_base(
|
|
||||||
dislike
|
|
||||||
.object()
|
|
||||||
.to_owned()
|
|
||||||
.one()
|
|
||||||
.context(location_info!())?,
|
|
||||||
)?
|
|
||||||
.context(location_info!())?;
|
|
||||||
let user = get_actor_as_user(&dislike, context, request_counter).await?;
|
let user = get_actor_as_user(&dislike, context, request_counter).await?;
|
||||||
|
|
||||||
let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?;
|
let comment_id = comment.id;
|
||||||
|
|
||||||
let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter)
|
|
||||||
.await?
|
|
||||||
.id;
|
|
||||||
|
|
||||||
let like_form = CommentLikeForm {
|
let like_form = CommentLikeForm {
|
||||||
comment_id,
|
comment_id,
|
||||||
post_id: comment.post_id,
|
post_id: comment.post_id,
|
||||||
|
|
|
@ -1,35 +1,23 @@
|
||||||
use crate::{
|
use crate::activities::receive::get_actor_as_user;
|
||||||
activities::receive::get_actor_as_user,
|
use activitystreams::activity::{Dislike, Like};
|
||||||
fetcher::get_or_fetch_and_insert_comment,
|
|
||||||
FromApub,
|
|
||||||
NoteExt,
|
|
||||||
};
|
|
||||||
use activitystreams::{activity::*, prelude::*};
|
|
||||||
use anyhow::Context;
|
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{Comment, CommentForm, CommentLike},
|
comment::{Comment, CommentLike},
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
Likeable,
|
Likeable,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{blocking, comment::CommentResponse};
|
use lemmy_structs::{blocking, comment::CommentResponse};
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation};
|
use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation};
|
||||||
|
|
||||||
pub(crate) async fn receive_undo_like_comment(
|
pub(crate) async fn receive_undo_like_comment(
|
||||||
like: &Like,
|
like: &Like,
|
||||||
|
comment: Comment,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let user = get_actor_as_user(like, context, request_counter).await?;
|
let user = get_actor_as_user(like, context, request_counter).await?;
|
||||||
let note = NoteExt::from_any_base(like.object().to_owned().one().context(location_info!())?)?
|
|
||||||
.context(location_info!())?;
|
|
||||||
|
|
||||||
let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?;
|
|
||||||
|
|
||||||
let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter)
|
|
||||||
.await?
|
|
||||||
.id;
|
|
||||||
|
|
||||||
|
let comment_id = comment.id;
|
||||||
let user_id = user.id;
|
let user_id = user.id;
|
||||||
blocking(context.pool(), move |conn| {
|
blocking(context.pool(), move |conn| {
|
||||||
CommentLike::remove(conn, user_id, comment_id)
|
CommentLike::remove(conn, user_id, comment_id)
|
||||||
|
@ -61,25 +49,13 @@ pub(crate) async fn receive_undo_like_comment(
|
||||||
|
|
||||||
pub(crate) async fn receive_undo_dislike_comment(
|
pub(crate) async fn receive_undo_dislike_comment(
|
||||||
dislike: &Dislike,
|
dislike: &Dislike,
|
||||||
|
comment: Comment,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let user = get_actor_as_user(dislike, context, request_counter).await?;
|
let user = get_actor_as_user(dislike, context, request_counter).await?;
|
||||||
let note = NoteExt::from_any_base(
|
|
||||||
dislike
|
|
||||||
.object()
|
|
||||||
.to_owned()
|
|
||||||
.one()
|
|
||||||
.context(location_info!())?,
|
|
||||||
)?
|
|
||||||
.context(location_info!())?;
|
|
||||||
|
|
||||||
let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?;
|
|
||||||
|
|
||||||
let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter)
|
|
||||||
.await?
|
|
||||||
.id;
|
|
||||||
|
|
||||||
|
let comment_id = comment.id;
|
||||||
let user_id = user.id;
|
let user_id = user.id;
|
||||||
blocking(context.pool(), move |conn| {
|
blocking(context.pool(), move |conn| {
|
||||||
CommentLike::remove(conn, user_id, comment_id)
|
CommentLike::remove(conn, user_id, comment_id)
|
||||||
|
|
|
@ -4,7 +4,7 @@ use activitystreams::{
|
||||||
base::{AnyBase, ExtendsExt},
|
base::{AnyBase, ExtendsExt},
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use lemmy_db::{community::Community, community_view::CommunityView};
|
use lemmy_db::{community::Community, community_view::CommunityView, ApubObject};
|
||||||
use lemmy_structs::{blocking, community::CommunityResponse};
|
use lemmy_structs::{blocking, community::CommunityResponse};
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation};
|
use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation};
|
||||||
|
@ -53,7 +53,7 @@ pub(crate) async fn receive_remove_community(
|
||||||
.single_xsd_any_uri()
|
.single_xsd_any_uri()
|
||||||
.context(location_info!())?;
|
.context(location_info!())?;
|
||||||
let community = blocking(context.pool(), move |conn| {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
Community::read_from_actor_id(conn, community_uri.as_str())
|
Community::read_from_apub_id(conn, community_uri.as_str())
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ pub(crate) async fn receive_undo_remove_community(
|
||||||
.single_xsd_any_uri()
|
.single_xsd_any_uri()
|
||||||
.context(location_info!())?;
|
.context(location_info!())?;
|
||||||
let community = blocking(context.pool(), move |conn| {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
Community::read_from_actor_id(conn, community_uri.as_str())
|
Community::read_from_apub_id(conn, community_uri.as_str())
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,12 @@
|
||||||
use crate::{
|
use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, PageExt};
|
||||||
activities::receive::get_actor_as_user,
|
|
||||||
fetcher::get_or_fetch_and_insert_post,
|
|
||||||
ActorType,
|
|
||||||
FromApub,
|
|
||||||
PageExt,
|
|
||||||
};
|
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{Create, Dislike, Like, Remove, Update},
|
activity::{Create, Dislike, Like, Remove, Update},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
post::{Post, PostForm, PostLike, PostLikeForm},
|
post::{Post, PostLike, PostLikeForm},
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
Crud,
|
|
||||||
Likeable,
|
Likeable,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{blocking, post::PostResponse};
|
use lemmy_structs::{blocking, post::PostResponse};
|
||||||
|
@ -29,16 +22,12 @@ pub(crate) async fn receive_create_post(
|
||||||
let page = PageExt::from_any_base(create.object().to_owned().one().context(location_info!())?)?
|
let page = PageExt::from_any_base(create.object().to_owned().one().context(location_info!())?)?
|
||||||
.context(location_info!())?;
|
.context(location_info!())?;
|
||||||
|
|
||||||
let post = PostForm::from_apub(&page, context, Some(user.actor_id()?), request_counter).await?;
|
let post = Post::from_apub(&page, context, user.actor_id()?, request_counter).await?;
|
||||||
|
|
||||||
// Using an upsert, since likes (which fetch the post), sometimes come in before the create
|
|
||||||
// resulting in double posts.
|
|
||||||
let inserted_post = blocking(context.pool(), move |conn| Post::upsert(conn, &post)).await??;
|
|
||||||
|
|
||||||
// Refetch the view
|
// Refetch the view
|
||||||
let inserted_post_id = inserted_post.id;
|
let post_id = post.id;
|
||||||
let post_view = blocking(context.pool(), move |conn| {
|
let post_view = blocking(context.pool(), move |conn| {
|
||||||
PostView::read(conn, inserted_post_id, None)
|
PostView::read(conn, post_id, None)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
@ -62,20 +51,12 @@ pub(crate) async fn receive_update_post(
|
||||||
let page = PageExt::from_any_base(update.object().to_owned().one().context(location_info!())?)?
|
let page = PageExt::from_any_base(update.object().to_owned().one().context(location_info!())?)?
|
||||||
.context(location_info!())?;
|
.context(location_info!())?;
|
||||||
|
|
||||||
let post = PostForm::from_apub(&page, context, Some(user.actor_id()?), request_counter).await?;
|
let post = Post::from_apub(&page, context, user.actor_id()?, request_counter).await?;
|
||||||
|
|
||||||
let original_post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter)
|
|
||||||
.await?
|
|
||||||
.id;
|
|
||||||
|
|
||||||
blocking(context.pool(), move |conn| {
|
|
||||||
Post::update(conn, original_post_id, &post)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
|
let post_id = post.id;
|
||||||
// Refetch the view
|
// Refetch the view
|
||||||
let post_view = blocking(context.pool(), move |conn| {
|
let post_view = blocking(context.pool(), move |conn| {
|
||||||
PostView::read(conn, original_post_id, None)
|
PostView::read(conn, post_id, None)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
@ -92,19 +73,13 @@ pub(crate) async fn receive_update_post(
|
||||||
|
|
||||||
pub(crate) async fn receive_like_post(
|
pub(crate) async fn receive_like_post(
|
||||||
like: Like,
|
like: Like,
|
||||||
|
post: Post,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let user = get_actor_as_user(&like, context, request_counter).await?;
|
let user = get_actor_as_user(&like, context, request_counter).await?;
|
||||||
let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)?
|
|
||||||
.context(location_info!())?;
|
|
||||||
|
|
||||||
let post = PostForm::from_apub(&page, context, None, request_counter).await?;
|
|
||||||
|
|
||||||
let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter)
|
|
||||||
.await?
|
|
||||||
.id;
|
|
||||||
|
|
||||||
|
let post_id = post.id;
|
||||||
let like_form = PostLikeForm {
|
let like_form = PostLikeForm {
|
||||||
post_id,
|
post_id,
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
|
@ -136,25 +111,13 @@ pub(crate) async fn receive_like_post(
|
||||||
|
|
||||||
pub(crate) async fn receive_dislike_post(
|
pub(crate) async fn receive_dislike_post(
|
||||||
dislike: Dislike,
|
dislike: Dislike,
|
||||||
|
post: Post,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let user = get_actor_as_user(&dislike, context, request_counter).await?;
|
let user = get_actor_as_user(&dislike, context, request_counter).await?;
|
||||||
let page = PageExt::from_any_base(
|
|
||||||
dislike
|
|
||||||
.object()
|
|
||||||
.to_owned()
|
|
||||||
.one()
|
|
||||||
.context(location_info!())?,
|
|
||||||
)?
|
|
||||||
.context(location_info!())?;
|
|
||||||
|
|
||||||
let post = PostForm::from_apub(&page, context, None, request_counter).await?;
|
|
||||||
|
|
||||||
let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter)
|
|
||||||
.await?
|
|
||||||
.id;
|
|
||||||
|
|
||||||
|
let post_id = post.id;
|
||||||
let like_form = PostLikeForm {
|
let like_form = PostLikeForm {
|
||||||
post_id,
|
post_id,
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
|
|
|
@ -1,35 +1,23 @@
|
||||||
use crate::{
|
use crate::activities::receive::get_actor_as_user;
|
||||||
activities::receive::get_actor_as_user,
|
use activitystreams::activity::{Dislike, Like};
|
||||||
fetcher::get_or_fetch_and_insert_post,
|
|
||||||
FromApub,
|
|
||||||
PageExt,
|
|
||||||
};
|
|
||||||
use activitystreams::{activity::*, prelude::*};
|
|
||||||
use anyhow::Context;
|
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
post::{Post, PostForm, PostLike},
|
post::{Post, PostLike},
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
Likeable,
|
Likeable,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{blocking, post::PostResponse};
|
use lemmy_structs::{blocking, post::PostResponse};
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation};
|
use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation};
|
||||||
|
|
||||||
pub(crate) async fn receive_undo_like_post(
|
pub(crate) async fn receive_undo_like_post(
|
||||||
like: &Like,
|
like: &Like,
|
||||||
|
post: Post,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let user = get_actor_as_user(like, context, request_counter).await?;
|
let user = get_actor_as_user(like, context, request_counter).await?;
|
||||||
let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)?
|
|
||||||
.context(location_info!())?;
|
|
||||||
|
|
||||||
let post = PostForm::from_apub(&page, context, None, request_counter).await?;
|
|
||||||
|
|
||||||
let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter)
|
|
||||||
.await?
|
|
||||||
.id;
|
|
||||||
|
|
||||||
|
let post_id = post.id;
|
||||||
let user_id = user.id;
|
let user_id = user.id;
|
||||||
blocking(context.pool(), move |conn| {
|
blocking(context.pool(), move |conn| {
|
||||||
PostLike::remove(conn, user_id, post_id)
|
PostLike::remove(conn, user_id, post_id)
|
||||||
|
@ -55,25 +43,13 @@ pub(crate) async fn receive_undo_like_post(
|
||||||
|
|
||||||
pub(crate) async fn receive_undo_dislike_post(
|
pub(crate) async fn receive_undo_dislike_post(
|
||||||
dislike: &Dislike,
|
dislike: &Dislike,
|
||||||
|
post: Post,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let user = get_actor_as_user(dislike, context, request_counter).await?;
|
let user = get_actor_as_user(dislike, context, request_counter).await?;
|
||||||
let page = PageExt::from_any_base(
|
|
||||||
dislike
|
|
||||||
.object()
|
|
||||||
.to_owned()
|
|
||||||
.one()
|
|
||||||
.context(location_info!())?,
|
|
||||||
)?
|
|
||||||
.context(location_info!())?;
|
|
||||||
|
|
||||||
let post = PostForm::from_apub(&page, context, None, request_counter).await?;
|
|
||||||
|
|
||||||
let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter)
|
|
||||||
.await?
|
|
||||||
.id;
|
|
||||||
|
|
||||||
|
let post_id = post.id;
|
||||||
let user_id = user.id;
|
let user_id = user.id;
|
||||||
blocking(context.pool(), move |conn| {
|
blocking(context.pool(), move |conn| {
|
||||||
PostLike::remove(conn, user_id, post_id)
|
PostLike::remove(conn, user_id, post_id)
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
check_is_apub_id_valid,
|
check_is_apub_id_valid,
|
||||||
fetcher::get_or_fetch_and_upsert_user,
|
fetcher::get_or_fetch_and_upsert_user,
|
||||||
inbox::get_activity_to_and_cc,
|
inbox::get_activity_to_and_cc,
|
||||||
FromApub,
|
objects::FromApub,
|
||||||
NoteExt,
|
NoteExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
|
@ -13,11 +13,7 @@ use activitystreams::{
|
||||||
public,
|
public,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use lemmy_db::{
|
use lemmy_db::{private_message::PrivateMessage, private_message_view::PrivateMessageView};
|
||||||
private_message::{PrivateMessage, PrivateMessageForm},
|
|
||||||
private_message_view::PrivateMessageView,
|
|
||||||
Crud,
|
|
||||||
};
|
|
||||||
use lemmy_structs::{blocking, user::PrivateMessageResponse};
|
use lemmy_structs::{blocking, user::PrivateMessageResponse};
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperation};
|
use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperation};
|
||||||
|
@ -41,15 +37,10 @@ pub(crate) async fn receive_create_private_message(
|
||||||
.context(location_info!())?;
|
.context(location_info!())?;
|
||||||
|
|
||||||
let private_message =
|
let private_message =
|
||||||
PrivateMessageForm::from_apub(¬e, context, Some(expected_domain), request_counter).await?;
|
PrivateMessage::from_apub(¬e, context, expected_domain, request_counter).await?;
|
||||||
|
|
||||||
let inserted_private_message = blocking(&context.pool(), move |conn| {
|
|
||||||
PrivateMessage::create(conn, &private_message)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let message = blocking(&context.pool(), move |conn| {
|
let message = blocking(&context.pool(), move |conn| {
|
||||||
PrivateMessageView::read(conn, inserted_private_message.id)
|
PrivateMessageView::read(conn, private_message.id)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
@ -82,24 +73,8 @@ pub(crate) async fn receive_update_private_message(
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let note = NoteExt::from_any_base(object)?.context(location_info!())?;
|
let note = NoteExt::from_any_base(object)?.context(location_info!())?;
|
||||||
|
|
||||||
let private_message_form =
|
let private_message =
|
||||||
PrivateMessageForm::from_apub(¬e, context, Some(expected_domain), request_counter).await?;
|
PrivateMessage::from_apub(¬e, context, expected_domain, request_counter).await?;
|
||||||
|
|
||||||
let private_message_ap_id = private_message_form
|
|
||||||
.ap_id
|
|
||||||
.as_ref()
|
|
||||||
.context(location_info!())?
|
|
||||||
.clone();
|
|
||||||
let private_message = blocking(&context.pool(), move |conn| {
|
|
||||||
PrivateMessage::read_from_apub_id(conn, &private_message_ap_id)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let private_message_id = private_message.id;
|
|
||||||
blocking(&context.pool(), move |conn| {
|
|
||||||
PrivateMessage::update(conn, private_message_id, &private_message_form)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let private_message_id = private_message.id;
|
let private_message_id = private_message.id;
|
||||||
let message = blocking(&context.pool(), move |conn| {
|
let message = blocking(&context.pool(), move |conn| {
|
||||||
|
|
|
@ -3,10 +3,10 @@ use crate::{
|
||||||
activity_queue::{send_comment_mentions, send_to_community},
|
activity_queue::{send_comment_mentions, send_to_community},
|
||||||
extensions::context::lemmy_context,
|
extensions::context::lemmy_context,
|
||||||
fetcher::get_or_fetch_and_upsert_user,
|
fetcher::get_or_fetch_and_upsert_user,
|
||||||
|
objects::ToApub,
|
||||||
ActorType,
|
ActorType,
|
||||||
ApubLikeableType,
|
ApubLikeableType,
|
||||||
ApubObjectType,
|
ApubObjectType,
|
||||||
ToApub,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{
|
activity::{
|
||||||
|
@ -218,8 +218,6 @@ impl ApubObjectType for Comment {
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl ApubLikeableType for Comment {
|
impl ApubLikeableType for Comment {
|
||||||
async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
|
async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
|
||||||
let note = self.to_apub(context.pool()).await?;
|
|
||||||
|
|
||||||
let post_id = self.post_id;
|
let post_id = self.post_id;
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
||||||
|
|
||||||
|
@ -229,7 +227,7 @@ impl ApubLikeableType for Comment {
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
let mut like = Like::new(creator.actor_id.to_owned(), note.into_any_base()?);
|
let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?);
|
||||||
like
|
like
|
||||||
.set_many_contexts(lemmy_context()?)
|
.set_many_contexts(lemmy_context()?)
|
||||||
.set_id(generate_activity_id(LikeType::Like)?)
|
.set_id(generate_activity_id(LikeType::Like)?)
|
||||||
|
@ -241,8 +239,6 @@ impl ApubLikeableType for Comment {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_dislike(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
|
async fn send_dislike(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
|
||||||
let note = self.to_apub(context.pool()).await?;
|
|
||||||
|
|
||||||
let post_id = self.post_id;
|
let post_id = self.post_id;
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
||||||
|
|
||||||
|
@ -252,7 +248,7 @@ impl ApubLikeableType for Comment {
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
let mut dislike = Dislike::new(creator.actor_id.to_owned(), note.into_any_base()?);
|
let mut dislike = Dislike::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?);
|
||||||
dislike
|
dislike
|
||||||
.set_many_contexts(lemmy_context()?)
|
.set_many_contexts(lemmy_context()?)
|
||||||
.set_id(generate_activity_id(DislikeType::Dislike)?)
|
.set_id(generate_activity_id(DislikeType::Dislike)?)
|
||||||
|
@ -268,8 +264,6 @@ impl ApubLikeableType for Comment {
|
||||||
creator: &User_,
|
creator: &User_,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let note = self.to_apub(context.pool()).await?;
|
|
||||||
|
|
||||||
let post_id = self.post_id;
|
let post_id = self.post_id;
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
||||||
|
|
||||||
|
@ -279,7 +273,7 @@ impl ApubLikeableType for Comment {
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
let mut like = Like::new(creator.actor_id.to_owned(), note.into_any_base()?);
|
let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?);
|
||||||
like
|
like
|
||||||
.set_many_contexts(lemmy_context()?)
|
.set_many_contexts(lemmy_context()?)
|
||||||
.set_id(generate_activity_id(DislikeType::Dislike)?)
|
.set_id(generate_activity_id(DislikeType::Dislike)?)
|
||||||
|
|
|
@ -2,10 +2,10 @@ use crate::{
|
||||||
activities::send::generate_activity_id,
|
activities::send::generate_activity_id,
|
||||||
activity_queue::send_to_community,
|
activity_queue::send_to_community,
|
||||||
extensions::context::lemmy_context,
|
extensions::context::lemmy_context,
|
||||||
|
objects::ToApub,
|
||||||
ActorType,
|
ActorType,
|
||||||
ApubLikeableType,
|
ApubLikeableType,
|
||||||
ApubObjectType,
|
ApubObjectType,
|
||||||
ToApub,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{
|
activity::{
|
||||||
|
@ -167,15 +167,13 @@ impl ApubObjectType for Post {
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl ApubLikeableType for Post {
|
impl ApubLikeableType for Post {
|
||||||
async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
|
async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
|
||||||
let page = self.to_apub(context.pool()).await?;
|
|
||||||
|
|
||||||
let community_id = self.community_id;
|
let community_id = self.community_id;
|
||||||
let community = blocking(context.pool(), move |conn| {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
Community::read(conn, community_id)
|
Community::read(conn, community_id)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
let mut like = Like::new(creator.actor_id.to_owned(), page.into_any_base()?);
|
let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?);
|
||||||
like
|
like
|
||||||
.set_many_contexts(lemmy_context()?)
|
.set_many_contexts(lemmy_context()?)
|
||||||
.set_id(generate_activity_id(LikeType::Like)?)
|
.set_id(generate_activity_id(LikeType::Like)?)
|
||||||
|
@ -187,15 +185,13 @@ impl ApubLikeableType for Post {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_dislike(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
|
async fn send_dislike(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
|
||||||
let page = self.to_apub(context.pool()).await?;
|
|
||||||
|
|
||||||
let community_id = self.community_id;
|
let community_id = self.community_id;
|
||||||
let community = blocking(context.pool(), move |conn| {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
Community::read(conn, community_id)
|
Community::read(conn, community_id)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
let mut dislike = Dislike::new(creator.actor_id.to_owned(), page.into_any_base()?);
|
let mut dislike = Dislike::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?);
|
||||||
dislike
|
dislike
|
||||||
.set_many_contexts(lemmy_context()?)
|
.set_many_contexts(lemmy_context()?)
|
||||||
.set_id(generate_activity_id(DislikeType::Dislike)?)
|
.set_id(generate_activity_id(DislikeType::Dislike)?)
|
||||||
|
@ -211,15 +207,13 @@ impl ApubLikeableType for Post {
|
||||||
creator: &User_,
|
creator: &User_,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let page = self.to_apub(context.pool()).await?;
|
|
||||||
|
|
||||||
let community_id = self.community_id;
|
let community_id = self.community_id;
|
||||||
let community = blocking(context.pool(), move |conn| {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
Community::read(conn, community_id)
|
Community::read(conn, community_id)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
let mut like = Like::new(creator.actor_id.to_owned(), page.into_any_base()?);
|
let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?);
|
||||||
like
|
like
|
||||||
.set_many_contexts(lemmy_context()?)
|
.set_many_contexts(lemmy_context()?)
|
||||||
.set_id(generate_activity_id(LikeType::Like)?)
|
.set_id(generate_activity_id(LikeType::Like)?)
|
||||||
|
|
|
@ -2,9 +2,9 @@ use crate::{
|
||||||
activities::send::generate_activity_id,
|
activities::send::generate_activity_id,
|
||||||
activity_queue::send_activity_single_dest,
|
activity_queue::send_activity_single_dest,
|
||||||
extensions::context::lemmy_context,
|
extensions::context::lemmy_context,
|
||||||
|
objects::ToApub,
|
||||||
ActorType,
|
ActorType,
|
||||||
ApubObjectType,
|
ApubObjectType,
|
||||||
ToApub,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{
|
activity::{
|
||||||
|
|
|
@ -16,6 +16,7 @@ use activitystreams::{
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
community::{Community, CommunityFollower, CommunityFollowerForm},
|
community::{Community, CommunityFollower, CommunityFollowerForm},
|
||||||
user::User_,
|
user::User_,
|
||||||
|
ApubObject,
|
||||||
DbPool,
|
DbPool,
|
||||||
Followable,
|
Followable,
|
||||||
};
|
};
|
||||||
|
@ -46,7 +47,7 @@ impl ActorType for User_ {
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let follow_actor_id = follow_actor_id.to_string();
|
let follow_actor_id = follow_actor_id.to_string();
|
||||||
let community = blocking(context.pool(), move |conn| {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
Community::read_from_actor_id(conn, &follow_actor_id)
|
Community::read_from_apub_id(conn, &follow_actor_id)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ impl ActorType for User_ {
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let follow_actor_id = follow_actor_id.to_string();
|
let follow_actor_id = follow_actor_id.to_string();
|
||||||
let community = blocking(context.pool(), move |conn| {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
Community::read_from_actor_id(conn, &follow_actor_id)
|
Community::read_from_apub_id(conn, &follow_actor_id)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ use url::Url;
|
||||||
/// * `activity` the apub activity to be sent
|
/// * `activity` the apub activity to be sent
|
||||||
/// * `creator` the local actor which created the activity
|
/// * `creator` the local actor which created the activity
|
||||||
/// * `inbox` the inbox url where the activity should be delivered to
|
/// * `inbox` the inbox url where the activity should be delivered to
|
||||||
pub async fn send_activity_single_dest<T, Kind>(
|
pub(crate) async fn send_activity_single_dest<T, Kind>(
|
||||||
activity: T,
|
activity: T,
|
||||||
creator: &dyn ActorType,
|
creator: &dyn ActorType,
|
||||||
inbox: Url,
|
inbox: Url,
|
||||||
|
@ -71,7 +71,7 @@ where
|
||||||
/// * `community` the sending community
|
/// * `community` the sending community
|
||||||
/// * `sender_shared_inbox` in case of an announce, this should be the shared inbox of the inner
|
/// * `sender_shared_inbox` in case of an announce, this should be the shared inbox of the inner
|
||||||
/// activities creator, as receiving a known activity will cause an error
|
/// activities creator, as receiving a known activity will cause an error
|
||||||
pub async fn send_to_community_followers<T, Kind>(
|
pub(crate) async fn send_to_community_followers<T, Kind>(
|
||||||
activity: T,
|
activity: T,
|
||||||
community: &Community,
|
community: &Community,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
|
@ -116,7 +116,7 @@ where
|
||||||
/// * `creator` the creator of the activity
|
/// * `creator` the creator of the activity
|
||||||
/// * `community` the destination community
|
/// * `community` the destination community
|
||||||
///
|
///
|
||||||
pub async fn send_to_community<T, Kind>(
|
pub(crate) async fn send_to_community<T, Kind>(
|
||||||
activity: T,
|
activity: T,
|
||||||
creator: &User_,
|
creator: &User_,
|
||||||
community: &Community,
|
community: &Community,
|
||||||
|
@ -160,7 +160,7 @@ where
|
||||||
/// * `creator` user who created the comment
|
/// * `creator` user who created the comment
|
||||||
/// * `mentions` list of inboxes of users which are mentioned in the comment
|
/// * `mentions` list of inboxes of users which are mentioned in the comment
|
||||||
/// * `activity` either a `Create/Note` or `Update/Note`
|
/// * `activity` either a `Create/Note` or `Update/Note`
|
||||||
pub async fn send_comment_mentions<T, Kind>(
|
pub(crate) async fn send_comment_mentions<T, Kind>(
|
||||||
creator: &User_,
|
creator: &User_,
|
||||||
mentions: Vec<Url>,
|
mentions: Vec<Url>,
|
||||||
activity: T,
|
activity: T,
|
||||||
|
|
|
@ -65,7 +65,10 @@ pub async fn sign_and_send(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verifies the HTTP signature on an incoming inbox request.
|
/// Verifies the HTTP signature on an incoming inbox request.
|
||||||
pub fn verify_signature(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyError> {
|
pub(crate) fn verify_signature(
|
||||||
|
request: &HttpRequest,
|
||||||
|
actor: &dyn ActorType,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
let public_key = actor.public_key().context(location_info!())?;
|
let public_key = actor.public_key().context(location_info!())?;
|
||||||
let verified = CONFIG2
|
let verified = CONFIG2
|
||||||
.begin_verify(
|
.begin_verify(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
check_is_apub_id_valid,
|
check_is_apub_id_valid,
|
||||||
|
objects::FromApub,
|
||||||
ActorType,
|
ActorType,
|
||||||
FromApub,
|
|
||||||
GroupExt,
|
GroupExt,
|
||||||
NoteExt,
|
NoteExt,
|
||||||
PageExt,
|
PageExt,
|
||||||
|
@ -13,16 +13,16 @@ use anyhow::{anyhow, Context};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use diesel::result::Error::NotFound;
|
use diesel::result::Error::NotFound;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{Comment, CommentForm},
|
comment::Comment,
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
community::{Community, CommunityForm, CommunityModerator, CommunityModeratorForm},
|
community::{Community, CommunityModerator, CommunityModeratorForm},
|
||||||
community_view::CommunityView,
|
community_view::CommunityView,
|
||||||
naive_now,
|
naive_now,
|
||||||
post::{Post, PostForm},
|
post::Post,
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
user::{UserForm, User_},
|
user::User_,
|
||||||
user_view::UserView,
|
user_view::UserView,
|
||||||
Crud,
|
ApubObject,
|
||||||
Joinable,
|
Joinable,
|
||||||
SearchType,
|
SearchType,
|
||||||
};
|
};
|
||||||
|
@ -184,22 +184,16 @@ pub async fn search_by_apub_id(
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
SearchAcceptedObjects::Page(p) => {
|
SearchAcceptedObjects::Page(p) => {
|
||||||
let post_form = PostForm::from_apub(&p, context, Some(query_url), recursion_counter).await?;
|
let p = Post::from_apub(&p, context, query_url, recursion_counter).await?;
|
||||||
|
|
||||||
let p = blocking(context.pool(), move |conn| Post::upsert(conn, &post_form)).await??;
|
|
||||||
response.posts =
|
response.posts =
|
||||||
vec![blocking(context.pool(), move |conn| PostView::read(conn, p.id, None)).await??];
|
vec![blocking(context.pool(), move |conn| PostView::read(conn, p.id, None)).await??];
|
||||||
|
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
SearchAcceptedObjects::Comment(c) => {
|
SearchAcceptedObjects::Comment(c) => {
|
||||||
let comment_form =
|
let c = Comment::from_apub(&c, context, query_url, recursion_counter).await?;
|
||||||
CommentForm::from_apub(&c, context, Some(query_url), recursion_counter).await?;
|
|
||||||
|
|
||||||
let c = blocking(context.pool(), move |conn| {
|
|
||||||
Comment::upsert(conn, &comment_form)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
response.comments = vec![
|
response.comments = vec![
|
||||||
blocking(context.pool(), move |conn| {
|
blocking(context.pool(), move |conn| {
|
||||||
CommentView::read(conn, c.id, None)
|
CommentView::read(conn, c.id, None)
|
||||||
|
@ -243,7 +237,7 @@ pub(crate) async fn get_or_fetch_and_upsert_user(
|
||||||
) -> Result<User_, LemmyError> {
|
) -> Result<User_, LemmyError> {
|
||||||
let apub_id_owned = apub_id.to_owned();
|
let apub_id_owned = apub_id.to_owned();
|
||||||
let user = blocking(context.pool(), move |conn| {
|
let user = blocking(context.pool(), move |conn| {
|
||||||
User_::read_from_actor_id(conn, apub_id_owned.as_ref())
|
User_::read_from_apub_id(conn, apub_id_owned.as_ref())
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -258,15 +252,13 @@ pub(crate) async fn get_or_fetch_and_upsert_user(
|
||||||
return Ok(u);
|
return Ok(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut uf = UserForm::from_apub(
|
let user = User_::from_apub(&person?, context, apub_id.to_owned(), recursion_counter).await?;
|
||||||
&person?,
|
|
||||||
context,
|
let user_id = user.id;
|
||||||
Some(apub_id.to_owned()),
|
blocking(context.pool(), move |conn| {
|
||||||
recursion_counter,
|
User_::mark_as_updated(conn, user_id)
|
||||||
)
|
})
|
||||||
.await?;
|
.await??;
|
||||||
uf.last_refreshed_at = Some(naive_now());
|
|
||||||
let user = blocking(context.pool(), move |conn| User_::update(conn, u.id, &uf)).await??;
|
|
||||||
|
|
||||||
Ok(user)
|
Ok(user)
|
||||||
}
|
}
|
||||||
|
@ -276,14 +268,7 @@ pub(crate) async fn get_or_fetch_and_upsert_user(
|
||||||
let person =
|
let person =
|
||||||
fetch_remote_object::<PersonExt>(context.client(), apub_id, recursion_counter).await?;
|
fetch_remote_object::<PersonExt>(context.client(), apub_id, recursion_counter).await?;
|
||||||
|
|
||||||
let uf = UserForm::from_apub(
|
let user = User_::from_apub(&person, context, apub_id.to_owned(), recursion_counter).await?;
|
||||||
&person,
|
|
||||||
context,
|
|
||||||
Some(apub_id.to_owned()),
|
|
||||||
recursion_counter,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let user = blocking(context.pool(), move |conn| User_::upsert(conn, &uf)).await??;
|
|
||||||
|
|
||||||
Ok(user)
|
Ok(user)
|
||||||
}
|
}
|
||||||
|
@ -318,7 +303,7 @@ pub(crate) async fn get_or_fetch_and_upsert_community(
|
||||||
) -> Result<Community, LemmyError> {
|
) -> Result<Community, LemmyError> {
|
||||||
let apub_id_owned = apub_id.to_owned();
|
let apub_id_owned = apub_id.to_owned();
|
||||||
let community = blocking(context.pool(), move |conn| {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
Community::read_from_actor_id(conn, apub_id_owned.as_str())
|
Community::read_from_apub_id(conn, apub_id_owned.as_str())
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -354,9 +339,8 @@ async fn fetch_remote_community(
|
||||||
}
|
}
|
||||||
|
|
||||||
let group = group?;
|
let group = group?;
|
||||||
let cf =
|
let community =
|
||||||
CommunityForm::from_apub(&group, context, Some(apub_id.to_owned()), recursion_counter).await?;
|
Community::from_apub(&group, context, apub_id.to_owned(), recursion_counter).await?;
|
||||||
let community = blocking(context.pool(), move |conn| Community::upsert(conn, &cf)).await??;
|
|
||||||
|
|
||||||
// Also add the community moderators too
|
// Also add the community moderators too
|
||||||
let attributed_to = group.inner.attributed_to().context(location_info!())?;
|
let attributed_to = group.inner.attributed_to().context(location_info!())?;
|
||||||
|
@ -406,23 +390,13 @@ async fn fetch_remote_community(
|
||||||
}
|
}
|
||||||
for o in outbox_items {
|
for o in outbox_items {
|
||||||
let page = PageExt::from_any_base(o)?.context(location_info!())?;
|
let page = PageExt::from_any_base(o)?.context(location_info!())?;
|
||||||
|
let page_id = page.id_unchecked().context(location_info!())?;
|
||||||
|
|
||||||
// The post creator may be from a blocked instance,
|
// The post creator may be from a blocked instance, if it errors, then skip it
|
||||||
// if it errors, then continue
|
if check_is_apub_id_valid(page_id).is_err() {
|
||||||
let post = match PostForm::from_apub(&page, context, None, recursion_counter).await {
|
continue;
|
||||||
Ok(post) => post,
|
}
|
||||||
Err(_) => continue,
|
Post::from_apub(&page, context, page_id.to_owned(), recursion_counter).await?;
|
||||||
};
|
|
||||||
let post_ap_id = post.ap_id.as_ref().context(location_info!())?.clone();
|
|
||||||
// Check whether the post already exists in the local db
|
|
||||||
let existing = blocking(context.pool(), move |conn| {
|
|
||||||
Post::read_from_apub_id(conn, &post_ap_id)
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
match existing {
|
|
||||||
Ok(e) => blocking(context.pool(), move |conn| Post::update(conn, e.id, &post)).await??,
|
|
||||||
Err(_) => blocking(context.pool(), move |conn| Post::upsert(conn, &post)).await??,
|
|
||||||
};
|
|
||||||
// TODO: we need to send a websocket update here
|
// TODO: we need to send a websocket update here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,17 +422,9 @@ pub(crate) async fn get_or_fetch_and_insert_post(
|
||||||
Ok(p) => Ok(p),
|
Ok(p) => Ok(p),
|
||||||
Err(NotFound {}) => {
|
Err(NotFound {}) => {
|
||||||
debug!("Fetching and creating remote post: {}", post_ap_id);
|
debug!("Fetching and creating remote post: {}", post_ap_id);
|
||||||
let post =
|
let page =
|
||||||
fetch_remote_object::<PageExt>(context.client(), post_ap_id, recursion_counter).await?;
|
fetch_remote_object::<PageExt>(context.client(), post_ap_id, recursion_counter).await?;
|
||||||
let post_form = PostForm::from_apub(
|
let post = Post::from_apub(&page, context, post_ap_id.to_owned(), recursion_counter).await?;
|
||||||
&post,
|
|
||||||
context,
|
|
||||||
Some(post_ap_id.to_owned()),
|
|
||||||
recursion_counter,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let post = blocking(context.pool(), move |conn| Post::upsert(conn, &post_form)).await??;
|
|
||||||
|
|
||||||
Ok(post)
|
Ok(post)
|
||||||
}
|
}
|
||||||
|
@ -490,25 +456,20 @@ pub(crate) async fn get_or_fetch_and_insert_comment(
|
||||||
);
|
);
|
||||||
let comment =
|
let comment =
|
||||||
fetch_remote_object::<NoteExt>(context.client(), comment_ap_id, recursion_counter).await?;
|
fetch_remote_object::<NoteExt>(context.client(), comment_ap_id, recursion_counter).await?;
|
||||||
let comment_form = CommentForm::from_apub(
|
let comment = Comment::from_apub(
|
||||||
&comment,
|
&comment,
|
||||||
context,
|
context,
|
||||||
Some(comment_ap_id.to_owned()),
|
comment_ap_id.to_owned(),
|
||||||
recursion_counter,
|
recursion_counter,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let post_id = comment_form.post_id;
|
let post_id = comment.post_id;
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
||||||
if post.locked {
|
if post.locked {
|
||||||
return Err(anyhow!("Post is locked").into());
|
return Err(anyhow!("Post is locked").into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let comment = blocking(context.pool(), move |conn| {
|
|
||||||
Comment::upsert(conn, &comment_form)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
Ok(comment)
|
Ok(comment)
|
||||||
}
|
}
|
||||||
Err(e) => Err(e.into()),
|
Err(e) => Err(e.into()),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
http::{create_apub_response, create_apub_tombstone_response},
|
http::{create_apub_response, create_apub_tombstone_response},
|
||||||
ToApub,
|
objects::ToApub,
|
||||||
};
|
};
|
||||||
use actix_web::{body::Body, web, web::Path, HttpResponse};
|
use actix_web::{body::Body, web, web::Path, HttpResponse};
|
||||||
use diesel::result::Error::NotFound;
|
use diesel::result::Error::NotFound;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
extensions::context::lemmy_context,
|
extensions::context::lemmy_context,
|
||||||
http::{create_apub_response, create_apub_tombstone_response},
|
http::{create_apub_response, create_apub_tombstone_response},
|
||||||
|
objects::ToApub,
|
||||||
ActorType,
|
ActorType,
|
||||||
ToApub,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
base::{AnyBase, BaseExt, ExtendsExt},
|
base::{AnyBase, BaseExt, ExtendsExt},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
http::{create_apub_response, create_apub_tombstone_response},
|
http::{create_apub_response, create_apub_tombstone_response},
|
||||||
ToApub,
|
objects::ToApub,
|
||||||
};
|
};
|
||||||
use actix_web::{body::Body, web, HttpResponse};
|
use actix_web::{body::Body, web, HttpResponse};
|
||||||
use diesel::result::Error::NotFound;
|
use diesel::result::Error::NotFound;
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
use crate::{extensions::context::lemmy_context, http::create_apub_response, ActorType, ToApub};
|
use crate::{
|
||||||
|
extensions::context::lemmy_context,
|
||||||
|
http::create_apub_response,
|
||||||
|
objects::ToApub,
|
||||||
|
ActorType,
|
||||||
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
base::BaseExt,
|
base::BaseExt,
|
||||||
collection::{CollectionExt, OrderedCollection},
|
collection::{CollectionExt, OrderedCollection},
|
||||||
|
|
|
@ -30,6 +30,7 @@ use lemmy_db::{
|
||||||
community::{Community, CommunityFollower, CommunityFollowerForm},
|
community::{Community, CommunityFollower, CommunityFollowerForm},
|
||||||
community_view::CommunityUserBanView,
|
community_view::CommunityUserBanView,
|
||||||
user::User_,
|
user::User_,
|
||||||
|
ApubObject,
|
||||||
DbPool,
|
DbPool,
|
||||||
Followable,
|
Followable,
|
||||||
};
|
};
|
||||||
|
@ -118,7 +119,7 @@ pub(crate) async fn community_receive_message(
|
||||||
// unconditionally.
|
// unconditionally.
|
||||||
let actor_id = actor.actor_id_str();
|
let actor_id = actor.actor_id_str();
|
||||||
let user = blocking(&context.pool(), move |conn| {
|
let user = blocking(&context.pool(), move |conn| {
|
||||||
User_::read_from_actor_id(&conn, &actor_id)
|
User_::read_from_apub_id(&conn, &actor_id)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
check_community_or_site_ban(&user, &to_community, context.pool()).await?;
|
check_community_or_site_ban(&user, &to_community, context.pool()).await?;
|
||||||
|
@ -242,7 +243,7 @@ async fn handle_undo_follow(
|
||||||
verify_activity_domains_valid(&follow, &user_url, false)?;
|
verify_activity_domains_valid(&follow, &user_url, false)?;
|
||||||
|
|
||||||
let user = blocking(&context.pool(), move |conn| {
|
let user = blocking(&context.pool(), move |conn| {
|
||||||
User_::read_from_actor_id(&conn, user_url.as_str())
|
User_::read_from_apub_id(&conn, user_url.as_str())
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
let community_follower_form = CommunityFollowerForm {
|
let community_follower_form = CommunityFollowerForm {
|
||||||
|
@ -260,7 +261,7 @@ async fn handle_undo_follow(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn check_community_or_site_ban(
|
pub(crate) async fn check_community_or_site_ban(
|
||||||
user: &User_,
|
user: &User_,
|
||||||
community: &Community,
|
community: &Community,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
|
|
|
@ -12,7 +12,7 @@ use activitystreams::{
|
||||||
};
|
};
|
||||||
use actix_web::HttpRequest;
|
use actix_web::HttpRequest;
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use lemmy_db::{activity::Activity, community::Community, user::User_, DbPool};
|
use lemmy_db::{activity::Activity, community::Community, user::User_, ApubObject, DbPool};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{location_info, settings::Settings, LemmyError};
|
use lemmy_utils::{location_info, settings::Settings, LemmyError};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
|
@ -119,7 +119,7 @@ pub(crate) async fn is_addressed_to_local_user(
|
||||||
) -> Result<bool, LemmyError> {
|
) -> Result<bool, LemmyError> {
|
||||||
for url in to_and_cc {
|
for url in to_and_cc {
|
||||||
let url = url.to_string();
|
let url = url.to_string();
|
||||||
let user = blocking(&pool, move |conn| User_::read_from_actor_id(&conn, &url)).await?;
|
let user = blocking(&pool, move |conn| User_::read_from_apub_id(&conn, &url)).await?;
|
||||||
if let Ok(u) = user {
|
if let Ok(u) = user {
|
||||||
if u.local {
|
if u.local {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
@ -141,7 +141,7 @@ pub(crate) async fn is_addressed_to_community_followers(
|
||||||
if url.ends_with("/followers") {
|
if url.ends_with("/followers") {
|
||||||
let community_url = url.replace("/followers", "");
|
let community_url = url.replace("/followers", "");
|
||||||
let community = blocking(&pool, move |conn| {
|
let community = blocking(&pool, move |conn| {
|
||||||
Community::read_from_actor_id(&conn, &community_url)
|
Community::read_from_apub_id(&conn, &community_url)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
if !community.local {
|
if !community.local {
|
||||||
|
|
|
@ -31,6 +31,7 @@ use crate::{
|
||||||
receive_unhandled_activity,
|
receive_unhandled_activity,
|
||||||
verify_activity_domains_valid,
|
verify_activity_domains_valid,
|
||||||
},
|
},
|
||||||
|
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
||||||
inbox::is_addressed_to_public,
|
inbox::is_addressed_to_public,
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
|
@ -40,7 +41,7 @@ use activitystreams::{
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use diesel::result::Error::NotFound;
|
use diesel::result::Error::NotFound;
|
||||||
use lemmy_db::{comment::Comment, post::Post, site::Site, Crud};
|
use lemmy_db::{comment::Comment, post::Post, site::Site, ApubObject, Crud};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
|
@ -96,10 +97,12 @@ pub(in crate::inbox) async fn receive_like_for_community(
|
||||||
verify_activity_domains_valid(&like, &expected_domain, false)?;
|
verify_activity_domains_valid(&like, &expected_domain, false)?;
|
||||||
is_addressed_to_public(&like)?;
|
is_addressed_to_public(&like)?;
|
||||||
|
|
||||||
match like.object().as_single_kind_str() {
|
let object_id = get_like_object_id(&like)?;
|
||||||
Some("Page") => receive_like_post(like, context, request_counter).await,
|
match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? {
|
||||||
Some("Note") => receive_like_comment(like, context, request_counter).await,
|
PostOrComment::Post(post) => receive_like_post(like, post, context, request_counter).await,
|
||||||
_ => receive_unhandled_activity(like),
|
PostOrComment::Comment(comment) => {
|
||||||
|
receive_like_comment(like, comment, context, request_counter).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,10 +125,14 @@ pub(in crate::inbox) async fn receive_dislike_for_community(
|
||||||
verify_activity_domains_valid(&dislike, &expected_domain, false)?;
|
verify_activity_domains_valid(&dislike, &expected_domain, false)?;
|
||||||
is_addressed_to_public(&dislike)?;
|
is_addressed_to_public(&dislike)?;
|
||||||
|
|
||||||
match dislike.object().as_single_kind_str() {
|
let object_id = get_like_object_id(&dislike)?;
|
||||||
Some("Page") => receive_dislike_post(dislike, context, request_counter).await,
|
match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? {
|
||||||
Some("Note") => receive_dislike_comment(dislike, context, request_counter).await,
|
PostOrComment::Post(post) => {
|
||||||
_ => receive_unhandled_activity(dislike),
|
receive_dislike_post(dislike, post, context, request_counter).await
|
||||||
|
}
|
||||||
|
PostOrComment::Comment(comment) => {
|
||||||
|
receive_dislike_comment(dislike, comment, context, request_counter).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,14 +282,14 @@ pub(in crate::inbox) async fn receive_undo_like_for_community(
|
||||||
verify_activity_domains_valid(&like, &expected_domain, false)?;
|
verify_activity_domains_valid(&like, &expected_domain, false)?;
|
||||||
is_addressed_to_public(&like)?;
|
is_addressed_to_public(&like)?;
|
||||||
|
|
||||||
let type_ = like
|
let object_id = get_like_object_id(&like)?;
|
||||||
.object()
|
match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? {
|
||||||
.as_single_kind_str()
|
PostOrComment::Post(post) => {
|
||||||
.context(location_info!())?;
|
receive_undo_like_post(&like, post, context, request_counter).await
|
||||||
match type_ {
|
}
|
||||||
"Note" => receive_undo_like_comment(&like, context, request_counter).await,
|
PostOrComment::Comment(comment) => {
|
||||||
"Page" => receive_undo_like_post(&like, context, request_counter).await,
|
receive_undo_like_comment(&like, comment, context, request_counter).await
|
||||||
_ => receive_unhandled_activity(like),
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,14 +305,14 @@ pub(in crate::inbox) async fn receive_undo_dislike_for_community(
|
||||||
verify_activity_domains_valid(&dislike, &expected_domain, false)?;
|
verify_activity_domains_valid(&dislike, &expected_domain, false)?;
|
||||||
is_addressed_to_public(&dislike)?;
|
is_addressed_to_public(&dislike)?;
|
||||||
|
|
||||||
let type_ = dislike
|
let object_id = get_like_object_id(&dislike)?;
|
||||||
.object()
|
match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? {
|
||||||
.as_single_kind_str()
|
PostOrComment::Post(post) => {
|
||||||
.context(location_info!())?;
|
receive_undo_dislike_post(&dislike, post, context, request_counter).await
|
||||||
match type_ {
|
}
|
||||||
"Note" => receive_undo_dislike_comment(&dislike, context, request_counter).await,
|
PostOrComment::Comment(comment) => {
|
||||||
"Page" => receive_undo_dislike_post(&dislike, context, request_counter).await,
|
receive_undo_dislike_comment(&dislike, comment, context, request_counter).await
|
||||||
_ => receive_unhandled_activity(dislike),
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,3 +348,42 @@ async fn find_post_or_comment_by_id(
|
||||||
|
|
||||||
return Err(NotFound.into());
|
return Err(NotFound.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn fetch_post_or_comment_by_id(
|
||||||
|
apub_id: &Url,
|
||||||
|
context: &LemmyContext,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<PostOrComment, LemmyError> {
|
||||||
|
if let Ok(post) = get_or_fetch_and_insert_post(apub_id, context, request_counter).await {
|
||||||
|
return Ok(PostOrComment::Post(post));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(comment) = get_or_fetch_and_insert_comment(apub_id, context, request_counter).await {
|
||||||
|
return Ok(PostOrComment::Comment(comment));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(NotFound.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_like_object_id<Activity>(like_or_dislike: &Activity) -> Result<Url, LemmyError>
|
||||||
|
where
|
||||||
|
Activity: ActorAndObjectRefExt,
|
||||||
|
{
|
||||||
|
// TODO: For backwards compatibility with older Lemmy versions where like.object contains a full
|
||||||
|
// post/comment. This can be removed after some time, using
|
||||||
|
// `activity.oject().as_single_xsd_any_uri()` instead.
|
||||||
|
let object = like_or_dislike.object();
|
||||||
|
if let Some(xsd_uri) = object.as_single_xsd_any_uri() {
|
||||||
|
Ok(xsd_uri.to_owned())
|
||||||
|
} else {
|
||||||
|
Ok(
|
||||||
|
object
|
||||||
|
.to_owned()
|
||||||
|
.one()
|
||||||
|
.context(location_info!())?
|
||||||
|
.id()
|
||||||
|
.context(location_info!())?
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::{
|
||||||
use activitystreams::{activity::ActorAndObject, prelude::*};
|
use activitystreams::{activity::ActorAndObject, prelude::*};
|
||||||
use actix_web::{web, HttpRequest, HttpResponse};
|
use actix_web::{web, HttpRequest, HttpResponse};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use lemmy_db::{community::Community, DbPool};
|
use lemmy_db::{community::Community, ApubObject, DbPool};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
|
@ -137,10 +137,7 @@ async fn extract_local_community_from_destinations(
|
||||||
) -> Result<Option<Community>, LemmyError> {
|
) -> Result<Option<Community>, LemmyError> {
|
||||||
for url in to_and_cc {
|
for url in to_and_cc {
|
||||||
let url = url.to_string();
|
let url = url.to_string();
|
||||||
let community = blocking(&pool, move |conn| {
|
let community = blocking(&pool, move |conn| Community::read_from_apub_id(&conn, &url)).await?;
|
||||||
Community::read_from_actor_id(&conn, &url)
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
if let Ok(c) = community {
|
if let Ok(c) = community {
|
||||||
if c.local {
|
if c.local {
|
||||||
return Ok(Some(c));
|
return Ok(Some(c));
|
||||||
|
|
|
@ -52,6 +52,7 @@ use lemmy_db::{
|
||||||
community::{Community, CommunityFollower},
|
community::{Community, CommunityFollower},
|
||||||
private_message::PrivateMessage,
|
private_message::PrivateMessage,
|
||||||
user::User_,
|
user::User_,
|
||||||
|
ApubObject,
|
||||||
Followable,
|
Followable,
|
||||||
};
|
};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
|
@ -377,7 +378,7 @@ async fn find_community_or_private_message_by_id(
|
||||||
) -> Result<CommunityOrPrivateMessage, LemmyError> {
|
) -> Result<CommunityOrPrivateMessage, LemmyError> {
|
||||||
let ap_id = apub_id.to_string();
|
let ap_id = apub_id.to_string();
|
||||||
let community = blocking(context.pool(), move |conn| {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
Community::read_from_actor_id(conn, &ap_id)
|
Community::read_from_apub_id(conn, &ap_id)
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
if let Ok(c) = community {
|
if let Ok(c) = community {
|
||||||
|
|
|
@ -18,7 +18,7 @@ use activitystreams::{
|
||||||
activity::Follow,
|
activity::Follow,
|
||||||
actor::{ApActor, Group, Person},
|
actor::{ApActor, Group, Person},
|
||||||
base::AnyBase,
|
base::AnyBase,
|
||||||
object::{ApObject, Note, Page, Tombstone},
|
object::{ApObject, Note, Page},
|
||||||
};
|
};
|
||||||
use activitystreams_ext::{Ext1, Ext2};
|
use activitystreams_ext::{Ext1, Ext2};
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
|
@ -109,33 +109,6 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for converting an object or actor into the respective ActivityPub type.
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
pub trait ToApub {
|
|
||||||
type ApubType;
|
|
||||||
async fn to_apub(&self, pool: &DbPool) -> Result<Self::ApubType, LemmyError>;
|
|
||||||
fn to_tombstone(&self) -> Result<Tombstone, LemmyError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
pub trait FromApub {
|
|
||||||
type ApubType;
|
|
||||||
/// Converts an object from ActivityPub type to Lemmy internal type.
|
|
||||||
///
|
|
||||||
/// * `apub` The object to read from
|
|
||||||
/// * `context` LemmyContext which holds DB pool, HTTP client etc
|
|
||||||
/// * `expected_domain` If present, ensure that the domains of this and of the apub object ID are
|
|
||||||
/// identical
|
|
||||||
async fn from_apub(
|
|
||||||
apub: &Self::ApubType,
|
|
||||||
context: &LemmyContext,
|
|
||||||
expected_domain: Option<Url>,
|
|
||||||
request_counter: &mut i32,
|
|
||||||
) -> Result<Self, LemmyError>
|
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Common functions for ActivityPub objects, which are implemented by most (but not all) objects
|
/// Common functions for ActivityPub objects, which are implemented by most (but not all) objects
|
||||||
/// and actors in Lemmy.
|
/// and actors in Lemmy.
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
|
@ -248,7 +221,7 @@ pub trait ActorType {
|
||||||
|
|
||||||
/// Store a sent or received activity in the database, for logging purposes. These records are not
|
/// Store a sent or received activity in the database, for logging purposes. These records are not
|
||||||
/// persistent.
|
/// persistent.
|
||||||
pub async fn insert_activity<T>(
|
pub(crate) async fn insert_activity<T>(
|
||||||
ap_id: &Url,
|
ap_id: &Url,
|
||||||
activity: T,
|
activity: T,
|
||||||
local: bool,
|
local: bool,
|
||||||
|
|
|
@ -7,19 +7,22 @@ use crate::{
|
||||||
},
|
},
|
||||||
objects::{
|
objects::{
|
||||||
check_object_domain,
|
check_object_domain,
|
||||||
|
check_object_for_community_or_site_ban,
|
||||||
create_tombstone,
|
create_tombstone,
|
||||||
|
get_object_from_apub,
|
||||||
get_source_markdown_value,
|
get_source_markdown_value,
|
||||||
set_content_and_source,
|
set_content_and_source,
|
||||||
},
|
|
||||||
FromApub,
|
FromApub,
|
||||||
NoteExt,
|
FromApubToForm,
|
||||||
ToApub,
|
ToApub,
|
||||||
|
},
|
||||||
|
NoteExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
object::{kind::NoteType, ApObject, Note, Tombstone},
|
object::{kind::NoteType, ApObject, Note, Tombstone},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::{anyhow, Context};
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{Comment, CommentForm},
|
comment::{Comment, CommentForm},
|
||||||
community::Community,
|
community::Community,
|
||||||
|
@ -87,16 +90,45 @@ impl ToApub for Comment {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl FromApub for CommentForm {
|
impl FromApub for Comment {
|
||||||
type ApubType = NoteExt;
|
type ApubType = NoteExt;
|
||||||
|
|
||||||
/// Converts a `Note` to `CommentForm`.
|
/// Converts a `Note` to `Comment`.
|
||||||
///
|
///
|
||||||
/// If the parent community, post and comment(s) are not known locally, these are also fetched.
|
/// If the parent community, post and comment(s) are not known locally, these are also fetched.
|
||||||
async fn from_apub(
|
async fn from_apub(
|
||||||
note: &NoteExt,
|
note: &NoteExt,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
expected_domain: Option<Url>,
|
expected_domain: Url,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<Comment, LemmyError> {
|
||||||
|
check_object_for_community_or_site_ban(note, context, request_counter).await?;
|
||||||
|
|
||||||
|
let comment: Comment =
|
||||||
|
get_object_from_apub(note, context, expected_domain, request_counter).await?;
|
||||||
|
|
||||||
|
let post_id = comment.post_id;
|
||||||
|
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
||||||
|
if post.locked {
|
||||||
|
// This is not very efficient because a comment gets inserted just to be deleted right
|
||||||
|
// afterwards, but it seems to be the easiest way to implement it.
|
||||||
|
blocking(context.pool(), move |conn| {
|
||||||
|
Comment::delete(conn, comment.id)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
return Err(anyhow!("Post is locked").into());
|
||||||
|
} else {
|
||||||
|
Ok(comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl FromApubToForm<NoteExt> for CommentForm {
|
||||||
|
async fn from_apub(
|
||||||
|
note: &NoteExt,
|
||||||
|
context: &LemmyContext,
|
||||||
|
expected_domain: Url,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<CommentForm, LemmyError> {
|
) -> Result<CommentForm, LemmyError> {
|
||||||
let creator_actor_id = ¬e
|
let creator_actor_id = ¬e
|
||||||
|
|
|
@ -4,13 +4,15 @@ use crate::{
|
||||||
objects::{
|
objects::{
|
||||||
check_object_domain,
|
check_object_domain,
|
||||||
create_tombstone,
|
create_tombstone,
|
||||||
|
get_object_from_apub,
|
||||||
get_source_markdown_value,
|
get_source_markdown_value,
|
||||||
set_content_and_source,
|
set_content_and_source,
|
||||||
|
FromApub,
|
||||||
|
FromApubToForm,
|
||||||
|
ToApub,
|
||||||
},
|
},
|
||||||
ActorType,
|
ActorType,
|
||||||
FromApub,
|
|
||||||
GroupExt,
|
GroupExt,
|
||||||
ToApub,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
actor::{kind::GroupType, ApActor, Endpoints, Group},
|
actor::{kind::GroupType, ApActor, Endpoints, Group},
|
||||||
|
@ -106,14 +108,28 @@ impl ToApub for Community {
|
||||||
create_tombstone(self.deleted, &self.actor_id, self.updated, GroupType::Group)
|
create_tombstone(self.deleted, &self.actor_id, self.updated, GroupType::Group)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl FromApub for CommunityForm {
|
impl FromApub for Community {
|
||||||
type ApubType = GroupExt;
|
type ApubType = GroupExt;
|
||||||
|
|
||||||
|
/// Converts a `Group` to `Community`.
|
||||||
async fn from_apub(
|
async fn from_apub(
|
||||||
group: &GroupExt,
|
group: &GroupExt,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
expected_domain: Option<Url>,
|
expected_domain: Url,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<Community, LemmyError> {
|
||||||
|
get_object_from_apub(group, context, expected_domain, request_counter).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl FromApubToForm<GroupExt> for CommunityForm {
|
||||||
|
async fn from_apub(
|
||||||
|
group: &GroupExt,
|
||||||
|
context: &LemmyContext,
|
||||||
|
expected_domain: Url,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<Self, LemmyError> {
|
) -> Result<Self, LemmyError> {
|
||||||
let creator_and_moderator_uris = group.inner.attributed_to().context(location_info!())?;
|
let creator_and_moderator_uris = group.inner.attributed_to().context(location_info!())?;
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
use crate::check_is_apub_id_valid;
|
use crate::{
|
||||||
|
check_is_apub_id_valid,
|
||||||
|
fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user},
|
||||||
|
inbox::community_inbox::check_community_or_site_ban,
|
||||||
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
base::{AsBase, BaseExt, ExtendsExt},
|
base::{AsBase, BaseExt, ExtendsExt},
|
||||||
markers::Base,
|
markers::Base,
|
||||||
|
@ -7,7 +11,10 @@ use activitystreams::{
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use lemmy_utils::{location_info, utils::convert_datetime, LemmyError};
|
use lemmy_db::{ApubObject, Crud, DbPool};
|
||||||
|
use lemmy_structs::blocking;
|
||||||
|
use lemmy_utils::{location_info, settings::Settings, utils::convert_datetime, LemmyError};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub(crate) mod comment;
|
pub(crate) mod comment;
|
||||||
|
@ -16,6 +23,44 @@ pub(crate) mod post;
|
||||||
pub(crate) mod private_message;
|
pub(crate) mod private_message;
|
||||||
pub(crate) mod user;
|
pub(crate) mod user;
|
||||||
|
|
||||||
|
/// Trait for converting an object or actor into the respective ActivityPub type.
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
pub(crate) trait ToApub {
|
||||||
|
type ApubType;
|
||||||
|
async fn to_apub(&self, pool: &DbPool) -> Result<Self::ApubType, LemmyError>;
|
||||||
|
fn to_tombstone(&self) -> Result<Tombstone, LemmyError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
pub(crate) trait FromApub {
|
||||||
|
type ApubType;
|
||||||
|
/// Converts an object from ActivityPub type to Lemmy internal type.
|
||||||
|
///
|
||||||
|
/// * `apub` The object to read from
|
||||||
|
/// * `context` LemmyContext which holds DB pool, HTTP client etc
|
||||||
|
/// * `expected_domain` Domain where the object was received from
|
||||||
|
async fn from_apub(
|
||||||
|
apub: &Self::ApubType,
|
||||||
|
context: &LemmyContext,
|
||||||
|
expected_domain: Url,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<Self, LemmyError>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
pub(in crate::objects) trait FromApubToForm<ApubType> {
|
||||||
|
async fn from_apub(
|
||||||
|
apub: &ApubType,
|
||||||
|
context: &LemmyContext,
|
||||||
|
expected_domain: Url,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<Self, LemmyError>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
}
|
||||||
|
|
||||||
/// Updated is actually the deletion time
|
/// Updated is actually the deletion time
|
||||||
fn create_tombstone<T>(
|
fn create_tombstone<T>(
|
||||||
deleted: bool,
|
deleted: bool,
|
||||||
|
@ -43,17 +88,13 @@ where
|
||||||
|
|
||||||
pub(in crate::objects) fn check_object_domain<T, Kind>(
|
pub(in crate::objects) fn check_object_domain<T, Kind>(
|
||||||
apub: &T,
|
apub: &T,
|
||||||
expected_domain: Option<Url>,
|
expected_domain: Url,
|
||||||
) -> Result<String, LemmyError>
|
) -> Result<String, LemmyError>
|
||||||
where
|
where
|
||||||
T: Base + AsBase<Kind>,
|
T: Base + AsBase<Kind>,
|
||||||
{
|
{
|
||||||
let object_id = if let Some(url) = expected_domain {
|
let domain = expected_domain.domain().context(location_info!())?;
|
||||||
let domain = url.domain().context(location_info!())?;
|
let object_id = apub.id(domain)?.context(location_info!())?;
|
||||||
apub.id(domain)?.context(location_info!())?
|
|
||||||
} else {
|
|
||||||
apub.id_unchecked().context(location_info!())?
|
|
||||||
};
|
|
||||||
check_is_apub_id_valid(&object_id)?;
|
check_is_apub_id_valid(&object_id)?;
|
||||||
Ok(object_id.to_string())
|
Ok(object_id.to_string())
|
||||||
}
|
}
|
||||||
|
@ -127,3 +168,60 @@ pub(in crate::objects) fn check_is_markdown(mime: Option<&Mime>) -> Result<(), L
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts an ActivityPub object (eg `Note`) to a database object (eg `Comment`). If an object
|
||||||
|
/// with the same ActivityPub ID already exists in the database, it is returned directly. Otherwise
|
||||||
|
/// the apub object is parsed, inserted and returned.
|
||||||
|
pub(in crate::objects) async fn get_object_from_apub<From, Kind, To, ToForm>(
|
||||||
|
from: &From,
|
||||||
|
context: &LemmyContext,
|
||||||
|
expected_domain: Url,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<To, LemmyError>
|
||||||
|
where
|
||||||
|
From: BaseExt<Kind>,
|
||||||
|
To: ApubObject<ToForm> + Crud<ToForm> + Send + 'static,
|
||||||
|
ToForm: FromApubToForm<From> + Send + 'static,
|
||||||
|
{
|
||||||
|
let object_id = from.id_unchecked().context(location_info!())?.to_owned();
|
||||||
|
let domain = object_id.domain().context(location_info!())?;
|
||||||
|
|
||||||
|
// if its a local object, return it directly from the database
|
||||||
|
if Settings::get().hostname == domain {
|
||||||
|
let object = blocking(context.pool(), move |conn| {
|
||||||
|
To::read_from_apub_id(conn, object_id.as_str())
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
Ok(object)
|
||||||
|
}
|
||||||
|
// otherwise parse and insert, assuring that it comes from the right domain
|
||||||
|
else {
|
||||||
|
let to_form = ToForm::from_apub(&from, context, expected_domain, request_counter).await?;
|
||||||
|
|
||||||
|
let to = blocking(context.pool(), move |conn| To::upsert(conn, &to_form)).await??;
|
||||||
|
Ok(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate::objects) async fn check_object_for_community_or_site_ban<T, Kind>(
|
||||||
|
object: &T,
|
||||||
|
context: &LemmyContext,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<(), LemmyError>
|
||||||
|
where
|
||||||
|
T: ObjectExt<Kind>,
|
||||||
|
{
|
||||||
|
let user_id = object
|
||||||
|
.attributed_to()
|
||||||
|
.context(location_info!())?
|
||||||
|
.as_single_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
|
let user = get_or_fetch_and_upsert_user(user_id, context, request_counter).await?;
|
||||||
|
let community_id = object
|
||||||
|
.to()
|
||||||
|
.context(location_info!())?
|
||||||
|
.as_single_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
|
let community = get_or_fetch_and_upsert_community(community_id, context, request_counter).await?;
|
||||||
|
check_community_or_site_ban(&user, &community, context.pool()).await
|
||||||
|
}
|
||||||
|
|
|
@ -3,13 +3,16 @@ use crate::{
|
||||||
fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user},
|
fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user},
|
||||||
objects::{
|
objects::{
|
||||||
check_object_domain,
|
check_object_domain,
|
||||||
|
check_object_for_community_or_site_ban,
|
||||||
create_tombstone,
|
create_tombstone,
|
||||||
|
get_object_from_apub,
|
||||||
get_source_markdown_value,
|
get_source_markdown_value,
|
||||||
set_content_and_source,
|
set_content_and_source,
|
||||||
},
|
|
||||||
FromApub,
|
FromApub,
|
||||||
PageExt,
|
FromApubToForm,
|
||||||
ToApub,
|
ToApub,
|
||||||
|
},
|
||||||
|
PageExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
object::{kind::PageType, ApObject, Image, Page, Tombstone},
|
object::{kind::PageType, ApObject, Image, Page, Tombstone},
|
||||||
|
@ -98,7 +101,7 @@ impl ToApub for Post {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl FromApub for PostForm {
|
impl FromApub for Post {
|
||||||
type ApubType = PageExt;
|
type ApubType = PageExt;
|
||||||
|
|
||||||
/// Converts a `PageExt` to `PostForm`.
|
/// Converts a `PageExt` to `PostForm`.
|
||||||
|
@ -107,7 +110,20 @@ impl FromApub for PostForm {
|
||||||
async fn from_apub(
|
async fn from_apub(
|
||||||
page: &PageExt,
|
page: &PageExt,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
expected_domain: Option<Url>,
|
expected_domain: Url,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<Post, LemmyError> {
|
||||||
|
check_object_for_community_or_site_ban(page, context, request_counter).await?;
|
||||||
|
get_object_from_apub(page, context, expected_domain, request_counter).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl FromApubToForm<PageExt> for PostForm {
|
||||||
|
async fn from_apub(
|
||||||
|
page: &PageExt,
|
||||||
|
context: &LemmyContext,
|
||||||
|
expected_domain: Url,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<PostForm, LemmyError> {
|
) -> Result<PostForm, LemmyError> {
|
||||||
let ext = &page.ext_one;
|
let ext = &page.ext_one;
|
||||||
|
|
|
@ -5,12 +5,14 @@ use crate::{
|
||||||
objects::{
|
objects::{
|
||||||
check_object_domain,
|
check_object_domain,
|
||||||
create_tombstone,
|
create_tombstone,
|
||||||
|
get_object_from_apub,
|
||||||
get_source_markdown_value,
|
get_source_markdown_value,
|
||||||
set_content_and_source,
|
set_content_and_source,
|
||||||
},
|
|
||||||
FromApub,
|
FromApub,
|
||||||
NoteExt,
|
FromApubToForm,
|
||||||
ToApub,
|
ToApub,
|
||||||
|
},
|
||||||
|
NoteExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
object::{kind::NoteType, ApObject, Note, Tombstone},
|
object::{kind::NoteType, ApObject, Note, Tombstone},
|
||||||
|
@ -63,13 +65,25 @@ impl ToApub for PrivateMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl FromApub for PrivateMessageForm {
|
impl FromApub for PrivateMessage {
|
||||||
type ApubType = NoteExt;
|
type ApubType = NoteExt;
|
||||||
|
|
||||||
async fn from_apub(
|
async fn from_apub(
|
||||||
note: &NoteExt,
|
note: &NoteExt,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
expected_domain: Option<Url>,
|
expected_domain: Url,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<PrivateMessage, LemmyError> {
|
||||||
|
get_object_from_apub(note, context, expected_domain, request_counter).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl FromApubToForm<NoteExt> for PrivateMessageForm {
|
||||||
|
async fn from_apub(
|
||||||
|
note: &NoteExt,
|
||||||
|
context: &LemmyContext,
|
||||||
|
expected_domain: Url,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<PrivateMessageForm, LemmyError> {
|
) -> Result<PrivateMessageForm, LemmyError> {
|
||||||
let creator_actor_id = note
|
let creator_actor_id = note
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
extensions::context::lemmy_context,
|
extensions::context::lemmy_context,
|
||||||
objects::{check_object_domain, get_source_markdown_value, set_content_and_source},
|
objects::{
|
||||||
ActorType,
|
check_object_domain,
|
||||||
|
get_source_markdown_value,
|
||||||
|
set_content_and_source,
|
||||||
FromApub,
|
FromApub,
|
||||||
PersonExt,
|
FromApubToForm,
|
||||||
ToApub,
|
ToApub,
|
||||||
|
},
|
||||||
|
ActorType,
|
||||||
|
PersonExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
actor::{ApActor, Endpoints, Person},
|
actor::{ApActor, Endpoints, Person},
|
||||||
|
@ -16,10 +21,13 @@ use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
naive_now,
|
naive_now,
|
||||||
user::{UserForm, User_},
|
user::{UserForm, User_},
|
||||||
|
ApubObject,
|
||||||
DbPool,
|
DbPool,
|
||||||
};
|
};
|
||||||
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
location_info,
|
location_info,
|
||||||
|
settings::Settings,
|
||||||
utils::{check_slurs, check_slurs_opt, convert_datetime},
|
utils::{check_slurs, check_slurs_opt, convert_datetime},
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
@ -81,13 +89,38 @@ impl ToApub for User_ {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl FromApub for UserForm {
|
impl FromApub for User_ {
|
||||||
type ApubType = PersonExt;
|
type ApubType = PersonExt;
|
||||||
|
|
||||||
|
async fn from_apub(
|
||||||
|
person: &PersonExt,
|
||||||
|
context: &LemmyContext,
|
||||||
|
expected_domain: Url,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<User_, LemmyError> {
|
||||||
|
let user_id = person.id_unchecked().context(location_info!())?.to_owned();
|
||||||
|
let domain = user_id.domain().context(location_info!())?;
|
||||||
|
if domain == Settings::get().hostname {
|
||||||
|
let user = blocking(context.pool(), move |conn| {
|
||||||
|
User_::read_from_apub_id(conn, user_id.as_str())
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
Ok(user)
|
||||||
|
} else {
|
||||||
|
let user_form =
|
||||||
|
UserForm::from_apub(person, context, expected_domain, request_counter).await?;
|
||||||
|
let user = blocking(context.pool(), move |conn| User_::upsert(conn, &user_form)).await??;
|
||||||
|
Ok(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl FromApubToForm<PersonExt> for UserForm {
|
||||||
async fn from_apub(
|
async fn from_apub(
|
||||||
person: &PersonExt,
|
person: &PersonExt,
|
||||||
_context: &LemmyContext,
|
_context: &LemmyContext,
|
||||||
expected_domain: Option<Url>,
|
expected_domain: Url,
|
||||||
_request_counter: &mut i32,
|
_request_counter: &mut i32,
|
||||||
) -> Result<Self, LemmyError> {
|
) -> Result<Self, LemmyError> {
|
||||||
let avatar = match person.icon() {
|
let avatar = match person.icon() {
|
||||||
|
|
|
@ -2,6 +2,7 @@ use super::post::Post;
|
||||||
use crate::{
|
use crate::{
|
||||||
naive_now,
|
naive_now,
|
||||||
schema::{comment, comment_like, comment_saved},
|
schema::{comment, comment_like, comment_saved},
|
||||||
|
ApubObject,
|
||||||
Crud,
|
Crud,
|
||||||
Likeable,
|
Likeable,
|
||||||
Saveable,
|
Saveable,
|
||||||
|
@ -86,6 +87,23 @@ impl Crud<CommentForm> for Comment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApubObject<CommentForm> for Comment {
|
||||||
|
fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
|
||||||
|
use crate::schema::comment::dsl::*;
|
||||||
|
comment.filter(ap_id.eq(object_id)).first::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upsert(conn: &PgConnection, comment_form: &CommentForm) -> Result<Self, Error> {
|
||||||
|
use crate::schema::comment::dsl::*;
|
||||||
|
insert_into(comment)
|
||||||
|
.values(comment_form)
|
||||||
|
.on_conflict(ap_id)
|
||||||
|
.do_update()
|
||||||
|
.set(comment_form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Comment {
|
impl Comment {
|
||||||
pub fn update_ap_id(
|
pub fn update_ap_id(
|
||||||
conn: &PgConnection,
|
conn: &PgConnection,
|
||||||
|
@ -99,11 +117,6 @@ impl Comment {
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
|
|
||||||
use crate::schema::comment::dsl::*;
|
|
||||||
comment.filter(ap_id.eq(object_id)).first::<Self>(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn permadelete_for_creator(
|
pub fn permadelete_for_creator(
|
||||||
conn: &PgConnection,
|
conn: &PgConnection,
|
||||||
for_creator_id: i32,
|
for_creator_id: i32,
|
||||||
|
@ -168,16 +181,6 @@ impl Comment {
|
||||||
.set((content.eq(new_content), updated.eq(naive_now())))
|
.set((content.eq(new_content), updated.eq(naive_now())))
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upsert(conn: &PgConnection, comment_form: &CommentForm) -> Result<Self, Error> {
|
|
||||||
use crate::schema::comment::dsl::*;
|
|
||||||
insert_into(comment)
|
|
||||||
.values(comment_form)
|
|
||||||
.on_conflict(ap_id)
|
|
||||||
.do_update()
|
|
||||||
.set(comment_form)
|
|
||||||
.get_result::<Self>(conn)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Clone)]
|
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Clone)]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
naive_now,
|
naive_now,
|
||||||
schema::{community, community_follower, community_moderator, community_user_ban},
|
schema::{community, community_follower, community_moderator, community_user_ban},
|
||||||
|
ApubObject,
|
||||||
Bannable,
|
Bannable,
|
||||||
Crud,
|
Crud,
|
||||||
Followable,
|
Followable,
|
||||||
|
@ -83,6 +84,25 @@ impl Crud<CommunityForm> for Community {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApubObject<CommunityForm> for Community {
|
||||||
|
fn read_from_apub_id(conn: &PgConnection, for_actor_id: &str) -> Result<Self, Error> {
|
||||||
|
use crate::schema::community::dsl::*;
|
||||||
|
community
|
||||||
|
.filter(actor_id.eq(for_actor_id))
|
||||||
|
.first::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upsert(conn: &PgConnection, community_form: &CommunityForm) -> Result<Community, Error> {
|
||||||
|
use crate::schema::community::dsl::*;
|
||||||
|
insert_into(community)
|
||||||
|
.values(community_form)
|
||||||
|
.on_conflict(actor_id)
|
||||||
|
.do_update()
|
||||||
|
.set(community_form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Community {
|
impl Community {
|
||||||
pub fn read_from_name(conn: &PgConnection, community_name: &str) -> Result<Self, Error> {
|
pub fn read_from_name(conn: &PgConnection, community_name: &str) -> Result<Self, Error> {
|
||||||
use crate::schema::community::dsl::*;
|
use crate::schema::community::dsl::*;
|
||||||
|
@ -92,13 +112,6 @@ impl Community {
|
||||||
.first::<Self>(conn)
|
.first::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_from_actor_id(conn: &PgConnection, for_actor_id: &str) -> Result<Self, Error> {
|
|
||||||
use crate::schema::community::dsl::*;
|
|
||||||
community
|
|
||||||
.filter(actor_id.eq(for_actor_id))
|
|
||||||
.first::<Self>(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_deleted(
|
pub fn update_deleted(
|
||||||
conn: &PgConnection,
|
conn: &PgConnection,
|
||||||
community_id: i32,
|
community_id: i32,
|
||||||
|
@ -165,16 +178,6 @@ impl Community {
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.contains(&user_id)
|
.contains(&user_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upsert(conn: &PgConnection, community_form: &CommunityForm) -> Result<Community, Error> {
|
|
||||||
use crate::schema::community::dsl::*;
|
|
||||||
insert_into(community)
|
|
||||||
.values(community_form)
|
|
||||||
.on_conflict(actor_id)
|
|
||||||
.do_update()
|
|
||||||
.set(community_form)
|
|
||||||
.get_result::<Self>(conn)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
|
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
|
||||||
|
|
|
@ -124,6 +124,15 @@ pub trait Reportable<T> {
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ApubObject<T> {
|
||||||
|
fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
fn upsert(conn: &PgConnection, user_form: &T) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait MaybeOptional<T> {
|
pub trait MaybeOptional<T> {
|
||||||
fn get_optional(self) -> Option<T>;
|
fn get_optional(self) -> Option<T>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
naive_now,
|
naive_now,
|
||||||
schema::{post, post_like, post_read, post_saved},
|
schema::{post, post_like, post_read, post_saved},
|
||||||
|
ApubObject,
|
||||||
Crud,
|
Crud,
|
||||||
Likeable,
|
Likeable,
|
||||||
Readable,
|
Readable,
|
||||||
|
@ -62,6 +63,47 @@ impl PostForm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Crud<PostForm> for Post {
|
||||||
|
fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> {
|
||||||
|
use crate::schema::post::dsl::*;
|
||||||
|
post.find(post_id).first::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete(conn: &PgConnection, post_id: i32) -> Result<usize, Error> {
|
||||||
|
use crate::schema::post::dsl::*;
|
||||||
|
diesel::delete(post.find(post_id)).execute(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(conn: &PgConnection, new_post: &PostForm) -> Result<Self, Error> {
|
||||||
|
use crate::schema::post::dsl::*;
|
||||||
|
insert_into(post).values(new_post).get_result::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result<Self, Error> {
|
||||||
|
use crate::schema::post::dsl::*;
|
||||||
|
diesel::update(post.find(post_id))
|
||||||
|
.set(new_post)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApubObject<PostForm> for Post {
|
||||||
|
fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
|
||||||
|
use crate::schema::post::dsl::*;
|
||||||
|
post.filter(ap_id.eq(object_id)).first::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upsert(conn: &PgConnection, post_form: &PostForm) -> Result<Post, Error> {
|
||||||
|
use crate::schema::post::dsl::*;
|
||||||
|
insert_into(post)
|
||||||
|
.values(post_form)
|
||||||
|
.on_conflict(ap_id)
|
||||||
|
.do_update()
|
||||||
|
.set(post_form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Post {
|
impl Post {
|
||||||
pub fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> {
|
pub fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> {
|
||||||
use crate::schema::post::dsl::*;
|
use crate::schema::post::dsl::*;
|
||||||
|
@ -81,11 +123,6 @@ impl Post {
|
||||||
.load::<Self>(conn)
|
.load::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
|
|
||||||
use crate::schema::post::dsl::*;
|
|
||||||
post.filter(ap_id.eq(object_id)).first::<Self>(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: String) -> Result<Self, Error> {
|
pub fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: String) -> Result<Self, Error> {
|
||||||
use crate::schema::post::dsl::*;
|
use crate::schema::post::dsl::*;
|
||||||
|
|
||||||
|
@ -177,40 +214,6 @@ impl Post {
|
||||||
pub fn is_post_creator(user_id: i32, post_creator_id: i32) -> bool {
|
pub fn is_post_creator(user_id: i32, post_creator_id: i32) -> bool {
|
||||||
user_id == post_creator_id
|
user_id == post_creator_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upsert(conn: &PgConnection, post_form: &PostForm) -> Result<Post, Error> {
|
|
||||||
use crate::schema::post::dsl::*;
|
|
||||||
insert_into(post)
|
|
||||||
.values(post_form)
|
|
||||||
.on_conflict(ap_id)
|
|
||||||
.do_update()
|
|
||||||
.set(post_form)
|
|
||||||
.get_result::<Self>(conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Crud<PostForm> for Post {
|
|
||||||
fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> {
|
|
||||||
use crate::schema::post::dsl::*;
|
|
||||||
post.find(post_id).first::<Self>(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete(conn: &PgConnection, post_id: i32) -> Result<usize, Error> {
|
|
||||||
use crate::schema::post::dsl::*;
|
|
||||||
diesel::delete(post.find(post_id)).execute(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create(conn: &PgConnection, new_post: &PostForm) -> Result<Self, Error> {
|
|
||||||
use crate::schema::post::dsl::*;
|
|
||||||
insert_into(post).values(new_post).get_result::<Self>(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result<Self, Error> {
|
|
||||||
use crate::schema::post::dsl::*;
|
|
||||||
diesel::update(post.find(post_id))
|
|
||||||
.set(new_post)
|
|
||||||
.get_result::<Self>(conn)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
|
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{naive_now, schema::private_message, Crud};
|
use crate::{naive_now, schema::private_message, ApubObject, Crud};
|
||||||
use diesel::{dsl::*, result::Error, *};
|
use diesel::{dsl::*, result::Error, *};
|
||||||
|
|
||||||
#[derive(Queryable, Identifiable, PartialEq, Debug)]
|
#[derive(Queryable, Identifiable, PartialEq, Debug)]
|
||||||
|
@ -55,6 +55,28 @@ impl Crud<PrivateMessageForm> for PrivateMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApubObject<PrivateMessageForm> for PrivateMessage {
|
||||||
|
fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
use crate::schema::private_message::dsl::*;
|
||||||
|
private_message
|
||||||
|
.filter(ap_id.eq(object_id))
|
||||||
|
.first::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upsert(conn: &PgConnection, private_message_form: &PrivateMessageForm) -> Result<Self, Error> {
|
||||||
|
use crate::schema::private_message::dsl::*;
|
||||||
|
insert_into(private_message)
|
||||||
|
.values(private_message_form)
|
||||||
|
.on_conflict(ap_id)
|
||||||
|
.do_update()
|
||||||
|
.set(private_message_form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PrivateMessage {
|
impl PrivateMessage {
|
||||||
pub fn update_ap_id(
|
pub fn update_ap_id(
|
||||||
conn: &PgConnection,
|
conn: &PgConnection,
|
||||||
|
@ -68,13 +90,6 @@ impl PrivateMessage {
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
|
|
||||||
use crate::schema::private_message::dsl::*;
|
|
||||||
private_message
|
|
||||||
.filter(ap_id.eq(object_id))
|
|
||||||
.first::<Self>(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_content(
|
pub fn update_content(
|
||||||
conn: &PgConnection,
|
conn: &PgConnection,
|
||||||
private_message_id: i32,
|
private_message_id: i32,
|
||||||
|
@ -118,20 +133,6 @@ impl PrivateMessage {
|
||||||
.set(read.eq(true))
|
.set(read.eq(true))
|
||||||
.get_results::<Self>(conn)
|
.get_results::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO use this
|
|
||||||
pub fn upsert(
|
|
||||||
conn: &PgConnection,
|
|
||||||
private_message_form: &PrivateMessageForm,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
use crate::schema::private_message::dsl::*;
|
|
||||||
insert_into(private_message)
|
|
||||||
.values(private_message_form)
|
|
||||||
.on_conflict(ap_id)
|
|
||||||
.do_update()
|
|
||||||
.set(private_message_form)
|
|
||||||
.get_result::<Self>(conn)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::{
|
||||||
is_email_regex,
|
is_email_regex,
|
||||||
naive_now,
|
naive_now,
|
||||||
schema::{user_, user_::dsl::*},
|
schema::{user_, user_::dsl::*},
|
||||||
|
ApubObject,
|
||||||
Crud,
|
Crud,
|
||||||
};
|
};
|
||||||
use bcrypt::{hash, DEFAULT_COST};
|
use bcrypt::{hash, DEFAULT_COST};
|
||||||
|
@ -89,6 +90,25 @@ impl Crud<UserForm> for User_ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApubObject<UserForm> for User_ {
|
||||||
|
fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
|
||||||
|
use crate::schema::user_::dsl::*;
|
||||||
|
user_
|
||||||
|
.filter(deleted.eq(false))
|
||||||
|
.filter(actor_id.eq(object_id))
|
||||||
|
.first::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upsert(conn: &PgConnection, user_form: &UserForm) -> Result<User_, Error> {
|
||||||
|
insert_into(user_)
|
||||||
|
.values(user_form)
|
||||||
|
.on_conflict(actor_id)
|
||||||
|
.do_update()
|
||||||
|
.set(user_form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl User_ {
|
impl User_ {
|
||||||
pub fn register(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> {
|
pub fn register(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> {
|
||||||
let mut edited_user = form.clone();
|
let mut edited_user = form.clone();
|
||||||
|
@ -135,14 +155,6 @@ impl User_ {
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_from_actor_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
|
|
||||||
use crate::schema::user_::dsl::*;
|
|
||||||
user_
|
|
||||||
.filter(deleted.eq(false))
|
|
||||||
.filter(actor_id.eq(object_id))
|
|
||||||
.first::<Self>(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_by_email_or_username(
|
pub fn find_by_email_or_username(
|
||||||
conn: &PgConnection,
|
conn: &PgConnection,
|
||||||
username_or_email: &str,
|
username_or_email: &str,
|
||||||
|
@ -179,12 +191,9 @@ impl User_ {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upsert(conn: &PgConnection, user_form: &UserForm) -> Result<User_, Error> {
|
pub fn mark_as_updated(conn: &PgConnection, user_id: i32) -> Result<User_, Error> {
|
||||||
insert_into(user_)
|
diesel::update(user_.find(user_id))
|
||||||
.values(user_form)
|
.set((last_refreshed_at.eq(naive_now()),))
|
||||||
.on_conflict(actor_id)
|
|
||||||
.do_update()
|
|
||||||
.set(user_form)
|
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue