This commit is contained in:
parent
05a7fced65
commit
d82194cfe9
16 changed files with 460 additions and 521 deletions
|
@ -1,9 +1,10 @@
|
||||||
use crate::Perform;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
build_response::build_comment_response,
|
build_response::build_comment_response,
|
||||||
comment::{CommentResponse, CreateCommentLike},
|
comment::{CommentResponse, CreateCommentLike},
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::{check_community_ban, check_downvotes_enabled, local_user_view_from_jwt},
|
utils::{check_community_ban, check_downvotes_enabled, local_user_view_from_jwt},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -17,70 +18,80 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{CommentView, LocalUserView};
|
use lemmy_db_views::structs::{CommentView, LocalUserView};
|
||||||
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[tracing::instrument(skip(context))]
|
||||||
impl Perform for CreateCommentLike {
|
pub async fn like_comment(
|
||||||
type Response = CommentResponse;
|
data: Json<CreateCommentLike>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
) -> Result<Json<CommentResponse>, LemmyError> {
|
||||||
|
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||||
|
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
let mut recipient_ids = Vec::<LocalUserId>::new();
|
||||||
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommentResponse, LemmyError> {
|
|
||||||
let data: &CreateCommentLike = self;
|
|
||||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
|
||||||
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
|
|
||||||
|
|
||||||
let mut recipient_ids = Vec::<LocalUserId>::new();
|
// Don't do a downvote if site has downvotes disabled
|
||||||
|
check_downvotes_enabled(data.score, &local_site)?;
|
||||||
|
|
||||||
// Don't do a downvote if site has downvotes disabled
|
let comment_id = data.comment_id;
|
||||||
check_downvotes_enabled(data.score, &local_site)?;
|
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
|
||||||
|
|
||||||
let comment_id = data.comment_id;
|
check_community_ban(
|
||||||
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
|
local_user_view.person.id,
|
||||||
|
orig_comment.community.id,
|
||||||
|
&mut context.pool(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
check_community_ban(
|
// Add parent poster or commenter to recipients
|
||||||
local_user_view.person.id,
|
let comment_reply = CommentReply::read_by_comment(&mut context.pool(), comment_id).await;
|
||||||
orig_comment.community.id,
|
if let Ok(reply) = comment_reply {
|
||||||
&mut context.pool(),
|
let recipient_id = reply.recipient_id;
|
||||||
)
|
if let Ok(local_recipient) = LocalUserView::read_person(&mut context.pool(), recipient_id).await
|
||||||
.await?;
|
{
|
||||||
|
recipient_ids.push(local_recipient.local_user.id);
|
||||||
// Add parent poster or commenter to recipients
|
|
||||||
let comment_reply = CommentReply::read_by_comment(&mut context.pool(), comment_id).await;
|
|
||||||
if let Ok(reply) = comment_reply {
|
|
||||||
let recipient_id = reply.recipient_id;
|
|
||||||
if let Ok(local_recipient) =
|
|
||||||
LocalUserView::read_person(&mut context.pool(), recipient_id).await
|
|
||||||
{
|
|
||||||
recipient_ids.push(local_recipient.local_user.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let like_form = CommentLikeForm {
|
let like_form = CommentLikeForm {
|
||||||
comment_id: data.comment_id,
|
comment_id: data.comment_id,
|
||||||
post_id: orig_comment.post.id,
|
post_id: orig_comment.post.id,
|
||||||
person_id: local_user_view.person.id,
|
person_id: local_user_view.person.id,
|
||||||
score: data.score,
|
score: data.score,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove any likes first
|
// Remove any likes first
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
|
|
||||||
CommentLike::remove(&mut context.pool(), person_id, comment_id).await?;
|
CommentLike::remove(&mut context.pool(), person_id, comment_id).await?;
|
||||||
|
|
||||||
// Only add the like if the score isnt 0
|
// Only add the like if the score isnt 0
|
||||||
let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
|
let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
|
||||||
if do_add {
|
if do_add {
|
||||||
CommentLike::like(&mut context.pool(), &like_form)
|
CommentLike::like(&mut context.pool(), &like_form)
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntLikeComment)?;
|
.with_lemmy_type(LemmyErrorType::CouldntLikeComment)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActivityChannel::submit_activity(
|
||||||
|
SendActivityData::LikePostOrComment(
|
||||||
|
orig_comment.comment.ap_id,
|
||||||
|
local_user_view.person.clone(),
|
||||||
|
orig_comment.community,
|
||||||
|
data.score,
|
||||||
|
),
|
||||||
|
&context,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(Json(
|
||||||
build_comment_response(
|
build_comment_response(
|
||||||
context,
|
context.deref(),
|
||||||
comment_id,
|
comment_id,
|
||||||
Some(local_user_view),
|
Some(local_user_view),
|
||||||
None,
|
None,
|
||||||
recipient_ids,
|
recipient_ids,
|
||||||
)
|
)
|
||||||
.await
|
.await?,
|
||||||
}
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::Perform;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
build_response::build_post_response,
|
build_response::build_post_response,
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
post::{CreatePostLike, PostResponse},
|
post::{CreatePostLike, PostResponse},
|
||||||
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::{
|
utils::{
|
||||||
check_community_ban,
|
check_community_ban,
|
||||||
check_community_deleted_or_removed,
|
check_community_deleted_or_removed,
|
||||||
|
@ -14,66 +15,78 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
|
community::Community,
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
post::{Post, PostLike, PostLikeForm},
|
post::{Post, PostLike, PostLikeForm},
|
||||||
},
|
},
|
||||||
traits::{Crud, Likeable},
|
traits::{Crud, Likeable},
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[tracing::instrument(skip(context))]
|
||||||
impl Perform for CreatePostLike {
|
pub async fn like_post(
|
||||||
type Response = PostResponse;
|
data: Json<CreatePostLike>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
) -> Result<Json<PostResponse>, LemmyError> {
|
||||||
|
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
|
||||||
|
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
// Don't do a downvote if site has downvotes disabled
|
||||||
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostResponse, LemmyError> {
|
check_downvotes_enabled(data.score, &local_site)?;
|
||||||
let data: &CreatePostLike = self;
|
|
||||||
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
|
|
||||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
|
||||||
|
|
||||||
// Don't do a downvote if site has downvotes disabled
|
// Check for a community ban
|
||||||
check_downvotes_enabled(data.score, &local_site)?;
|
let post_id = data.post_id;
|
||||||
|
let post = Post::read(&mut context.pool(), post_id).await?;
|
||||||
|
|
||||||
// Check for a community ban
|
check_community_ban(
|
||||||
let post_id = data.post_id;
|
local_user_view.person.id,
|
||||||
let post = Post::read(&mut context.pool(), post_id).await?;
|
post.community_id,
|
||||||
|
&mut context.pool(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
check_community_deleted_or_removed(post.community_id, &mut context.pool()).await?;
|
||||||
|
|
||||||
check_community_ban(
|
let like_form = PostLikeForm {
|
||||||
local_user_view.person.id,
|
post_id: data.post_id,
|
||||||
post.community_id,
|
person_id: local_user_view.person.id,
|
||||||
&mut context.pool(),
|
score: data.score,
|
||||||
)
|
};
|
||||||
.await?;
|
|
||||||
check_community_deleted_or_removed(post.community_id, &mut context.pool()).await?;
|
|
||||||
|
|
||||||
let like_form = PostLikeForm {
|
// Remove any likes first
|
||||||
post_id: data.post_id,
|
let person_id = local_user_view.person.id;
|
||||||
person_id: local_user_view.person.id,
|
|
||||||
score: data.score,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove any likes first
|
PostLike::remove(&mut context.pool(), person_id, post_id).await?;
|
||||||
let person_id = local_user_view.person.id;
|
|
||||||
|
|
||||||
PostLike::remove(&mut context.pool(), person_id, post_id).await?;
|
// Only add the like if the score isnt 0
|
||||||
|
let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
|
||||||
|
if do_add {
|
||||||
|
PostLike::like(&mut context.pool(), &like_form)
|
||||||
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Only add the like if the score isnt 0
|
// Mark the post as read
|
||||||
let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
|
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
|
||||||
if do_add {
|
|
||||||
PostLike::like(&mut context.pool(), &like_form)
|
|
||||||
.await
|
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark the post as read
|
ActivityChannel::submit_activity(
|
||||||
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
|
SendActivityData::LikePostOrComment(
|
||||||
|
post.ap_id,
|
||||||
|
local_user_view.person.clone(),
|
||||||
|
Community::read(&mut context.pool(), post.community_id).await?,
|
||||||
|
data.score,
|
||||||
|
),
|
||||||
|
&context,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(Json(
|
||||||
build_post_response(
|
build_post_response(
|
||||||
context,
|
context.deref(),
|
||||||
post.community_id,
|
post.community_id,
|
||||||
local_user_view.person.id,
|
local_user_view.person.id,
|
||||||
post_id,
|
post_id,
|
||||||
)
|
)
|
||||||
.await
|
.await?,
|
||||||
}
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
mod feature;
|
pub mod feature;
|
||||||
mod get_link_metadata;
|
pub mod get_link_metadata;
|
||||||
mod like;
|
pub mod like;
|
||||||
mod lock;
|
pub mod lock;
|
||||||
mod mark_read;
|
pub mod mark_read;
|
||||||
mod save;
|
pub mod save;
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
use crate::context::LemmyContext;
|
use crate::context::LemmyContext;
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use lemmy_db_schema::source::{comment::Comment, post::Post};
|
use lemmy_db_schema::{
|
||||||
|
newtypes::DbUrl,
|
||||||
|
source::{comment::Comment, community::Community, person::Person, post::Post},
|
||||||
|
};
|
||||||
use lemmy_utils::{error::LemmyResult, SYNCHRONOUS_FEDERATION};
|
use lemmy_utils::{error::LemmyResult, SYNCHRONOUS_FEDERATION};
|
||||||
use once_cell::sync::{Lazy, OnceCell};
|
use once_cell::sync::{Lazy, OnceCell};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
|
@ -22,7 +25,12 @@ pub static MATCH_OUTGOING_ACTIVITIES: OnceCell<MatchOutgoingActivitiesBoxed> = O
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SendActivityData {
|
pub enum SendActivityData {
|
||||||
CreatePost(Post),
|
CreatePost(Post),
|
||||||
|
UpdatePost(Post),
|
||||||
CreateComment(Comment),
|
CreateComment(Comment),
|
||||||
|
DeleteComment(Comment, Person, Community),
|
||||||
|
RemoveComment(Comment, Person, Community, Option<String>),
|
||||||
|
UpdateComment(Comment),
|
||||||
|
LikePostOrComment(DbUrl, Person, Community, i16),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: instead of static, move this into LemmyContext. make sure that stopping the process with
|
// TODO: instead of static, move this into LemmyContext. make sure that stopping the process with
|
||||||
|
|
|
@ -36,7 +36,6 @@ use lemmy_utils::{
|
||||||
validation::is_valid_body_field,
|
validation::is_valid_body_field,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
const MAX_COMMENT_DEPTH_LIMIT: usize = 100;
|
const MAX_COMMENT_DEPTH_LIMIT: usize = 100;
|
||||||
|
|
||||||
|
@ -196,7 +195,7 @@ pub async fn create_comment(
|
||||||
|
|
||||||
Ok(Json(
|
Ok(Json(
|
||||||
build_comment_response(
|
build_comment_response(
|
||||||
context.deref(),
|
&context,
|
||||||
inserted_comment.id,
|
inserted_comment.id,
|
||||||
Some(local_user_view),
|
Some(local_user_view),
|
||||||
data.form_id.clone(),
|
data.form_id.clone(),
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::PerformCrud;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
build_response::{build_comment_response, send_local_notifs},
|
build_response::{build_comment_response, send_local_notifs},
|
||||||
comment::{CommentResponse, DeleteComment},
|
comment::{CommentResponse, DeleteComment},
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::{check_community_ban, local_user_view_from_jwt},
|
utils::{check_community_ban, local_user_view_from_jwt},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -15,66 +16,75 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::CommentView;
|
use lemmy_db_views::structs::CommentView;
|
||||||
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[tracing::instrument(skip(context))]
|
||||||
impl PerformCrud for DeleteComment {
|
pub async fn delete_comment(
|
||||||
type Response = CommentResponse;
|
data: Json<DeleteComment>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
) -> Result<Json<CommentResponse>, LemmyError> {
|
||||||
|
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
let comment_id = data.comment_id;
|
||||||
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommentResponse, LemmyError> {
|
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
|
||||||
let data: &DeleteComment = self;
|
|
||||||
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
|
|
||||||
|
|
||||||
let comment_id = data.comment_id;
|
// Dont delete it if its already been deleted.
|
||||||
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
|
if orig_comment.comment.deleted == data.deleted {
|
||||||
|
return Err(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Dont delete it if its already been deleted.
|
check_community_ban(
|
||||||
if orig_comment.comment.deleted == data.deleted {
|
local_user_view.person.id,
|
||||||
return Err(LemmyErrorType::CouldntUpdateComment)?;
|
orig_comment.community.id,
|
||||||
}
|
&mut context.pool(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
check_community_ban(
|
// Verify that only the creator can delete
|
||||||
local_user_view.person.id,
|
if local_user_view.person.id != orig_comment.creator.id {
|
||||||
orig_comment.community.id,
|
return Err(LemmyErrorType::NoCommentEditAllowed)?;
|
||||||
&mut context.pool(),
|
}
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Verify that only the creator can delete
|
// Do the delete
|
||||||
if local_user_view.person.id != orig_comment.creator.id {
|
let deleted = data.deleted;
|
||||||
return Err(LemmyErrorType::NoCommentEditAllowed)?;
|
let updated_comment = Comment::update(
|
||||||
}
|
&mut context.pool(),
|
||||||
|
comment_id,
|
||||||
|
&CommentUpdateForm::builder().deleted(Some(deleted)).build(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
// Do the delete
|
let post_id = updated_comment.post_id;
|
||||||
let deleted = data.deleted;
|
let post = Post::read(&mut context.pool(), post_id).await?;
|
||||||
let updated_comment = Comment::update(
|
let recipient_ids = send_local_notifs(
|
||||||
&mut context.pool(),
|
vec![],
|
||||||
comment_id,
|
&updated_comment,
|
||||||
&CommentUpdateForm::builder().deleted(Some(deleted)).build(),
|
&local_user_view.person,
|
||||||
)
|
&post,
|
||||||
.await
|
false,
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
&context,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let updated_comment_id = updated_comment.id;
|
||||||
|
|
||||||
let post_id = updated_comment.post_id;
|
ActivityChannel::submit_activity(
|
||||||
let post = Post::read(&mut context.pool(), post_id).await?;
|
SendActivityData::DeleteComment(
|
||||||
let recipient_ids = send_local_notifs(
|
updated_comment,
|
||||||
vec![],
|
local_user_view.person.clone(),
|
||||||
&updated_comment,
|
orig_comment.community,
|
||||||
&local_user_view.person,
|
),
|
||||||
&post,
|
&context,
|
||||||
false,
|
)
|
||||||
context,
|
.await?;
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
|
Ok(Json(
|
||||||
build_comment_response(
|
build_comment_response(
|
||||||
context.deref(),
|
&context,
|
||||||
updated_comment.id,
|
updated_comment_id,
|
||||||
Some(local_user_view),
|
Some(local_user_view),
|
||||||
None,
|
None,
|
||||||
recipient_ids,
|
recipient_ids,
|
||||||
)
|
)
|
||||||
.await
|
.await?,
|
||||||
}
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::local_site::LocalSite;
|
use lemmy_db_schema::source::local_site::LocalSite;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
pub async fn get_comment(
|
pub async fn get_comment(
|
||||||
|
@ -20,6 +19,6 @@ pub async fn get_comment(
|
||||||
check_private_instance(&local_user_view, &local_site)?;
|
check_private_instance(&local_user_view, &local_site)?;
|
||||||
|
|
||||||
Ok(Json(
|
Ok(Json(
|
||||||
build_comment_response(context.deref(), data.id, local_user_view, None, vec![]).await?,
|
build_comment_response(&context, data.id, local_user_view, None, vec![]).await?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::PerformCrud;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
build_response::{build_comment_response, send_local_notifs},
|
build_response::{build_comment_response, send_local_notifs},
|
||||||
comment::{CommentResponse, RemoveComment},
|
comment::{CommentResponse, RemoveComment},
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::{check_community_ban, is_mod_or_admin, local_user_view_from_jwt},
|
utils::{check_community_ban, is_mod_or_admin, local_user_view_from_jwt},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -16,73 +17,83 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::CommentView;
|
use lemmy_db_views::structs::CommentView;
|
||||||
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[tracing::instrument(skip(context))]
|
||||||
impl PerformCrud for RemoveComment {
|
pub async fn remove_comment(
|
||||||
type Response = CommentResponse;
|
data: Json<RemoveComment>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
) -> Result<Json<CommentResponse>, LemmyError> {
|
||||||
|
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
let comment_id = data.comment_id;
|
||||||
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommentResponse, LemmyError> {
|
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
|
||||||
let data: &RemoveComment = self;
|
|
||||||
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
|
|
||||||
|
|
||||||
let comment_id = data.comment_id;
|
check_community_ban(
|
||||||
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
|
local_user_view.person.id,
|
||||||
|
orig_comment.community.id,
|
||||||
|
&mut context.pool(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
check_community_ban(
|
// Verify that only a mod or admin can remove
|
||||||
local_user_view.person.id,
|
is_mod_or_admin(
|
||||||
orig_comment.community.id,
|
&mut context.pool(),
|
||||||
&mut context.pool(),
|
local_user_view.person.id,
|
||||||
)
|
orig_comment.community.id,
|
||||||
.await?;
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Verify that only a mod or admin can remove
|
// Do the remove
|
||||||
is_mod_or_admin(
|
let removed = data.removed;
|
||||||
&mut context.pool(),
|
let updated_comment = Comment::update(
|
||||||
local_user_view.person.id,
|
&mut context.pool(),
|
||||||
orig_comment.community.id,
|
comment_id,
|
||||||
)
|
&CommentUpdateForm::builder().removed(Some(removed)).build(),
|
||||||
.await?;
|
)
|
||||||
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
// Do the remove
|
// Mod tables
|
||||||
let removed = data.removed;
|
let form = ModRemoveCommentForm {
|
||||||
let updated_comment = Comment::update(
|
mod_person_id: local_user_view.person.id,
|
||||||
&mut context.pool(),
|
comment_id: data.comment_id,
|
||||||
comment_id,
|
removed: Some(removed),
|
||||||
&CommentUpdateForm::builder().removed(Some(removed)).build(),
|
reason: data.reason.clone(),
|
||||||
)
|
};
|
||||||
.await
|
ModRemoveComment::create(&mut context.pool(), &form).await?;
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
|
||||||
|
|
||||||
// Mod tables
|
let post_id = updated_comment.post_id;
|
||||||
let form = ModRemoveCommentForm {
|
let post = Post::read(&mut context.pool(), post_id).await?;
|
||||||
mod_person_id: local_user_view.person.id,
|
let recipient_ids = send_local_notifs(
|
||||||
comment_id: data.comment_id,
|
vec![],
|
||||||
removed: Some(removed),
|
&updated_comment,
|
||||||
reason: data.reason.clone(),
|
&local_user_view.person.clone(),
|
||||||
};
|
&post,
|
||||||
ModRemoveComment::create(&mut context.pool(), &form).await?;
|
false,
|
||||||
|
&context,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let updated_comment_id = updated_comment.id;
|
||||||
|
|
||||||
let post_id = updated_comment.post_id;
|
ActivityChannel::submit_activity(
|
||||||
let post = Post::read(&mut context.pool(), post_id).await?;
|
SendActivityData::RemoveComment(
|
||||||
let recipient_ids = send_local_notifs(
|
updated_comment,
|
||||||
vec![],
|
local_user_view.person.clone(),
|
||||||
&updated_comment,
|
orig_comment.community,
|
||||||
&local_user_view.person.clone(),
|
data.reason.clone(),
|
||||||
&post,
|
),
|
||||||
false,
|
&context,
|
||||||
context,
|
)
|
||||||
)
|
.await?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
|
Ok(Json(
|
||||||
build_comment_response(
|
build_comment_response(
|
||||||
context.deref(),
|
&context,
|
||||||
updated_comment.id,
|
updated_comment_id,
|
||||||
Some(local_user_view),
|
Some(local_user_view),
|
||||||
None,
|
None,
|
||||||
recipient_ids,
|
recipient_ids,
|
||||||
)
|
)
|
||||||
.await
|
.await?,
|
||||||
}
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::PerformCrud;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
build_response::{build_comment_response, send_local_notifs},
|
build_response::{build_comment_response, send_local_notifs},
|
||||||
comment::{CommentResponse, EditComment},
|
comment::{CommentResponse, EditComment},
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::{
|
utils::{
|
||||||
check_community_ban,
|
check_community_ban,
|
||||||
local_site_to_slur_regex,
|
local_site_to_slur_regex,
|
||||||
|
@ -29,79 +30,83 @@ use lemmy_utils::{
|
||||||
validation::is_valid_body_field,
|
validation::is_valid_body_field,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[tracing::instrument(skip(context))]
|
||||||
impl PerformCrud for EditComment {
|
pub async fn update_comment(
|
||||||
type Response = CommentResponse;
|
data: Json<EditComment>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
) -> Result<Json<CommentResponse>, LemmyError> {
|
||||||
|
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
|
||||||
|
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
let comment_id = data.comment_id;
|
||||||
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommentResponse, LemmyError> {
|
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
|
||||||
let data: &EditComment = self;
|
|
||||||
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
|
|
||||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
|
||||||
|
|
||||||
let comment_id = data.comment_id;
|
check_community_ban(
|
||||||
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
|
local_user_view.person.id,
|
||||||
|
orig_comment.community.id,
|
||||||
|
&mut context.pool(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
check_community_ban(
|
// Verify that only the creator can edit
|
||||||
local_user_view.person.id,
|
if local_user_view.person.id != orig_comment.creator.id {
|
||||||
orig_comment.community.id,
|
return Err(LemmyErrorType::NoCommentEditAllowed)?;
|
||||||
&mut context.pool(),
|
}
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Verify that only the creator can edit
|
let language_id = data.language_id;
|
||||||
if local_user_view.person.id != orig_comment.creator.id {
|
CommunityLanguage::is_allowed_community_language(
|
||||||
return Err(LemmyErrorType::NoCommentEditAllowed)?;
|
&mut context.pool(),
|
||||||
}
|
language_id,
|
||||||
|
orig_comment.community.id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let language_id = self.language_id;
|
// Update the Content
|
||||||
CommunityLanguage::is_allowed_community_language(
|
let content = data
|
||||||
&mut context.pool(),
|
.content
|
||||||
language_id,
|
.as_ref()
|
||||||
orig_comment.community.id,
|
.map(|c| remove_slurs(c, &local_site_to_slur_regex(&local_site)));
|
||||||
)
|
is_valid_body_field(&content, false)?;
|
||||||
.await?;
|
let content = sanitize_html_opt(&content);
|
||||||
|
|
||||||
// Update the Content
|
let comment_id = data.comment_id;
|
||||||
let content = data
|
let form = CommentUpdateForm::builder()
|
||||||
.content
|
.content(content)
|
||||||
.as_ref()
|
.language_id(data.language_id)
|
||||||
.map(|c| remove_slurs(c, &local_site_to_slur_regex(&local_site)));
|
.updated(Some(Some(naive_now())))
|
||||||
is_valid_body_field(&content, false)?;
|
.build();
|
||||||
let content = sanitize_html_opt(&content);
|
let updated_comment = Comment::update(&mut context.pool(), comment_id, &form)
|
||||||
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
let comment_id = data.comment_id;
|
// Do the mentions / recipients
|
||||||
let form = CommentUpdateForm::builder()
|
let updated_comment_content = updated_comment.content.clone();
|
||||||
.content(content)
|
let mentions = scrape_text_for_mentions(&updated_comment_content);
|
||||||
.language_id(data.language_id)
|
let recipient_ids = send_local_notifs(
|
||||||
.updated(Some(Some(naive_now())))
|
mentions,
|
||||||
.build();
|
&updated_comment,
|
||||||
let updated_comment = Comment::update(&mut context.pool(), comment_id, &form)
|
&local_user_view.person,
|
||||||
.await
|
&orig_comment.post,
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
false,
|
||||||
|
&context,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Do the mentions / recipients
|
ActivityChannel::submit_activity(
|
||||||
let updated_comment_content = updated_comment.content.clone();
|
SendActivityData::UpdateComment(updated_comment.clone()),
|
||||||
let mentions = scrape_text_for_mentions(&updated_comment_content);
|
&context,
|
||||||
let recipient_ids = send_local_notifs(
|
)
|
||||||
mentions,
|
.await?;
|
||||||
&updated_comment,
|
|
||||||
&local_user_view.person,
|
|
||||||
&orig_comment.post,
|
|
||||||
false,
|
|
||||||
context,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
|
Ok(Json(
|
||||||
build_comment_response(
|
build_comment_response(
|
||||||
context.deref(),
|
&context,
|
||||||
updated_comment.id,
|
updated_comment.id,
|
||||||
Some(local_user_view),
|
Some(local_user_view),
|
||||||
self.form_id.clone(),
|
data.form_id.clone(),
|
||||||
recipient_ids,
|
recipient_ids,
|
||||||
)
|
)
|
||||||
.await
|
.await?,
|
||||||
}
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use crate::PerformCrud;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
build_response::build_post_response,
|
build_response::build_post_response,
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
post::{EditPost, PostResponse},
|
post::{EditPost, PostResponse},
|
||||||
request::fetch_site_data,
|
request::fetch_site_data,
|
||||||
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::{
|
utils::{
|
||||||
check_community_ban,
|
check_community_ban,
|
||||||
local_site_to_slur_regex,
|
local_site_to_slur_regex,
|
||||||
|
@ -28,95 +29,97 @@ use lemmy_utils::{
|
||||||
validation::{check_url_scheme, clean_url_params, is_valid_body_field, is_valid_post_title},
|
validation::{check_url_scheme, clean_url_params, is_valid_body_field, is_valid_post_title},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[tracing::instrument(skip(context))]
|
||||||
impl PerformCrud for EditPost {
|
pub async fn update_post(
|
||||||
type Response = PostResponse;
|
data: Json<EditPost>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
) -> Result<Json<PostResponse>, LemmyError> {
|
||||||
|
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
|
||||||
|
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
let data_url = data.url.as_ref();
|
||||||
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostResponse, LemmyError> {
|
|
||||||
let data: &EditPost = self;
|
|
||||||
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
|
|
||||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
|
||||||
|
|
||||||
let data_url = data.url.as_ref();
|
// TODO No good way to handle a clear.
|
||||||
|
// Issue link: https://github.com/LemmyNet/lemmy/issues/2287
|
||||||
|
let url = Some(data_url.map(clean_url_params).map(Into::into));
|
||||||
|
|
||||||
// TODO No good way to handle a clear.
|
let slur_regex = local_site_to_slur_regex(&local_site);
|
||||||
// Issue link: https://github.com/LemmyNet/lemmy/issues/2287
|
check_slurs_opt(&data.name, &slur_regex)?;
|
||||||
let url = Some(data_url.map(clean_url_params).map(Into::into));
|
check_slurs_opt(&data.body, &slur_regex)?;
|
||||||
|
|
||||||
let slur_regex = local_site_to_slur_regex(&local_site);
|
if let Some(name) = &data.name {
|
||||||
check_slurs_opt(&data.name, &slur_regex)?;
|
is_valid_post_title(name)?;
|
||||||
check_slurs_opt(&data.body, &slur_regex)?;
|
}
|
||||||
|
|
||||||
if let Some(name) = &data.name {
|
is_valid_body_field(&data.body, true)?;
|
||||||
is_valid_post_title(name)?;
|
check_url_scheme(&data.url)?;
|
||||||
}
|
|
||||||
|
|
||||||
is_valid_body_field(&data.body, true)?;
|
let post_id = data.post_id;
|
||||||
check_url_scheme(&data.url)?;
|
let orig_post = Post::read(&mut context.pool(), post_id).await?;
|
||||||
|
|
||||||
let post_id = data.post_id;
|
check_community_ban(
|
||||||
let orig_post = Post::read(&mut context.pool(), post_id).await?;
|
local_user_view.person.id,
|
||||||
|
orig_post.community_id,
|
||||||
|
&mut context.pool(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
check_community_ban(
|
// Verify that only the creator can edit
|
||||||
local_user_view.person.id,
|
if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) {
|
||||||
orig_post.community_id,
|
return Err(LemmyErrorType::NoPostEditAllowed)?;
|
||||||
&mut context.pool(),
|
}
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Verify that only the creator can edit
|
// Fetch post links and Pictrs cached image
|
||||||
if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) {
|
let data_url = data.url.as_ref();
|
||||||
return Err(LemmyErrorType::NoPostEditAllowed)?;
|
let (metadata_res, thumbnail_url) =
|
||||||
}
|
fetch_site_data(context.client(), context.settings(), data_url, true).await;
|
||||||
|
let (embed_title, embed_description, embed_video_url) = metadata_res
|
||||||
|
.map(|u| (Some(u.title), Some(u.description), Some(u.embed_video_url)))
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
// Fetch post links and Pictrs cached image
|
let name = sanitize_html_opt(&data.name);
|
||||||
let data_url = data.url.as_ref();
|
let body = sanitize_html_opt(&data.body);
|
||||||
let (metadata_res, thumbnail_url) =
|
let body = diesel_option_overwrite(body);
|
||||||
fetch_site_data(context.client(), context.settings(), data_url, true).await;
|
let embed_title = embed_title.map(|e| sanitize_html_opt(&e));
|
||||||
let (embed_title, embed_description, embed_video_url) = metadata_res
|
let embed_description = embed_description.map(|e| sanitize_html_opt(&e));
|
||||||
.map(|u| (Some(u.title), Some(u.description), Some(u.embed_video_url)))
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let name = sanitize_html_opt(&data.name);
|
let language_id = data.language_id;
|
||||||
let body = sanitize_html_opt(&data.body);
|
CommunityLanguage::is_allowed_community_language(
|
||||||
let body = diesel_option_overwrite(body);
|
&mut context.pool(),
|
||||||
let embed_title = embed_title.map(|e| sanitize_html_opt(&e));
|
language_id,
|
||||||
let embed_description = embed_description.map(|e| sanitize_html_opt(&e));
|
orig_post.community_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let language_id = self.language_id;
|
let post_form = PostUpdateForm::builder()
|
||||||
CommunityLanguage::is_allowed_community_language(
|
.name(name)
|
||||||
&mut context.pool(),
|
.url(url)
|
||||||
language_id,
|
.body(body)
|
||||||
orig_post.community_id,
|
.nsfw(data.nsfw)
|
||||||
)
|
.embed_title(embed_title)
|
||||||
.await?;
|
.embed_description(embed_description)
|
||||||
|
.embed_video_url(embed_video_url)
|
||||||
|
.language_id(data.language_id)
|
||||||
|
.thumbnail_url(Some(thumbnail_url))
|
||||||
|
.updated(Some(Some(naive_now())))
|
||||||
|
.build();
|
||||||
|
|
||||||
let post_form = PostUpdateForm::builder()
|
let post_id = data.post_id;
|
||||||
.name(name)
|
let updated_post = Post::update(&mut context.pool(), post_id, &post_form)
|
||||||
.url(url)
|
.await
|
||||||
.body(body)
|
.with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?;
|
||||||
.nsfw(data.nsfw)
|
|
||||||
.embed_title(embed_title)
|
|
||||||
.embed_description(embed_description)
|
|
||||||
.embed_video_url(embed_video_url)
|
|
||||||
.language_id(data.language_id)
|
|
||||||
.thumbnail_url(Some(thumbnail_url))
|
|
||||||
.updated(Some(Some(naive_now())))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let post_id = data.post_id;
|
ActivityChannel::submit_activity(SendActivityData::UpdatePost(updated_post), &context).await?;
|
||||||
Post::update(&mut context.pool(), post_id, &post_form)
|
|
||||||
.await
|
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?;
|
|
||||||
|
|
||||||
|
Ok(Json(
|
||||||
build_post_response(
|
build_post_response(
|
||||||
context,
|
context.deref(),
|
||||||
orig_post.community_id,
|
orig_post.community_id,
|
||||||
local_user_view.person.id,
|
local_user_view.person.id,
|
||||||
post_id,
|
post_id,
|
||||||
)
|
)
|
||||||
.await
|
.await?,
|
||||||
}
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ use crate::{
|
||||||
activities::{create_or_update::note::CreateOrUpdateNote, CreateOrUpdateType},
|
activities::{create_or_update::note::CreateOrUpdateNote, CreateOrUpdateType},
|
||||||
InCommunity,
|
InCommunity,
|
||||||
},
|
},
|
||||||
SendActivity,
|
|
||||||
};
|
};
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
|
@ -25,7 +24,6 @@ use activitypub_federation::{
|
||||||
};
|
};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
build_response::send_local_notifs,
|
build_response::send_local_notifs,
|
||||||
comment::{CommentResponse, EditComment},
|
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
utils::{check_post_deleted_or_removed, is_mod_or_admin},
|
utils::{check_post_deleted_or_removed, is_mod_or_admin},
|
||||||
};
|
};
|
||||||
|
@ -43,25 +41,6 @@ use lemmy_db_schema::{
|
||||||
use lemmy_utils::{error::LemmyError, utils::mention::scrape_text_for_mentions};
|
use lemmy_utils::{error::LemmyError, utils::mention::scrape_text_for_mentions};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl SendActivity for EditComment {
|
|
||||||
type Response = CommentResponse;
|
|
||||||
|
|
||||||
async fn send_activity(
|
|
||||||
_request: &Self,
|
|
||||||
response: &Self::Response,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
CreateOrUpdateNote::send(
|
|
||||||
response.comment_view.comment.clone(),
|
|
||||||
response.comment_view.creator.id,
|
|
||||||
CreateOrUpdateType::Update,
|
|
||||||
context.reset_request_count(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CreateOrUpdateNote {
|
impl CreateOrUpdateNote {
|
||||||
#[tracing::instrument(skip(comment, person_id, kind, context))]
|
#[tracing::instrument(skip(comment, person_id, kind, context))]
|
||||||
pub(crate) async fn send(
|
pub(crate) async fn send(
|
||||||
|
|
|
@ -14,7 +14,6 @@ use crate::{
|
||||||
activities::{create_or_update::page::CreateOrUpdatePage, CreateOrUpdateType},
|
activities::{create_or_update::page::CreateOrUpdatePage, CreateOrUpdateType},
|
||||||
InCommunity,
|
InCommunity,
|
||||||
},
|
},
|
||||||
SendActivity,
|
|
||||||
};
|
};
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
|
@ -22,10 +21,7 @@ use activitypub_federation::{
|
||||||
protocol::verification::{verify_domains_match, verify_urls_match},
|
protocol::verification::{verify_domains_match, verify_urls_match},
|
||||||
traits::{ActivityHandler, Actor, Object},
|
traits::{ActivityHandler, Actor, Object},
|
||||||
};
|
};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::context::LemmyContext;
|
||||||
context::LemmyContext,
|
|
||||||
post::{EditPost, PostResponse},
|
|
||||||
};
|
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
aggregates::structs::PostAggregates,
|
aggregates::structs::PostAggregates,
|
||||||
newtypes::PersonId,
|
newtypes::PersonId,
|
||||||
|
@ -39,25 +35,6 @@ use lemmy_db_schema::{
|
||||||
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl SendActivity for EditPost {
|
|
||||||
type Response = PostResponse;
|
|
||||||
|
|
||||||
async fn send_activity(
|
|
||||||
_request: &Self,
|
|
||||||
response: &Self::Response,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
CreateOrUpdatePage::send(
|
|
||||||
response.post_view.post.clone(),
|
|
||||||
response.post_view.creator.id,
|
|
||||||
CreateOrUpdateType::Update,
|
|
||||||
context.reset_request_count(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CreateOrUpdatePage {
|
impl CreateOrUpdatePage {
|
||||||
pub(crate) async fn new(
|
pub(crate) async fn new(
|
||||||
post: ApubPost,
|
post: ApubPost,
|
||||||
|
|
|
@ -29,7 +29,6 @@ use activitypub_federation::{
|
||||||
traits::{Actor, Object},
|
traits::{Actor, Object},
|
||||||
};
|
};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
comment::{CommentResponse, DeleteComment, RemoveComment},
|
|
||||||
community::{CommunityResponse, DeleteCommunity, RemoveCommunity},
|
community::{CommunityResponse, DeleteCommunity, RemoveCommunity},
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
post::{DeletePost, PostResponse, RemovePost},
|
post::{DeletePost, PostResponse, RemovePost},
|
||||||
|
@ -102,50 +101,6 @@ impl SendActivity for RemovePost {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl SendActivity for DeleteComment {
|
|
||||||
type Response = CommentResponse;
|
|
||||||
|
|
||||||
async fn send_activity(
|
|
||||||
request: &Self,
|
|
||||||
response: &Self::Response,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let community_id = response.comment_view.community.id;
|
|
||||||
let community = Community::read(&mut context.pool(), community_id).await?;
|
|
||||||
let person = Person::read(&mut context.pool(), response.comment_view.creator.id).await?;
|
|
||||||
let deletable = DeletableObjects::Comment(response.comment_view.comment.clone().into());
|
|
||||||
send_apub_delete_in_community(person, community, deletable, None, request.deleted, context)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl SendActivity for RemoveComment {
|
|
||||||
type Response = CommentResponse;
|
|
||||||
|
|
||||||
async fn send_activity(
|
|
||||||
request: &Self,
|
|
||||||
response: &Self::Response,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let local_user_view = local_user_view_from_jwt(&request.auth, context).await?;
|
|
||||||
let comment = Comment::read(&mut context.pool(), request.comment_id).await?;
|
|
||||||
let community =
|
|
||||||
Community::read(&mut context.pool(), response.comment_view.community.id).await?;
|
|
||||||
let deletable = DeletableObjects::Comment(comment.into());
|
|
||||||
send_apub_delete_in_community(
|
|
||||||
local_user_view.person,
|
|
||||||
community,
|
|
||||||
deletable,
|
|
||||||
request.reason.clone().or_else(|| Some(String::new())),
|
|
||||||
request.removed,
|
|
||||||
context,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl SendActivity for DeletePrivateMessage {
|
impl SendActivity for DeletePrivateMessage {
|
||||||
type Response = PrivateMessageResponse;
|
type Response = PrivateMessageResponse;
|
||||||
|
@ -217,7 +172,7 @@ impl SendActivity for RemoveCommunity {
|
||||||
/// Parameter `reason` being set indicates that this is a removal by a mod. If its unset, this
|
/// Parameter `reason` being set indicates that this is a removal by a mod. If its unset, this
|
||||||
/// action was done by a normal user.
|
/// action was done by a normal user.
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn send_apub_delete_in_community(
|
pub(crate) async fn send_apub_delete_in_community(
|
||||||
actor: Person,
|
actor: Person,
|
||||||
community: Community,
|
community: Community,
|
||||||
object: DeletableObjects,
|
object: DeletableObjects,
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
activities::{
|
||||||
|
deletion::{send_apub_delete_in_community, DeletableObjects},
|
||||||
|
voting::send_like_activity,
|
||||||
|
},
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
protocol::activities::{
|
protocol::activities::{
|
||||||
create_or_update::{note::CreateOrUpdateNote, page::CreateOrUpdatePage},
|
create_or_update::{note::CreateOrUpdateNote, page::CreateOrUpdatePage},
|
||||||
|
@ -222,15 +226,30 @@ pub async fn match_outgoing_activities(
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
let context = context.reset_request_count();
|
let context = context.reset_request_count();
|
||||||
let fed_task = async {
|
let fed_task = async {
|
||||||
|
use SendActivityData::*;
|
||||||
match data {
|
match data {
|
||||||
SendActivityData::CreatePost(post) => {
|
CreatePost(post) | UpdatePost(post) => {
|
||||||
let creator_id = post.creator_id;
|
let creator_id = post.creator_id;
|
||||||
CreateOrUpdatePage::send(post, creator_id, CreateOrUpdateType::Create, context).await
|
CreateOrUpdatePage::send(post, creator_id, CreateOrUpdateType::Create, context).await
|
||||||
}
|
}
|
||||||
SendActivityData::CreateComment(comment) => {
|
CreateComment(comment) | UpdateComment(comment) => {
|
||||||
let creator_id = comment.creator_id;
|
let creator_id = comment.creator_id;
|
||||||
CreateOrUpdateNote::send(comment, creator_id, CreateOrUpdateType::Create, context).await
|
CreateOrUpdateNote::send(comment, creator_id, CreateOrUpdateType::Create, context).await
|
||||||
}
|
}
|
||||||
|
DeleteComment(comment, actor, community) => {
|
||||||
|
let is_deleted = comment.deleted;
|
||||||
|
let deletable = DeletableObjects::Comment(comment.into());
|
||||||
|
send_apub_delete_in_community(actor, community, deletable, None, is_deleted, &context).await
|
||||||
|
}
|
||||||
|
RemoveComment(comment, actor, community, reason) => {
|
||||||
|
let is_removed = comment.removed;
|
||||||
|
let deletable = DeletableObjects::Comment(comment.into());
|
||||||
|
send_apub_delete_in_community(actor, community, deletable, reason, is_removed, &context)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
LikePostOrComment(object_id, person, community, score) => {
|
||||||
|
send_like_activity(object_id, person, community, score, context).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if *SYNCHRONOUS_FEDERATION {
|
if *SYNCHRONOUS_FEDERATION {
|
||||||
|
|
|
@ -2,106 +2,51 @@ use crate::{
|
||||||
activities::community::send_activity_in_community,
|
activities::community::send_activity_in_community,
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
fetcher::post_or_comment::PostOrComment,
|
fetcher::post_or_comment::PostOrComment,
|
||||||
objects::{comment::ApubComment, person::ApubPerson, post::ApubPost},
|
objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
|
||||||
protocol::activities::voting::{
|
protocol::activities::voting::{
|
||||||
undo_vote::UndoVote,
|
undo_vote::UndoVote,
|
||||||
vote::{Vote, VoteType},
|
vote::{Vote, VoteType},
|
||||||
},
|
},
|
||||||
SendActivity,
|
|
||||||
};
|
};
|
||||||
use activitypub_federation::{config::Data, fetch::object_id::ObjectId};
|
use activitypub_federation::{config::Data, fetch::object_id::ObjectId};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::context::LemmyContext;
|
||||||
comment::{CommentResponse, CreateCommentLike},
|
|
||||||
context::LemmyContext,
|
|
||||||
post::{CreatePostLike, PostResponse},
|
|
||||||
sensitive::Sensitive,
|
|
||||||
utils::local_user_view_from_jwt,
|
|
||||||
};
|
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::CommunityId,
|
newtypes::DbUrl,
|
||||||
source::{
|
source::{
|
||||||
comment::{CommentLike, CommentLikeForm},
|
comment::{CommentLike, CommentLikeForm},
|
||||||
community::Community,
|
community::Community,
|
||||||
person::Person,
|
person::Person,
|
||||||
post::{PostLike, PostLikeForm},
|
post::{PostLike, PostLikeForm},
|
||||||
},
|
},
|
||||||
traits::{Crud, Likeable},
|
traits::Likeable,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
|
|
||||||
pub mod undo_vote;
|
pub mod undo_vote;
|
||||||
pub mod vote;
|
pub mod vote;
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
pub(crate) async fn send_like_activity(
|
||||||
impl SendActivity for CreatePostLike {
|
object_id: DbUrl,
|
||||||
type Response = PostResponse;
|
actor: Person,
|
||||||
|
community: Community,
|
||||||
async fn send_activity(
|
|
||||||
request: &Self,
|
|
||||||
response: &Self::Response,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let object_id = ObjectId::from(response.post_view.post.ap_id.clone());
|
|
||||||
let community_id = response.post_view.community.id;
|
|
||||||
send_activity(
|
|
||||||
object_id,
|
|
||||||
community_id,
|
|
||||||
request.score,
|
|
||||||
&request.auth,
|
|
||||||
context,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl SendActivity for CreateCommentLike {
|
|
||||||
type Response = CommentResponse;
|
|
||||||
|
|
||||||
async fn send_activity(
|
|
||||||
request: &Self,
|
|
||||||
response: &Self::Response,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let object_id = ObjectId::from(response.comment_view.comment.ap_id.clone());
|
|
||||||
let community_id = response.comment_view.community.id;
|
|
||||||
send_activity(
|
|
||||||
object_id,
|
|
||||||
community_id,
|
|
||||||
request.score,
|
|
||||||
&request.auth,
|
|
||||||
context,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_activity(
|
|
||||||
object_id: ObjectId<PostOrComment>,
|
|
||||||
community_id: CommunityId,
|
|
||||||
score: i16,
|
score: i16,
|
||||||
jwt: &Sensitive<String>,
|
context: Data<LemmyContext>,
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let community = Community::read(&mut context.pool(), community_id)
|
let object_id: ObjectId<PostOrComment> = object_id.try_into()?;
|
||||||
.await?
|
let actor: ApubPerson = actor.into();
|
||||||
.into();
|
let community: ApubCommunity = community.into();
|
||||||
let local_user_view = local_user_view_from_jwt(jwt, context).await?;
|
|
||||||
let actor = Person::read(&mut context.pool(), local_user_view.person.id)
|
|
||||||
.await?
|
|
||||||
.into();
|
|
||||||
|
|
||||||
// score of 1 means upvote, -1 downvote, 0 undo a previous vote
|
// score of 1 means upvote, -1 downvote, 0 undo a previous vote
|
||||||
if score != 0 {
|
if score != 0 {
|
||||||
let vote = Vote::new(object_id, &actor, &community, score.try_into()?, context)?;
|
let vote = Vote::new(object_id, &actor, &community, score.try_into()?, &context)?;
|
||||||
let activity = AnnouncableActivities::Vote(vote);
|
let activity = AnnouncableActivities::Vote(vote);
|
||||||
send_activity_in_community(activity, &actor, &community, vec![], false, context).await
|
send_activity_in_community(activity, &actor, &community, vec![], false, &context).await
|
||||||
} else {
|
} else {
|
||||||
// Lemmy API doesnt distinguish between Undo/Like and Undo/Dislike, so we hardcode it here.
|
// Lemmy API doesnt distinguish between Undo/Like and Undo/Dislike, so we hardcode it here.
|
||||||
let vote = Vote::new(object_id, &actor, &community, VoteType::Like, context)?;
|
let vote = Vote::new(object_id, &actor, &community, VoteType::Like, &context)?;
|
||||||
let undo_vote = UndoVote::new(vote, &actor, &community, context)?;
|
let undo_vote = UndoVote::new(vote, &actor, &community, &context)?;
|
||||||
let activity = AnnouncableActivities::UndoVote(undo_vote);
|
let activity = AnnouncableActivities::UndoVote(undo_vote);
|
||||||
send_activity_in_community(activity, &actor, &community, vec![], false, context).await
|
send_activity_in_community(activity, &actor, &community, vec![], false, &context).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use actix_web::{guard, web, Error, HttpResponse, Result};
|
use actix_web::{guard, web, Error, HttpResponse, Result};
|
||||||
use lemmy_api::{
|
use lemmy_api::{
|
||||||
comment::{distinguish::distinguish_comment, save::save_comment},
|
comment::{distinguish::distinguish_comment, like::like_comment, save::save_comment},
|
||||||
comment_report::{list::list_comment_reports, resolve::resolve_comment_report},
|
comment_report::{list::list_comment_reports, resolve::resolve_comment_report},
|
||||||
local_user::notifications::mark_reply_read::mark_reply_as_read,
|
local_user::notifications::mark_reply_read::mark_reply_as_read,
|
||||||
|
post::like::like_post,
|
||||||
Perform,
|
Perform,
|
||||||
};
|
};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
comment::{CreateCommentLike, CreateCommentReport, DeleteComment, EditComment, RemoveComment},
|
comment::CreateCommentReport,
|
||||||
community::{
|
community::{
|
||||||
AddModToCommunity,
|
AddModToCommunity,
|
||||||
BanFromCommunity,
|
BanFromCommunity,
|
||||||
|
@ -43,10 +44,8 @@ use lemmy_api_common::{
|
||||||
VerifyEmail,
|
VerifyEmail,
|
||||||
},
|
},
|
||||||
post::{
|
post::{
|
||||||
CreatePostLike,
|
|
||||||
CreatePostReport,
|
CreatePostReport,
|
||||||
DeletePost,
|
DeletePost,
|
||||||
EditPost,
|
|
||||||
FeaturePost,
|
FeaturePost,
|
||||||
GetSiteMetadata,
|
GetSiteMetadata,
|
||||||
ListPostReports,
|
ListPostReports,
|
||||||
|
@ -79,9 +78,15 @@ use lemmy_api_common::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lemmy_api_crud::{
|
use lemmy_api_crud::{
|
||||||
comment::{create::create_comment, read::get_comment},
|
comment::{
|
||||||
|
create::create_comment,
|
||||||
|
delete::delete_comment,
|
||||||
|
read::get_comment,
|
||||||
|
remove::remove_comment,
|
||||||
|
update::update_comment,
|
||||||
|
},
|
||||||
community::list::list_communities,
|
community::list::list_communities,
|
||||||
post::{create::create_post, read::get_post},
|
post::{create::create_post, read::get_post, update::update_post},
|
||||||
private_message::read::get_private_message,
|
private_message::read::get_private_message,
|
||||||
site::{create::create_site, read::get_site, update::update_site},
|
site::{create::create_site, read::get_site, update::update_site},
|
||||||
PerformCrud,
|
PerformCrud,
|
||||||
|
@ -173,7 +178,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
|
||||||
web::scope("/post")
|
web::scope("/post")
|
||||||
.wrap(rate_limit.message())
|
.wrap(rate_limit.message())
|
||||||
.route("", web::get().to(get_post))
|
.route("", web::get().to(get_post))
|
||||||
.route("", web::put().to(route_post_crud::<EditPost>))
|
.route("", web::put().to(update_post))
|
||||||
.route("/delete", web::post().to(route_post_crud::<DeletePost>))
|
.route("/delete", web::post().to(route_post_crud::<DeletePost>))
|
||||||
.route("/remove", web::post().to(route_post_crud::<RemovePost>))
|
.route("/remove", web::post().to(route_post_crud::<RemovePost>))
|
||||||
.route(
|
.route(
|
||||||
|
@ -183,7 +188,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
|
||||||
.route("/lock", web::post().to(route_post::<LockPost>))
|
.route("/lock", web::post().to(route_post::<LockPost>))
|
||||||
.route("/feature", web::post().to(route_post::<FeaturePost>))
|
.route("/feature", web::post().to(route_post::<FeaturePost>))
|
||||||
.route("/list", web::get().to(list_posts))
|
.route("/list", web::get().to(list_posts))
|
||||||
.route("/like", web::post().to(route_post::<CreatePostLike>))
|
.route("/like", web::post().to(like_post))
|
||||||
.route("/save", web::put().to(route_post::<SavePost>))
|
.route("/save", web::put().to(route_post::<SavePost>))
|
||||||
.route("/report", web::post().to(route_post::<CreatePostReport>))
|
.route("/report", web::post().to(route_post::<CreatePostReport>))
|
||||||
.route(
|
.route(
|
||||||
|
@ -208,12 +213,12 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
|
||||||
web::scope("/comment")
|
web::scope("/comment")
|
||||||
.wrap(rate_limit.message())
|
.wrap(rate_limit.message())
|
||||||
.route("", web::get().to(get_comment))
|
.route("", web::get().to(get_comment))
|
||||||
.route("", web::put().to(route_post_crud::<EditComment>))
|
.route("", web::put().to(update_comment))
|
||||||
.route("/delete", web::post().to(route_post_crud::<DeleteComment>))
|
.route("/delete", web::post().to(delete_comment))
|
||||||
.route("/remove", web::post().to(route_post_crud::<RemoveComment>))
|
.route("/remove", web::post().to(remove_comment))
|
||||||
.route("/mark_as_read", web::post().to(mark_reply_as_read))
|
.route("/mark_as_read", web::post().to(mark_reply_as_read))
|
||||||
.route("/distinguish", web::post().to(distinguish_comment))
|
.route("/distinguish", web::post().to(distinguish_comment))
|
||||||
.route("/like", web::post().to(route_post::<CreateCommentLike>))
|
.route("/like", web::post().to(like_comment))
|
||||||
.route("/save", web::put().to(save_comment))
|
.route("/save", web::put().to(save_comment))
|
||||||
.route("/list", web::get().to(list_comments))
|
.route("/list", web::get().to(list_comments))
|
||||||
.route("/report", web::post().to(route_post::<CreateCommentReport>))
|
.route("/report", web::post().to(route_post::<CreateCommentReport>))
|
||||||
|
|
Loading…
Reference in a new issue