- Works for both a site-ban, and a community ban.
- Fixes #557
data: {
user_id: i32,
ban: bool,
+ remove_data: Option<bool>, // Removes/Restores their comments, posts, and communities
reason: Option<String>,
expires: Option<i64>,
auth: String
community_id: i32,
user_id: i32,
ban: bool,
+ remove_data: Option<bool>, // Removes/Restores their comments and posts for that community
reason: Option<String>,
expires: Option<i64>,
auth: String
comment.filter(ap_id.eq(object_id)).first::<Self>(conn)
}
- pub fn permadelete(conn: &PgConnection, comment_id: i32) -> Result<Self, Error> {
+ pub fn permadelete_for_creator(conn: &PgConnection, for_creator_id: i32) -> Result<Vec<Self>, Error> {
use crate::schema::comment::dsl::*;
-
- diesel::update(comment.find(comment_id))
+ diesel::update(comment.filter(creator_id.eq(for_creator_id)))
.set((
content.eq("*Permananently Deleted*"),
deleted.eq(true),
updated.eq(naive_now()),
))
- .get_result::<Self>(conn)
+ .get_results::<Self>(conn)
}
pub fn update_deleted(
.get_result::<Self>(conn)
}
+ pub fn update_removed_for_creator(
+ conn: &PgConnection,
+ for_creator_id: i32,
+ new_removed: bool,
+ ) -> Result<Vec<Self>, Error> {
+ use crate::schema::comment::dsl::*;
+ diesel::update(comment.filter(creator_id.eq(for_creator_id)))
+ .set((removed.eq(new_removed), updated.eq(naive_now())))
+ .get_results::<Self>(conn)
+ }
+
pub fn update_read(conn: &PgConnection, comment_id: i32, new_read: bool) -> Result<Self, Error> {
use crate::schema::comment::dsl::*;
diesel::update(comment.find(comment_id))
.get_result::<Self>(conn)
}
+ pub fn update_removed_for_creator(
+ conn: &PgConnection,
+ for_creator_id: i32,
+ new_removed: bool,
+ ) -> Result<Vec<Self>, Error> {
+ use crate::schema::community::dsl::*;
+ diesel::update(community.filter(creator_id.eq(for_creator_id)))
+ .set((removed.eq(new_removed), updated.eq(naive_now())))
+ .get_results::<Self>(conn)
+ }
+
pub fn update_creator(
conn: &PgConnection,
community_id: i32,
.get_result::<Self>(conn)
}
- pub fn permadelete(conn: &PgConnection, post_id: i32) -> Result<Self, Error> {
+ pub fn permadelete_for_creator(conn: &PgConnection, for_creator_id: i32) -> Result<Vec<Self>, Error> {
use crate::schema::post::dsl::*;
let perma_deleted = "*Permananently Deleted*";
let perma_deleted_url = "https://deleted.com";
- diesel::update(post.find(post_id))
+ diesel::update(post.filter(creator_id.eq(for_creator_id)))
.set((
name.eq(perma_deleted),
url.eq(perma_deleted_url),
deleted.eq(true),
updated.eq(naive_now()),
))
- .get_result::<Self>(conn)
+ .get_results::<Self>(conn)
}
pub fn update_deleted(
.get_result::<Self>(conn)
}
+ pub fn update_removed_for_creator(
+ conn: &PgConnection,
+ for_creator_id: i32,
+ for_community_id: Option<i32>,
+ new_removed: bool,
+ ) -> Result<Vec<Self>, Error> {
+ use crate::schema::post::dsl::*;
+
+ let mut update = diesel::update(post).into_boxed();
+ update = update.filter(creator_id.eq(for_creator_id));
+
+ if let Some(for_community_id) = for_community_id {
+ update = update.filter(community_id.eq(for_community_id));
+ }
+
+ update
+ .set((removed.eq(new_removed), updated.eq(naive_now())))
+ .get_results::<Self>(conn)
+ }
+
pub fn update_locked(conn: &PgConnection, post_id: i32, new_locked: bool) -> Result<Self, Error> {
use crate::schema::post::dsl::*;
diesel::update(post.find(post_id))
use actix_web::client::Client;
use anyhow::Context;
use lemmy_db::{
+ comment::Comment,
+ comment_view::CommentQueryBuilder,
diesel_option_overwrite,
naive_now,
+ post::Post,
Bannable,
Crud,
Followable,
pub community_id: i32,
user_id: i32,
ban: bool,
+ remove_data: Option<bool>,
reason: Option<String>,
expires: Option<i64>,
auth: String,
let user = get_user_from_jwt(&data.auth, pool).await?;
let community_id = data.community_id;
+ let banned_user_id = data.user_id;
// Verify that only mods or admins can ban
is_mod_or_admin(pool, user.id, community_id).await?;
}
}
+ // Remove/Restore their data if that's desired
+ if let Some(remove_data) = data.remove_data {
+ // Posts
+ blocking(pool, move |conn: &'_ _| {
+ Post::update_removed_for_creator(conn, banned_user_id, Some(community_id), remove_data)
+ })
+ .await??;
+
+ // Comments
+ // Diesel doesn't allow updates with joins, so this has to be a loop
+ let comments = blocking(pool, move |conn| {
+ CommentQueryBuilder::create(conn)
+ .for_creator_id(banned_user_id)
+ .for_community_id(community_id)
+ .limit(std::i64::MAX)
+ .list()
+ })
+ .await??;
+
+ for comment in &comments {
+ let comment_id = comment.id;
+ blocking(pool, move |conn: &'_ _| {
+ Comment::update_removed(conn, comment_id, remove_data)
+ })
+ .await??;
+ }
+ }
+
// Mod tables
// TODO eventually do correct expires
let expires = match data.expires {
pub struct BanUser {
user_id: i32,
ban: bool,
+ remove_data: Option<bool>,
reason: Option<String>,
expires: Option<i64>,
auth: String,
return Err(APIError::err("couldnt_update_user").into());
}
+ // Remove their data if that's desired
+ if let Some(remove_data) = data.remove_data {
+ // Posts
+ blocking(pool, move |conn: &'_ _| {
+ Post::update_removed_for_creator(conn, banned_user_id, None, remove_data)
+ })
+ .await??;
+
+ // Communities
+ blocking(pool, move |conn: &'_ _| {
+ Community::update_removed_for_creator(conn, banned_user_id, remove_data)
+ })
+ .await??;
+
+ // Comments
+ blocking(pool, move |conn: &'_ _| {
+ Comment::update_removed_for_creator(conn, banned_user_id, remove_data)
+ })
+ .await??;
+ }
+
// Mod tables
let expires = match data.expires {
Some(time) => Some(naive_from_unix(time)),
// Comments
let user_id = user.id;
- let comments = blocking(pool, move |conn| {
- CommentQueryBuilder::create(conn)
- .for_creator_id(user_id)
- .limit(std::i64::MAX)
- .list()
- })
- .await??;
-
- // TODO: this should probably be a bulk operation
- for comment in &comments {
- let comment_id = comment.id;
- let permadelete = move |conn: &'_ _| Comment::permadelete(conn, comment_id);
- if blocking(pool, permadelete).await?.is_err() {
- return Err(APIError::err("couldnt_update_comment").into());
- }
+ let permadelete = move |conn: &'_ _| Comment::permadelete_for_creator(conn, user_id);
+ if blocking(pool, permadelete).await?.is_err() {
+ return Err(APIError::err("couldnt_update_comment").into());
}
// Posts
- let posts = blocking(pool, move |conn| {
- PostQueryBuilder::create(conn)
- .sort(&SortType::New)
- .for_creator_id(user_id)
- .limit(std::i64::MAX)
- .list()
- })
- .await??;
-
- // TODO: this should probably be a bulk operation
- for post in &posts {
- let post_id = post.id;
- let permadelete = move |conn: &'_ _| Post::permadelete(conn, post_id);
- if blocking(pool, permadelete).await?.is_err() {
- return Err(APIError::err("couldnt_update_post").into());
- }
+ let permadelete = move |conn: &'_ _| Post::permadelete_for_creator(conn, user_id);
+ if blocking(pool, permadelete).await?.is_err() {
+ return Err(APIError::err("couldnt_update_post").into());
}
Ok(LoginResponse {
showRemoveDialog: boolean;
removeReason: string;
showBanDialog: boolean;
+ removeData: boolean;
banReason: string;
banExpires: string;
banType: BanType;
showRemoveDialog: false,
removeReason: null,
showBanDialog: false,
+ removeData: null,
banReason: null,
banExpires: null,
banType: BanType.Community,
value={this.state.banReason}
onInput={linkEvent(this, this.handleModBanReasonChange)}
/>
+ <div class="form-group">
+ <div class="form-check">
+ <input
+ class="form-check-input"
+ id="mod-ban-remove-data"
+ type="checkbox"
+ checked={this.state.removeData}
+ onChange={linkEvent(this, this.handleModRemoveDataChange)}
+ />
+ <label class="form-check-label" htmlFor="mod-ban-remove-data">
+ {i18n.t('remove_posts_comments')}
+ </label>
+ </div>
+ </div>
</div>
{/* TODO hold off on expires until later */}
{/* <div class="form-group row"> */}
i.setState(i.state);
}
+ handleModRemoveDataChange(i: CommentNode, event: any) {
+ i.state.removeData = event.target.checked;
+ i.setState(i.state);
+ }
+
handleModRemoveSubmit(i: CommentNode) {
event.preventDefault();
let form: RemoveCommentForm = {
event.preventDefault();
if (i.state.banType == BanType.Community) {
+ // If its an unban, restore all their data
+ let ban = !i.props.node.comment.banned_from_community;
+ if (ban == false) {
+ i.state.removeData = false;
+ }
let form: BanFromCommunityForm = {
user_id: i.props.node.comment.creator_id,
community_id: i.props.node.comment.community_id,
- ban: !i.props.node.comment.banned_from_community,
+ ban,
+ remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
};
WebSocketService.Instance.banFromCommunity(form);
} else {
+ // If its an unban, restore all their data
+ let ban = !i.props.node.comment.banned;
+ if (ban == false) {
+ i.state.removeData = false;
+ }
let form: BanUserForm = {
user_id: i.props.node.comment.creator_id,
- ban: !i.props.node.comment.banned,
+ ban,
+ remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
};
showRemoveDialog: boolean;
removeReason: string;
showBanDialog: boolean;
+ removeData: boolean;
banReason: string;
banExpires: string;
banType: BanType;
showRemoveDialog: false,
removeReason: null,
showBanDialog: false,
+ removeData: null,
banReason: null,
banExpires: null,
banType: BanType.Community,
value={this.state.banReason}
onInput={linkEvent(this, this.handleModBanReasonChange)}
/>
+ <div class="form-group">
+ <div class="form-check">
+ <input
+ class="form-check-input"
+ id="mod-ban-remove-data"
+ type="checkbox"
+ checked={this.state.removeData}
+ onChange={linkEvent(this, this.handleModRemoveDataChange)}
+ />
+ <label class="form-check-label" htmlFor="mod-ban-remove-data">
+ {i18n.t('remove_posts_comments')}
+ </label>
+ </div>
+ </div>
</div>
{/* TODO hold off on expires until later */}
{/* <div class="form-group row"> */}
i.setState(i.state);
}
+ handleModRemoveDataChange(i: PostListing, event: any) {
+ i.state.removeData = event.target.checked;
+ i.setState(i.state);
+ }
+
handleModRemoveSubmit(i: PostListing) {
event.preventDefault();
let form: RemovePostForm = {
event.preventDefault();
if (i.state.banType == BanType.Community) {
+ // If its an unban, restore all their data
+ let ban = !i.props.post.banned_from_community;
+ if (ban == false) {
+ i.state.removeData = false;
+ }
let form: BanFromCommunityForm = {
user_id: i.props.post.creator_id,
community_id: i.props.post.community_id,
- ban: !i.props.post.banned_from_community,
+ ban,
+ remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
};
WebSocketService.Instance.banFromCommunity(form);
} else {
+ // If its an unban, restore all their data
+ let ban = !i.props.post.banned;
+ if (ban == false) {
+ i.state.removeData = false;
+ }
let form: BanUserForm = {
user_id: i.props.post.creator_id,
- ban: !i.props.post.banned,
+ ban,
+ remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
};
community_id: number;
user_id: number;
ban: boolean;
+ remove_data?: boolean;
reason?: string;
expires?: number;
auth?: string;
export interface BanUserForm {
user_id: number;
ban: boolean;
+ remove_data?: boolean;
reason?: string;
expires?: number;
auth?: string;
"number_of_comments": "{{count}} Comment",
"number_of_comments_plural": "{{count}} Comments",
"remove_comment": "Remove Comment",
+ "remove_posts_comments": "Remove Posts and Comments",
"communities": "Communities",
"users": "Users",
"create_a_community": "Create a community",