mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-26 14:21:19 +00:00
A first pass at user / community blocking. #426
This commit is contained in:
parent
6af75492a9
commit
9e8a4807ec
31 changed files with 661 additions and 10 deletions
|
@ -4,6 +4,7 @@ use lemmy_api_common::{
|
|||
blocking,
|
||||
check_community_ban,
|
||||
check_downvotes_enabled,
|
||||
check_person_block,
|
||||
comment::*,
|
||||
get_local_user_view_from_jwt,
|
||||
};
|
||||
|
@ -151,6 +152,13 @@ impl Perform for CreateCommentLike {
|
|||
)
|
||||
.await?;
|
||||
|
||||
check_person_block(
|
||||
local_user_view.person.id,
|
||||
orig_comment.get_recipient_id(),
|
||||
context.pool(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Add parent user to recipients
|
||||
let recipient_id = orig_comment.get_recipient_id();
|
||||
if let Ok(local_recipient) = blocking(context.pool(), move |conn| {
|
||||
|
|
|
@ -18,6 +18,7 @@ use lemmy_apub::{
|
|||
use lemmy_db_queries::{
|
||||
source::{comment::Comment_, community::CommunityModerator_, post::Post_},
|
||||
Bannable,
|
||||
Blockable,
|
||||
Crud,
|
||||
Followable,
|
||||
Joinable,
|
||||
|
@ -25,6 +26,7 @@ use lemmy_db_queries::{
|
|||
use lemmy_db_schema::source::{
|
||||
comment::Comment,
|
||||
community::*,
|
||||
community_block::{CommunityBlock, CommunityBlockForm},
|
||||
moderator::*,
|
||||
person::Person,
|
||||
post::Post,
|
||||
|
@ -107,6 +109,48 @@ impl Perform for FollowCommunity {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl Perform for BlockCommunity {
|
||||
type Response = CommunityResponse;
|
||||
|
||||
async fn perform(
|
||||
&self,
|
||||
context: &Data<LemmyContext>,
|
||||
_websocket_id: Option<ConnectionId>,
|
||||
) -> Result<CommunityResponse, LemmyError> {
|
||||
let data: &BlockCommunity = &self;
|
||||
let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
|
||||
|
||||
let community_id = data.community_id;
|
||||
let person_id = local_user_view.person.id;
|
||||
let community_block_form = CommunityBlockForm {
|
||||
person_id,
|
||||
community_id,
|
||||
};
|
||||
|
||||
if data.block {
|
||||
let block = move |conn: &'_ _| CommunityBlock::block(conn, &community_block_form);
|
||||
if blocking(context.pool(), block).await?.is_err() {
|
||||
return Err(ApiError::err("community_block_already_exists").into());
|
||||
}
|
||||
} else {
|
||||
let unblock = move |conn: &'_ _| CommunityBlock::unblock(conn, &community_block_form);
|
||||
if blocking(context.pool(), unblock).await?.is_err() {
|
||||
return Err(ApiError::err("community_block_already_exists").into());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO does any federated stuff need to be done here?
|
||||
|
||||
let community_view = blocking(context.pool(), move |conn| {
|
||||
CommunityView::read(conn, community_id, Some(person_id))
|
||||
})
|
||||
.await??;
|
||||
|
||||
Ok(CommunityResponse { community_view })
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl Perform for BanFromCommunity {
|
||||
type Response = BanFromCommunityResponse;
|
||||
|
|
|
@ -39,9 +39,15 @@ pub async fn match_websocket_operation(
|
|||
UserOperation::GetReplies => do_websocket_operation::<GetReplies>(context, id, op, data).await,
|
||||
UserOperation::AddAdmin => do_websocket_operation::<AddAdmin>(context, id, op, data).await,
|
||||
UserOperation::BanPerson => do_websocket_operation::<BanPerson>(context, id, op, data).await,
|
||||
UserOperation::BlockPerson => {
|
||||
do_websocket_operation::<BlockPerson>(context, id, op, data).await
|
||||
}
|
||||
UserOperation::GetPersonMentions => {
|
||||
do_websocket_operation::<GetPersonMentions>(context, id, op, data).await
|
||||
}
|
||||
UserOperation::GetBlockedPersons => {
|
||||
do_websocket_operation::<GetBlockedPersons>(context, id, op, data).await
|
||||
}
|
||||
UserOperation::MarkPersonMentionAsRead => {
|
||||
do_websocket_operation::<MarkPersonMentionAsRead>(context, id, op, data).await
|
||||
}
|
||||
|
@ -95,9 +101,15 @@ pub async fn match_websocket_operation(
|
|||
UserOperation::FollowCommunity => {
|
||||
do_websocket_operation::<FollowCommunity>(context, id, op, data).await
|
||||
}
|
||||
UserOperation::BlockCommunity => {
|
||||
do_websocket_operation::<BlockCommunity>(context, id, op, data).await
|
||||
}
|
||||
UserOperation::GetFollowedCommunities => {
|
||||
do_websocket_operation::<GetFollowedCommunities>(context, id, op, data).await
|
||||
}
|
||||
UserOperation::GetBlockedCommunities => {
|
||||
do_websocket_operation::<GetBlockedCommunities>(context, id, op, data).await
|
||||
}
|
||||
UserOperation::BanFromCommunity => {
|
||||
do_websocket_operation::<BanFromCommunity>(context, id, op, data).await
|
||||
}
|
||||
|
|
|
@ -7,7 +7,12 @@ use chrono::Duration;
|
|||
use lemmy_api_common::{
|
||||
blocking,
|
||||
collect_moderated_communities,
|
||||
community::{GetFollowedCommunities, GetFollowedCommunitiesResponse},
|
||||
community::{
|
||||
GetBlockedCommunities,
|
||||
GetBlockedCommunitiesResponse,
|
||||
GetFollowedCommunities,
|
||||
GetFollowedCommunitiesResponse,
|
||||
},
|
||||
get_local_user_view_from_jwt,
|
||||
is_admin,
|
||||
password_length_check,
|
||||
|
@ -27,6 +32,7 @@ use lemmy_db_queries::{
|
|||
post::Post_,
|
||||
private_message::PrivateMessage_,
|
||||
},
|
||||
Blockable,
|
||||
Crud,
|
||||
SortType,
|
||||
};
|
||||
|
@ -39,6 +45,7 @@ use lemmy_db_schema::{
|
|||
moderator::*,
|
||||
password_reset_request::*,
|
||||
person::*,
|
||||
person_block::{PersonBlock, PersonBlockForm},
|
||||
person_mention::*,
|
||||
post::Post,
|
||||
private_message::PrivateMessage,
|
||||
|
@ -52,8 +59,10 @@ use lemmy_db_views::{
|
|||
post_report_view::PostReportView,
|
||||
};
|
||||
use lemmy_db_views_actor::{
|
||||
community_block_view::CommunityBlockView,
|
||||
community_follower_view::CommunityFollowerView,
|
||||
community_moderator_view::CommunityModeratorView,
|
||||
person_block_view::PersonBlockView,
|
||||
person_mention_view::{PersonMentionQueryBuilder, PersonMentionView},
|
||||
person_view::PersonViewSafe,
|
||||
};
|
||||
|
@ -471,6 +480,53 @@ impl Perform for BanPerson {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl Perform for BlockPerson {
|
||||
type Response = BlockPersonResponse;
|
||||
|
||||
async fn perform(
|
||||
&self,
|
||||
context: &Data<LemmyContext>,
|
||||
_websocket_id: Option<ConnectionId>,
|
||||
) -> Result<BlockPersonResponse, LemmyError> {
|
||||
let data: &BlockPerson = &self;
|
||||
let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
|
||||
|
||||
let recipient_id = data.person_id;
|
||||
let person_id = local_user_view.person.id;
|
||||
let community_block_form = PersonBlockForm {
|
||||
person_id,
|
||||
recipient_id,
|
||||
};
|
||||
|
||||
if data.block {
|
||||
let block = move |conn: &'_ _| PersonBlock::block(conn, &community_block_form);
|
||||
if blocking(context.pool(), block).await?.is_err() {
|
||||
return Err(ApiError::err("person_block_already_exists").into());
|
||||
}
|
||||
} else {
|
||||
let unblock = move |conn: &'_ _| PersonBlock::unblock(conn, &community_block_form);
|
||||
if blocking(context.pool(), unblock).await?.is_err() {
|
||||
return Err(ApiError::err("person_block_already_exists").into());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO does any federated stuff need to be done here?
|
||||
|
||||
let person_view = blocking(context.pool(), move |conn| {
|
||||
PersonViewSafe::read(conn, recipient_id)
|
||||
})
|
||||
.await??;
|
||||
|
||||
let res = BlockPersonResponse {
|
||||
person_view,
|
||||
blocked: data.block,
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl Perform for GetReplies {
|
||||
type Response = GetRepliesResponse;
|
||||
|
@ -802,3 +858,51 @@ impl Perform for GetFollowedCommunities {
|
|||
Ok(GetFollowedCommunitiesResponse { communities })
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl Perform for GetBlockedCommunities {
|
||||
type Response = GetBlockedCommunitiesResponse;
|
||||
|
||||
async fn perform(
|
||||
&self,
|
||||
context: &Data<LemmyContext>,
|
||||
_websocket_id: Option<ConnectionId>,
|
||||
) -> Result<GetBlockedCommunitiesResponse, LemmyError> {
|
||||
let data: &GetBlockedCommunities = &self;
|
||||
let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
|
||||
|
||||
let person_id = local_user_view.person.id;
|
||||
let communities = blocking(context.pool(), move |conn| {
|
||||
CommunityBlockView::for_person(conn, person_id)
|
||||
})
|
||||
.await?
|
||||
.map_err(|_| ApiError::err("system_err_login"))?;
|
||||
|
||||
// Return the jwt
|
||||
Ok(GetBlockedCommunitiesResponse { communities })
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl Perform for GetBlockedPersons {
|
||||
type Response = GetBlockedPersonsResponse;
|
||||
|
||||
async fn perform(
|
||||
&self,
|
||||
context: &Data<LemmyContext>,
|
||||
_websocket_id: Option<ConnectionId>,
|
||||
) -> Result<GetBlockedPersonsResponse, LemmyError> {
|
||||
let data: &GetBlockedPersons = &self;
|
||||
let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
|
||||
|
||||
let person_id = local_user_view.person.id;
|
||||
let persons = blocking(context.pool(), move |conn| {
|
||||
PersonBlockView::for_person(conn, person_id)
|
||||
})
|
||||
.await?
|
||||
.map_err(|_| ApiError::err("system_err_login"))?;
|
||||
|
||||
// Return the jwt
|
||||
Ok(GetBlockedPersonsResponse { persons })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use lemmy_api_common::{
|
|||
blocking,
|
||||
check_community_ban,
|
||||
check_downvotes_enabled,
|
||||
check_person_block,
|
||||
get_local_user_view_from_jwt,
|
||||
is_mod_or_admin,
|
||||
mark_post_as_read,
|
||||
|
@ -48,6 +49,8 @@ impl Perform for CreatePostLike {
|
|||
|
||||
check_community_ban(local_user_view.person.id, post.community_id, context.pool()).await?;
|
||||
|
||||
check_person_block(local_user_view.person.id, post.creator_id, context.pool()).await?;
|
||||
|
||||
let like_form = PostLikeForm {
|
||||
post_id: data.post_id,
|
||||
person_id: local_user_view.person.id,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use lemmy_db_schema::{CommunityId, PersonId};
|
||||
use lemmy_db_views_actor::{
|
||||
community_block_view::CommunityBlockView,
|
||||
community_follower_view::CommunityFollowerView,
|
||||
community_moderator_view::CommunityModeratorView,
|
||||
community_view::CommunityView,
|
||||
|
@ -116,6 +117,13 @@ pub struct FollowCommunity {
|
|||
pub auth: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct BlockCommunity {
|
||||
pub community_id: CommunityId,
|
||||
pub block: bool,
|
||||
pub auth: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct GetFollowedCommunities {
|
||||
pub auth: String,
|
||||
|
@ -126,6 +134,16 @@ pub struct GetFollowedCommunitiesResponse {
|
|||
pub communities: Vec<CommunityFollowerView>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct GetBlockedCommunities {
|
||||
pub auth: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct GetBlockedCommunitiesResponse {
|
||||
pub communities: Vec<CommunityBlockView>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct TransferCommunity {
|
||||
pub community_id: CommunityId,
|
||||
|
|
|
@ -10,6 +10,7 @@ use diesel::PgConnection;
|
|||
use lemmy_db_queries::{
|
||||
source::{
|
||||
community::{CommunityModerator_, Community_},
|
||||
person_block::PersonBlock_,
|
||||
site::Site_,
|
||||
},
|
||||
Crud,
|
||||
|
@ -21,6 +22,7 @@ use lemmy_db_schema::{
|
|||
comment::Comment,
|
||||
community::{Community, CommunityModerator},
|
||||
person::Person,
|
||||
person_block::PersonBlock,
|
||||
person_mention::{PersonMention, PersonMentionForm},
|
||||
post::{Post, PostRead, PostReadForm},
|
||||
site::Site,
|
||||
|
@ -353,6 +355,20 @@ pub async fn check_community_ban(
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn check_person_block(
|
||||
person_id: PersonId,
|
||||
recipient_id: PersonId,
|
||||
pool: &DbPool,
|
||||
) -> Result<(), LemmyError> {
|
||||
// TODO the person and recipient might be reversed
|
||||
let is_blocked = move |conn: &'_ _| PersonBlock::read(conn, person_id, recipient_id).is_ok();
|
||||
if blocking(pool, is_blocked).await? {
|
||||
Err(ApiError::err("person_block").into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn check_downvotes_enabled(score: i16, pool: &DbPool) -> Result<(), LemmyError> {
|
||||
if score == -1 {
|
||||
let site = blocking(pool, move |conn| Site::read_simple(conn)).await??;
|
||||
|
|
|
@ -4,8 +4,10 @@ use lemmy_db_views::{
|
|||
private_message_view::PrivateMessageView,
|
||||
};
|
||||
use lemmy_db_views_actor::{
|
||||
community_block_view::CommunityBlockView,
|
||||
community_follower_view::CommunityFollowerView,
|
||||
community_moderator_view::CommunityModeratorView,
|
||||
person_block_view::PersonBlockView,
|
||||
person_mention_view::PersonMentionView,
|
||||
person_view::PersonViewSafe,
|
||||
};
|
||||
|
@ -97,6 +99,8 @@ pub struct GetPersonDetails {
|
|||
pub struct GetPersonDetailsResponse {
|
||||
pub person_view: PersonViewSafe,
|
||||
pub follows: Vec<CommunityFollowerView>,
|
||||
pub community_blocks: Vec<CommunityBlockView>,
|
||||
pub person_blocks: Vec<PersonBlockView>,
|
||||
pub moderates: Vec<CommunityModeratorView>,
|
||||
pub comments: Vec<CommentView>,
|
||||
pub posts: Vec<PostView>,
|
||||
|
@ -145,6 +149,19 @@ pub struct BanPersonResponse {
|
|||
pub banned: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct BlockPerson {
|
||||
pub person_id: PersonId,
|
||||
pub block: bool,
|
||||
pub auth: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
pub struct BlockPersonResponse {
|
||||
pub person_view: PersonViewSafe,
|
||||
pub blocked: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct GetReplies {
|
||||
pub sort: Option<String>,
|
||||
|
@ -254,3 +271,13 @@ pub struct GetReportCountResponse {
|
|||
pub comment_reports: i64,
|
||||
pub post_reports: i64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct GetBlockedPersons {
|
||||
pub auth: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct GetBlockedPersonsResponse {
|
||||
pub persons: Vec<PersonBlockView>,
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use actix_web::web::Data;
|
|||
use lemmy_api_common::{
|
||||
blocking,
|
||||
check_community_ban,
|
||||
check_person_block,
|
||||
comment::*,
|
||||
get_local_user_view_from_jwt,
|
||||
get_post,
|
||||
|
@ -49,6 +50,8 @@ impl PerformCrud for CreateComment {
|
|||
|
||||
check_community_ban(local_user_view.person.id, community_id, context.pool()).await?;
|
||||
|
||||
check_person_block(local_user_view.person.id, post.creator_id, context.pool()).await?;
|
||||
|
||||
// Check if post is locked, no new comments
|
||||
if post.locked {
|
||||
return Err(ApiError::err("locked").into());
|
||||
|
@ -60,6 +63,10 @@ impl PerformCrud for CreateComment {
|
|||
let parent = blocking(context.pool(), move |conn| Comment::read(conn, parent_id))
|
||||
.await?
|
||||
.map_err(|_| ApiError::err("couldnt_create_comment"))?;
|
||||
|
||||
check_person_block(local_user_view.person.id, parent.creator_id, context.pool()).await?;
|
||||
|
||||
// Strange issue where sometimes the post ID is incorrect
|
||||
if parent.post_id != post_id {
|
||||
return Err(ApiError::err("couldnt_create_comment").into());
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ impl PerformCrud for EditComment {
|
|||
})
|
||||
.await??;
|
||||
|
||||
// TODO is this necessary? It should really only need to check on create
|
||||
check_community_ban(
|
||||
local_user_view.person.id,
|
||||
orig_comment.community.id,
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::PerformCrud;
|
|||
use actix_web::web::Data;
|
||||
use lemmy_api_common::{
|
||||
blocking,
|
||||
check_person_block,
|
||||
get_local_user_view_from_jwt,
|
||||
person::{CreatePrivateMessage, PrivateMessageResponse},
|
||||
send_email_to_user,
|
||||
|
@ -34,6 +35,8 @@ impl PerformCrud for CreatePrivateMessage {
|
|||
|
||||
let content_slurs_removed = remove_slurs(&data.content.to_owned());
|
||||
|
||||
check_person_block(local_user_view.person.id, data.recipient_id, context.pool()).await?;
|
||||
|
||||
let private_message_form = PrivateMessageForm {
|
||||
content: content_slurs_removed.to_owned(),
|
||||
creator_id: local_user_view.person.id,
|
||||
|
|
|
@ -6,8 +6,10 @@ use lemmy_db_queries::{from_opt_str_to_opt_enum, ApubObject, SortType};
|
|||
use lemmy_db_schema::source::person::*;
|
||||
use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder};
|
||||
use lemmy_db_views_actor::{
|
||||
community_block_view::CommunityBlockView,
|
||||
community_follower_view::CommunityFollowerView,
|
||||
community_moderator_view::CommunityModeratorView,
|
||||
person_block_view::PersonBlockView,
|
||||
person_view::PersonViewSafe,
|
||||
};
|
||||
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
||||
|
@ -104,14 +106,27 @@ impl PerformCrud for GetPersonDetails {
|
|||
.await??;
|
||||
|
||||
let mut follows = vec![];
|
||||
let mut person_blocks = vec![];
|
||||
let mut community_blocks = vec![];
|
||||
|
||||
// Only show the followers and blocks for that user
|
||||
if let Some(pid) = person_id {
|
||||
if pid == person_details_id {
|
||||
follows = blocking(context.pool(), move |conn| {
|
||||
CommunityFollowerView::for_person(conn, person_details_id)
|
||||
})
|
||||
.await??;
|
||||
person_blocks = blocking(context.pool(), move |conn| {
|
||||
PersonBlockView::for_person(conn, person_details_id)
|
||||
})
|
||||
.await??;
|
||||
community_blocks = blocking(context.pool(), move |conn| {
|
||||
CommunityBlockView::for_person(conn, person_details_id)
|
||||
})
|
||||
.await??;
|
||||
}
|
||||
};
|
||||
|
||||
let moderates = blocking(context.pool(), move |conn| {
|
||||
CommunityModeratorView::for_person(conn, person_details_id)
|
||||
})
|
||||
|
@ -121,6 +136,8 @@ impl PerformCrud for GetPersonDetails {
|
|||
Ok(GetPersonDetailsResponse {
|
||||
person_view,
|
||||
follows,
|
||||
community_blocks,
|
||||
person_blocks,
|
||||
moderates,
|
||||
comments,
|
||||
posts,
|
||||
|
|
|
@ -108,6 +108,16 @@ pub trait Saveable {
|
|||
Self: Sized;
|
||||
}
|
||||
|
||||
pub trait Blockable {
|
||||
type Form;
|
||||
fn block(conn: &PgConnection, form: &Self::Form) -> Result<Self, Error>
|
||||
where
|
||||
Self: Sized;
|
||||
fn unblock(conn: &PgConnection, form: &Self::Form) -> Result<usize, Error>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
pub trait Readable {
|
||||
type Form;
|
||||
fn mark_as_read(conn: &PgConnection, form: &Self::Form) -> Result<Self, Error>
|
||||
|
|
28
crates/db_queries/src/source/community_block.rs
Normal file
28
crates/db_queries/src/source/community_block.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use crate::Blockable;
|
||||
use diesel::{dsl::*, result::Error, *};
|
||||
use lemmy_db_schema::source::community_block::{CommunityBlock, CommunityBlockForm};
|
||||
|
||||
impl Blockable for CommunityBlock {
|
||||
type Form = CommunityBlockForm;
|
||||
fn block(conn: &PgConnection, community_block_form: &CommunityBlockForm) -> Result<Self, Error> {
|
||||
use lemmy_db_schema::schema::community_block::dsl::*;
|
||||
insert_into(community_block)
|
||||
.values(community_block_form)
|
||||
.on_conflict((person_id, community_id))
|
||||
.do_update()
|
||||
.set(community_block_form)
|
||||
.get_result::<Self>(conn)
|
||||
}
|
||||
fn unblock(
|
||||
conn: &PgConnection,
|
||||
community_block_form: &CommunityBlockForm,
|
||||
) -> Result<usize, Error> {
|
||||
use lemmy_db_schema::schema::community_block::dsl::*;
|
||||
diesel::delete(
|
||||
community_block
|
||||
.filter(person_id.eq(community_block_form.person_id))
|
||||
.filter(community_id.eq(community_block_form.community_id)),
|
||||
)
|
||||
.execute(conn)
|
||||
}
|
||||
}
|
|
@ -2,10 +2,12 @@ pub mod activity;
|
|||
pub mod comment;
|
||||
pub mod comment_report;
|
||||
pub mod community;
|
||||
pub mod community_block;
|
||||
pub mod local_user;
|
||||
pub mod moderator;
|
||||
pub mod password_reset_request;
|
||||
pub mod person;
|
||||
pub mod person_block;
|
||||
pub mod person_mention;
|
||||
pub mod post;
|
||||
pub mod post_report;
|
||||
|
|
50
crates/db_queries/src/source/person_block.rs
Normal file
50
crates/db_queries/src/source/person_block.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use crate::Blockable;
|
||||
use diesel::{dsl::*, result::Error, *};
|
||||
use lemmy_db_schema::{
|
||||
source::person_block::{PersonBlock, PersonBlockForm},
|
||||
PersonId,
|
||||
};
|
||||
|
||||
pub trait PersonBlock_ {
|
||||
fn read(
|
||||
conn: &PgConnection,
|
||||
person_id: PersonId,
|
||||
recipient_id: PersonId,
|
||||
) -> Result<PersonBlock, Error>;
|
||||
}
|
||||
|
||||
impl PersonBlock_ for PersonBlock {
|
||||
fn read(
|
||||
conn: &PgConnection,
|
||||
for_person_id: PersonId,
|
||||
for_recipient_id: PersonId,
|
||||
) -> Result<Self, Error> {
|
||||
use lemmy_db_schema::schema::person_block::dsl::*;
|
||||
person_block
|
||||
.filter(person_id.eq(for_person_id))
|
||||
.filter(recipient_id.eq(for_recipient_id))
|
||||
.first::<Self>(conn)
|
||||
}
|
||||
}
|
||||
|
||||
impl Blockable for PersonBlock {
|
||||
type Form = PersonBlockForm;
|
||||
fn block(conn: &PgConnection, person_block_form: &PersonBlockForm) -> Result<Self, Error> {
|
||||
use lemmy_db_schema::schema::person_block::dsl::*;
|
||||
insert_into(person_block)
|
||||
.values(person_block_form)
|
||||
.on_conflict((person_id, recipient_id))
|
||||
.do_update()
|
||||
.set(person_block_form)
|
||||
.get_result::<Self>(conn)
|
||||
}
|
||||
fn unblock(conn: &PgConnection, person_block_form: &PersonBlockForm) -> Result<usize, Error> {
|
||||
use lemmy_db_schema::schema::person_block::dsl::*;
|
||||
diesel::delete(
|
||||
person_block
|
||||
.filter(person_id.eq(person_block_form.person_id))
|
||||
.filter(recipient_id.eq(person_block_form.recipient_id)),
|
||||
)
|
||||
.execute(conn)
|
||||
}
|
||||
}
|
|
@ -67,6 +67,12 @@ impl fmt::Display for PrivateMessageId {
|
|||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, DieselNewType)]
|
||||
pub struct PersonMentionId(i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, DieselNewType)]
|
||||
pub struct PersonBlockId(i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, DieselNewType)]
|
||||
pub struct CommunityBlockId(i32);
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug, AsExpression, FromSqlRow)]
|
||||
#[sql_type = "Text"]
|
||||
|
|
|
@ -465,6 +465,24 @@ table! {
|
|||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
person_block (id) {
|
||||
id -> Int4,
|
||||
person_id -> Int4,
|
||||
recipient_id -> Int4,
|
||||
published -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
community_block (id) {
|
||||
id -> Int4,
|
||||
person_id -> Int4,
|
||||
community_id -> Int4,
|
||||
published -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
// These are necessary since diesel doesn't have self joins / aliases
|
||||
table! {
|
||||
comment_alias_1 (id) {
|
||||
|
@ -542,6 +560,9 @@ joinable!(comment -> person_alias_1 (creator_id));
|
|||
joinable!(post_report -> person_alias_2 (resolver_id));
|
||||
joinable!(comment_report -> person_alias_2 (resolver_id));
|
||||
|
||||
joinable!(person_block -> person (person_id));
|
||||
joinable!(person_block -> person_alias_1 (recipient_id));
|
||||
|
||||
joinable!(comment -> person (creator_id));
|
||||
joinable!(comment -> post (post_id));
|
||||
joinable!(comment_aggregates -> comment (comment_id));
|
||||
|
@ -552,6 +573,8 @@ joinable!(comment_report -> comment (comment_id));
|
|||
joinable!(comment_saved -> comment (comment_id));
|
||||
joinable!(comment_saved -> person (person_id));
|
||||
joinable!(community_aggregates -> community (community_id));
|
||||
joinable!(community_block -> community (community_id));
|
||||
joinable!(community_block -> person (person_id));
|
||||
joinable!(community_follower -> community (community_id));
|
||||
joinable!(community_follower -> person (person_id));
|
||||
joinable!(community_moderator -> community (community_id));
|
||||
|
@ -594,6 +617,7 @@ allow_tables_to_appear_in_same_query!(
|
|||
activity,
|
||||
comment,
|
||||
comment_aggregates,
|
||||
community_block,
|
||||
comment_like,
|
||||
comment_report,
|
||||
comment_saved,
|
||||
|
@ -617,6 +641,7 @@ allow_tables_to_appear_in_same_query!(
|
|||
person,
|
||||
person_aggregates,
|
||||
person_ban,
|
||||
person_block,
|
||||
person_mention,
|
||||
post,
|
||||
post_aggregates,
|
||||
|
|
25
crates/db_schema/src/source/community_block.rs
Normal file
25
crates/db_schema/src/source/community_block.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use crate::{
|
||||
schema::community_block,
|
||||
source::community::Community,
|
||||
CommunityBlockId,
|
||||
CommunityId,
|
||||
PersonId,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize)]
|
||||
#[table_name = "community_block"]
|
||||
#[belongs_to(Community)]
|
||||
pub struct CommunityBlock {
|
||||
pub id: CommunityBlockId,
|
||||
pub person_id: PersonId,
|
||||
pub community_id: CommunityId,
|
||||
pub published: chrono::NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(Insertable, AsChangeset)]
|
||||
#[table_name = "community_block"]
|
||||
pub struct CommunityBlockForm {
|
||||
pub person_id: PersonId,
|
||||
pub community_id: CommunityId,
|
||||
}
|
|
@ -2,10 +2,12 @@ pub mod activity;
|
|||
pub mod comment;
|
||||
pub mod comment_report;
|
||||
pub mod community;
|
||||
pub mod community_block;
|
||||
pub mod local_user;
|
||||
pub mod moderator;
|
||||
pub mod password_reset_request;
|
||||
pub mod person;
|
||||
pub mod person_block;
|
||||
pub mod person_mention;
|
||||
pub mod post;
|
||||
pub mod post_report;
|
||||
|
|
18
crates/db_schema/src/source/person_block.rs
Normal file
18
crates/db_schema/src/source/person_block.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use crate::{schema::person_block, PersonBlockId, PersonId};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize)]
|
||||
#[table_name = "person_block"]
|
||||
pub struct PersonBlock {
|
||||
pub id: PersonBlockId,
|
||||
pub person_id: PersonId,
|
||||
pub recipient_id: PersonId,
|
||||
pub published: chrono::NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(Insertable, AsChangeset)]
|
||||
#[table_name = "person_block"]
|
||||
pub struct PersonBlockForm {
|
||||
pub person_id: PersonId,
|
||||
pub recipient_id: PersonId,
|
||||
}
|
|
@ -18,16 +18,19 @@ use lemmy_db_schema::{
|
|||
comment_like,
|
||||
comment_saved,
|
||||
community,
|
||||
community_block,
|
||||
community_follower,
|
||||
community_person_ban,
|
||||
person,
|
||||
person_alias_1,
|
||||
person_block,
|
||||
post,
|
||||
},
|
||||
source::{
|
||||
comment::{Comment, CommentAlias1, CommentSaved},
|
||||
community::{Community, CommunityFollower, CommunityPersonBan, CommunitySafe},
|
||||
person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
|
||||
person_block::PersonBlock,
|
||||
post::Post,
|
||||
},
|
||||
CommentId,
|
||||
|
@ -49,6 +52,7 @@ pub struct CommentView {
|
|||
pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan
|
||||
pub subscribed: bool, // Left join to CommunityFollower
|
||||
pub saved: bool, // Left join to CommentSaved
|
||||
pub creator_blocked: bool, // Left join to PersonBlock
|
||||
pub my_vote: Option<i16>, // Left join to CommentLike
|
||||
}
|
||||
|
||||
|
@ -63,6 +67,7 @@ type CommentViewTuple = (
|
|||
Option<CommunityPersonBan>,
|
||||
Option<CommunityFollower>,
|
||||
Option<CommentSaved>,
|
||||
Option<PersonBlock>,
|
||||
Option<i16>,
|
||||
);
|
||||
|
||||
|
@ -86,6 +91,7 @@ impl CommentView {
|
|||
creator_banned_from_community,
|
||||
subscribed,
|
||||
saved,
|
||||
creator_blocked,
|
||||
comment_like,
|
||||
) = comment::table
|
||||
.find(comment_id)
|
||||
|
@ -117,6 +123,13 @@ impl CommentView {
|
|||
.and(comment_saved::person_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
person_block::table.on(
|
||||
comment::creator_id
|
||||
.eq(person_block::person_id)
|
||||
.and(person_block::recipient_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
comment_like::table.on(
|
||||
comment::id
|
||||
|
@ -135,6 +148,7 @@ impl CommentView {
|
|||
community_person_ban::all_columns.nullable(),
|
||||
community_follower::all_columns.nullable(),
|
||||
comment_saved::all_columns.nullable(),
|
||||
person_block::all_columns.nullable(),
|
||||
comment_like::score.nullable(),
|
||||
))
|
||||
.first::<CommentViewTuple>(conn)?;
|
||||
|
@ -157,6 +171,7 @@ impl CommentView {
|
|||
creator_banned_from_community: creator_banned_from_community.is_some(),
|
||||
subscribed: subscribed.is_some(),
|
||||
saved: saved.is_some(),
|
||||
creator_blocked: creator_blocked.is_some(),
|
||||
my_vote,
|
||||
})
|
||||
}
|
||||
|
@ -315,6 +330,20 @@ impl<'a> CommentQueryBuilder<'a> {
|
|||
.and(comment_saved::person_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
person_block::table.on(
|
||||
comment::creator_id
|
||||
.eq(person_block::person_id)
|
||||
.and(person_block::recipient_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
community_block::table.on(
|
||||
community::id
|
||||
.eq(community_block::community_id)
|
||||
.and(community_block::person_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
comment_like::table.on(
|
||||
comment::id
|
||||
|
@ -333,6 +362,7 @@ impl<'a> CommentQueryBuilder<'a> {
|
|||
community_person_ban::all_columns.nullable(),
|
||||
community_follower::all_columns.nullable(),
|
||||
comment_saved::all_columns.nullable(),
|
||||
person_block::all_columns.nullable(),
|
||||
comment_like::score.nullable(),
|
||||
))
|
||||
.into_boxed();
|
||||
|
@ -413,6 +443,11 @@ impl<'a> CommentQueryBuilder<'a> {
|
|||
.order_by(comment_aggregates::score.desc()),
|
||||
};
|
||||
|
||||
// Don't show blocked communities
|
||||
if self.my_person_id.is_some() {
|
||||
query = query.filter(community_block::person_id.is_null());
|
||||
}
|
||||
|
||||
let (limit, offset) = limit_and_offset(self.page, self.limit);
|
||||
|
||||
// Note: deleted and removed comments are done on the front side
|
||||
|
@ -440,7 +475,8 @@ impl ViewToVec for CommentView {
|
|||
creator_banned_from_community: a.7.is_some(),
|
||||
subscribed: a.8.is_some(),
|
||||
saved: a.9.is_some(),
|
||||
my_vote: a.10,
|
||||
creator_blocked: a.10.is_some(),
|
||||
my_vote: a.11,
|
||||
})
|
||||
.collect::<Vec<Self>>()
|
||||
}
|
||||
|
@ -512,6 +548,7 @@ mod tests {
|
|||
my_vote: None,
|
||||
subscribed: false,
|
||||
saved: false,
|
||||
creator_blocked: false,
|
||||
comment: Comment {
|
||||
id: inserted_comment.id,
|
||||
content: "A test comment 32".into(),
|
||||
|
|
|
@ -13,9 +13,11 @@ use lemmy_db_queries::{
|
|||
use lemmy_db_schema::{
|
||||
schema::{
|
||||
community,
|
||||
community_block,
|
||||
community_follower,
|
||||
community_person_ban,
|
||||
person,
|
||||
person_block,
|
||||
post,
|
||||
post_aggregates,
|
||||
post_like,
|
||||
|
@ -25,6 +27,7 @@ use lemmy_db_schema::{
|
|||
source::{
|
||||
community::{Community, CommunityFollower, CommunityPersonBan, CommunitySafe},
|
||||
person::{Person, PersonSafe},
|
||||
person_block::PersonBlock,
|
||||
post::{Post, PostRead, PostSaved},
|
||||
},
|
||||
CommunityId,
|
||||
|
@ -42,10 +45,11 @@ pub struct PostView {
|
|||
pub community: CommunitySafe,
|
||||
pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan
|
||||
pub counts: PostAggregates,
|
||||
pub subscribed: bool, // Left join to CommunityFollower
|
||||
pub saved: bool, // Left join to PostSaved
|
||||
pub read: bool, // Left join to PostRead
|
||||
pub my_vote: Option<i16>, // Left join to PostLike
|
||||
pub subscribed: bool, // Left join to CommunityFollower
|
||||
pub saved: bool, // Left join to PostSaved
|
||||
pub read: bool, // Left join to PostRead
|
||||
pub creator_blocked: bool, // Left join to PersonBlock
|
||||
pub my_vote: Option<i16>, // Left join to PostLike
|
||||
}
|
||||
|
||||
type PostViewTuple = (
|
||||
|
@ -57,6 +61,7 @@ type PostViewTuple = (
|
|||
Option<CommunityFollower>,
|
||||
Option<PostSaved>,
|
||||
Option<PostRead>,
|
||||
Option<PersonBlock>,
|
||||
Option<i16>,
|
||||
);
|
||||
|
||||
|
@ -78,6 +83,7 @@ impl PostView {
|
|||
follower,
|
||||
saved,
|
||||
read,
|
||||
creator_blocked,
|
||||
post_like,
|
||||
) = post::table
|
||||
.find(post_id)
|
||||
|
@ -112,6 +118,13 @@ impl PostView {
|
|||
.and(post_read::person_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
person_block::table.on(
|
||||
post::creator_id
|
||||
.eq(person_block::person_id)
|
||||
.and(person_block::recipient_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
post_like::table.on(
|
||||
post::id
|
||||
|
@ -128,6 +141,7 @@ impl PostView {
|
|||
community_follower::all_columns.nullable(),
|
||||
post_saved::all_columns.nullable(),
|
||||
post_read::all_columns.nullable(),
|
||||
person_block::all_columns.nullable(),
|
||||
post_like::score.nullable(),
|
||||
))
|
||||
.first::<PostViewTuple>(conn)?;
|
||||
|
@ -149,6 +163,7 @@ impl PostView {
|
|||
subscribed: follower.is_some(),
|
||||
saved: saved.is_some(),
|
||||
read: read.is_some(),
|
||||
creator_blocked: creator_blocked.is_some(),
|
||||
my_vote,
|
||||
})
|
||||
}
|
||||
|
@ -301,6 +316,20 @@ impl<'a> PostQueryBuilder<'a> {
|
|||
.and(post_read::person_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
person_block::table.on(
|
||||
post::creator_id
|
||||
.eq(person_block::person_id)
|
||||
.and(person_block::recipient_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
community_block::table.on(
|
||||
community::id
|
||||
.eq(community_block::community_id)
|
||||
.and(community_block::person_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
post_like::table.on(
|
||||
post::id
|
||||
|
@ -317,6 +346,7 @@ impl<'a> PostQueryBuilder<'a> {
|
|||
community_follower::all_columns.nullable(),
|
||||
post_saved::all_columns.nullable(),
|
||||
post_read::all_columns.nullable(),
|
||||
person_block::all_columns.nullable(),
|
||||
post_like::score.nullable(),
|
||||
))
|
||||
.into_boxed();
|
||||
|
@ -377,6 +407,11 @@ impl<'a> PostQueryBuilder<'a> {
|
|||
query = query.filter(post_saved::id.is_not_null());
|
||||
};
|
||||
|
||||
// Don't show blocked communities
|
||||
if self.my_person_id.is_some() {
|
||||
query = query.filter(community_block::person_id.is_null());
|
||||
}
|
||||
|
||||
query = match self.sort.unwrap_or(SortType::Hot) {
|
||||
SortType::Active => query
|
||||
.then_order_by(
|
||||
|
@ -440,7 +475,8 @@ impl ViewToVec for PostView {
|
|||
subscribed: a.5.is_some(),
|
||||
saved: a.6.is_some(),
|
||||
read: a.7.is_some(),
|
||||
my_vote: a.8,
|
||||
creator_blocked: a.8.is_some(),
|
||||
my_vote: a.9,
|
||||
})
|
||||
.collect::<Vec<Self>>()
|
||||
}
|
||||
|
@ -623,6 +659,7 @@ mod tests {
|
|||
subscribed: false,
|
||||
read: false,
|
||||
saved: false,
|
||||
creator_blocked: false,
|
||||
};
|
||||
|
||||
// TODO More needs to be added here
|
||||
|
|
49
crates/db_views_actor/src/community_block_view.rs
Normal file
49
crates/db_views_actor/src/community_block_view.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use diesel::{result::Error, *};
|
||||
use lemmy_db_queries::{ToSafe, ViewToVec};
|
||||
use lemmy_db_schema::{
|
||||
schema::{community, community_block, person},
|
||||
source::{
|
||||
community::{Community, CommunitySafe},
|
||||
person::{Person, PersonSafe},
|
||||
},
|
||||
PersonId,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
pub struct CommunityBlockView {
|
||||
pub person: PersonSafe,
|
||||
pub community: CommunitySafe,
|
||||
}
|
||||
|
||||
type CommunityBlockViewTuple = (PersonSafe, CommunitySafe);
|
||||
|
||||
impl CommunityBlockView {
|
||||
pub fn for_person(conn: &PgConnection, person_id: PersonId) -> Result<Vec<Self>, Error> {
|
||||
let res = community_block::table
|
||||
.inner_join(person::table)
|
||||
.inner_join(community::table)
|
||||
.select((
|
||||
Person::safe_columns_tuple(),
|
||||
Community::safe_columns_tuple(),
|
||||
))
|
||||
.filter(community_block::person_id.eq(person_id))
|
||||
.order_by(community_block::published)
|
||||
.load::<CommunityBlockViewTuple>(conn)?;
|
||||
|
||||
Ok(Self::from_tuple_to_vec(res))
|
||||
}
|
||||
}
|
||||
|
||||
impl ViewToVec for CommunityBlockView {
|
||||
type DbTuple = CommunityBlockViewTuple;
|
||||
fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
|
||||
items
|
||||
.iter()
|
||||
.map(|a| Self {
|
||||
person: a.0.to_owned(),
|
||||
community: a.1.to_owned(),
|
||||
})
|
||||
.collect::<Vec<Self>>()
|
||||
}
|
||||
}
|
|
@ -12,8 +12,11 @@ use lemmy_db_queries::{
|
|||
ViewToVec,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
schema::{community, community_aggregates, community_follower},
|
||||
source::community::{Community, CommunityFollower, CommunitySafe},
|
||||
schema::{community, community_aggregates, community_block, community_follower},
|
||||
source::{
|
||||
community::{Community, CommunityFollower, CommunitySafe},
|
||||
community_block::CommunityBlock,
|
||||
},
|
||||
CommunityId,
|
||||
PersonId,
|
||||
};
|
||||
|
@ -23,6 +26,7 @@ use serde::Serialize;
|
|||
pub struct CommunityView {
|
||||
pub community: CommunitySafe,
|
||||
pub subscribed: bool,
|
||||
pub blocked: bool,
|
||||
pub counts: CommunityAggregates,
|
||||
}
|
||||
|
||||
|
@ -30,6 +34,7 @@ type CommunityViewTuple = (
|
|||
CommunitySafe,
|
||||
CommunityAggregates,
|
||||
Option<CommunityFollower>,
|
||||
Option<CommunityBlock>,
|
||||
);
|
||||
|
||||
impl CommunityView {
|
||||
|
@ -41,7 +46,7 @@ impl CommunityView {
|
|||
// The left join below will return None in this case
|
||||
let person_id_join = my_person_id.unwrap_or(PersonId(-1));
|
||||
|
||||
let (community, counts, follower) = community::table
|
||||
let (community, counts, follower, blocked) = community::table
|
||||
.find(community_id)
|
||||
.inner_join(community_aggregates::table)
|
||||
.left_join(
|
||||
|
@ -51,16 +56,25 @@ impl CommunityView {
|
|||
.and(community_follower::person_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
community_block::table.on(
|
||||
community::id
|
||||
.eq(community_block::community_id)
|
||||
.and(community_block::person_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.select((
|
||||
Community::safe_columns_tuple(),
|
||||
community_aggregates::all_columns,
|
||||
community_follower::all_columns.nullable(),
|
||||
community_block::all_columns.nullable(),
|
||||
))
|
||||
.first::<CommunityViewTuple>(conn)?;
|
||||
|
||||
Ok(CommunityView {
|
||||
community,
|
||||
subscribed: follower.is_some(),
|
||||
blocked: blocked.is_some(),
|
||||
counts,
|
||||
})
|
||||
}
|
||||
|
@ -165,10 +179,18 @@ impl<'a> CommunityQueryBuilder<'a> {
|
|||
.and(community_follower::person_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.left_join(
|
||||
community_block::table.on(
|
||||
community::id
|
||||
.eq(community_block::community_id)
|
||||
.and(community_block::person_id.eq(person_id_join)),
|
||||
),
|
||||
)
|
||||
.select((
|
||||
Community::safe_columns_tuple(),
|
||||
community_aggregates::all_columns,
|
||||
community_follower::all_columns.nullable(),
|
||||
community_block::all_columns.nullable(),
|
||||
))
|
||||
.into_boxed();
|
||||
|
||||
|
@ -210,6 +232,11 @@ impl<'a> CommunityQueryBuilder<'a> {
|
|||
};
|
||||
}
|
||||
|
||||
// Don't show blocked communities
|
||||
if self.my_person_id.is_some() {
|
||||
query = query.filter(community_block::person_id.is_null());
|
||||
}
|
||||
|
||||
let (limit, offset) = limit_and_offset(self.page, self.limit);
|
||||
let res = query
|
||||
.limit(limit)
|
||||
|
@ -231,6 +258,7 @@ impl ViewToVec for CommunityView {
|
|||
community: a.0.to_owned(),
|
||||
counts: a.1.to_owned(),
|
||||
subscribed: a.2.is_some(),
|
||||
blocked: a.3.is_some(),
|
||||
})
|
||||
.collect::<Vec<Self>>()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
pub mod community_block_view;
|
||||
pub mod community_follower_view;
|
||||
pub mod community_moderator_view;
|
||||
pub mod community_person_ban_view;
|
||||
pub mod community_view;
|
||||
pub mod person_block_view;
|
||||
pub mod person_mention_view;
|
||||
pub mod person_view;
|
||||
|
|
46
crates/db_views_actor/src/person_block_view.rs
Normal file
46
crates/db_views_actor/src/person_block_view.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
use diesel::{result::Error, *};
|
||||
use lemmy_db_queries::{ToSafe, ViewToVec};
|
||||
use lemmy_db_schema::{
|
||||
schema::{person, person_alias_1, person_block},
|
||||
source::person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
|
||||
PersonId,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
pub struct PersonBlockView {
|
||||
pub person: PersonSafe,
|
||||
pub recipient: PersonSafeAlias1,
|
||||
}
|
||||
|
||||
type PersonBlockViewTuple = (PersonSafe, PersonSafeAlias1);
|
||||
|
||||
impl PersonBlockView {
|
||||
pub fn for_person(conn: &PgConnection, person_id: PersonId) -> Result<Vec<Self>, Error> {
|
||||
let res = person_block::table
|
||||
.inner_join(person::table)
|
||||
.inner_join(person_alias_1::table) // TODO I dont know if this will be smart abt the column
|
||||
.select((
|
||||
Person::safe_columns_tuple(),
|
||||
PersonAlias1::safe_columns_tuple(),
|
||||
))
|
||||
.filter(person_block::person_id.eq(person_id))
|
||||
.order_by(person_block::published)
|
||||
.load::<PersonBlockViewTuple>(conn)?;
|
||||
|
||||
Ok(Self::from_tuple_to_vec(res))
|
||||
}
|
||||
}
|
||||
|
||||
impl ViewToVec for PersonBlockView {
|
||||
type DbTuple = PersonBlockViewTuple;
|
||||
fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
|
||||
items
|
||||
.iter()
|
||||
.map(|a| Self {
|
||||
person: a.0.to_owned(),
|
||||
recipient: a.1.to_owned(),
|
||||
})
|
||||
.collect::<Vec<Self>>()
|
||||
}
|
||||
}
|
|
@ -126,6 +126,10 @@ pub enum UserOperation {
|
|||
ModJoin,
|
||||
ChangePassword,
|
||||
GetSiteMetadata,
|
||||
BlockCommunity,
|
||||
BlockPerson,
|
||||
GetBlockedCommunities,
|
||||
GetBlockedPersons,
|
||||
}
|
||||
|
||||
#[derive(EnumString, ToString, Debug, Clone)]
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
drop table person_block;
|
||||
drop table community_block;
|
|
@ -0,0 +1,13 @@
|
|||
create table person_block (
|
||||
id serial primary key,
|
||||
person_id int references person on update cascade on delete cascade not null,
|
||||
recipient_id int references person on update cascade on delete cascade not null,
|
||||
published timestamp not null default now()
|
||||
);
|
||||
|
||||
create table community_block (
|
||||
id serial primary key,
|
||||
person_id int references person on update cascade on delete cascade not null,
|
||||
community_id int references community on update cascade on delete cascade not null,
|
||||
published timestamp not null default now()
|
||||
);
|
|
@ -47,6 +47,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
|||
.route("", web::put().to(route_post_crud::<EditCommunity>))
|
||||
.route("/list", web::get().to(route_get_crud::<ListCommunities>))
|
||||
.route("/follow", web::post().to(route_post::<FollowCommunity>))
|
||||
.route("/block", web::post().to(route_post::<BlockCommunity>))
|
||||
.route(
|
||||
"/delete",
|
||||
web::post().to(route_post_crud::<DeleteCommunity>),
|
||||
|
@ -150,6 +151,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
|||
.wrap(rate_limit.message())
|
||||
.route("", web::get().to(route_get_crud::<GetPersonDetails>))
|
||||
.route("/mention", web::get().to(route_get::<GetPersonMentions>))
|
||||
.route("/block", web::get().to(route_get::<GetBlockedPersons>))
|
||||
.route(
|
||||
"/mention/mark_as_read",
|
||||
web::post().to(route_post::<MarkPersonMentionAsRead>),
|
||||
|
@ -159,9 +161,14 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
|||
"/followed_communities",
|
||||
web::get().to(route_get::<GetFollowedCommunities>),
|
||||
)
|
||||
.route(
|
||||
"/blocked_communities",
|
||||
web::get().to(route_get::<GetBlockedCommunities>),
|
||||
)
|
||||
.route("/join", web::post().to(route_post::<UserJoin>))
|
||||
// Admin action. I don't like that it's in /user
|
||||
.route("/ban", web::post().to(route_post::<BanPerson>))
|
||||
.route("/block", web::post().to(route_post::<BlockPerson>))
|
||||
// Account actions. I don't like that they're in /user maybe /accounts
|
||||
.route("/login", web::post().to(route_post::<Login>))
|
||||
.route("/get_captcha", web::get().to(route_get::<GetCaptcha>))
|
||||
|
|
Loading…
Reference in a new issue