feat: account content deletion, closes #8381

v1.18.x
Julian Lam 5 years ago
parent 4b577a527a
commit 67aca822e6

@ -12,8 +12,9 @@
"unban": "Unban User(s)",
"reset-lockout": "Reset Lockout",
"reset-flags": "Reset Flags",
"delete": "Delete User(s)",
"purge": "Delete User(s) and Content",
"delete": "Delete <strong>User(s)</strong>",
"delete-content": "Delete User(s) <strong>Content</strong>",
"purge": "Delete <strong>User(s)</strong> and <strong>Content</strong>",
"download-csv": "Download CSV",
"manage-groups": "Manage Groups",
"add-group": "Add Group",
@ -93,9 +94,11 @@
"alerts.validate-email-success": "Emails validated",
"alerts.validate-force-password-reset-success": "User(s) passwords have been reset and their existing sessions have been revoked.",
"alerts.password-reset-confirm": "Do you want to send password reset email(s) to these user(s)?",
"alerts.confirm-delete": "<b>Warning!</b><br/>Do you really want to delete user(s)?<br/> This action is not reversable! Only the user account will be deleted, their posts and topics will remain.",
"alerts.confirm-delete": "<strong>Warning!</strong><p>Do you really want to delete <strong>user(s)</strong>?</p><p>This action is not reversible! Only the user account will be deleted, their posts and topics will remain.</p>",
"alerts.delete-success": "User(s) Deleted!",
"alerts.confirm-purge": "<b>Warning!</b><br/>Do you really want to delete user(s) and their content?<br/> This action is not reversable! All user data and content will be erased!",
"alerts.confirm-delete-content": "<strong>Warning!</strong><p>Do you really want to delete these user(s) <strong>content</strong>?</p><p>This action is not reversible! The users' accounts will remain, but their posts and topics will be deleted.</p>",
"alerts.delete-content-success": "User(s) Content Deleted!",
"alerts.confirm-purge": "<strong>Warning!</strong><p>Do you really want to delete <strong>user(s) and their content</strong>?</p><p>This action is not reversible! All user data and content will be erased!</p>",
"alerts.create": "Create User",
"alerts.button-create": "Create",
"alerts.button-cancel": "Cancel",

@ -13,9 +13,12 @@
"ban_account_confirm": "Do you really want to ban this user?",
"unban_account": "Unban Account",
"delete_account": "Delete Account",
"delete_content": "Delete Account Content Only",
"delete_account_confirm": "Are you sure you want to delete your account? <br /><strong>This action is irreversible and you will not be able to recover any of your data</strong><br /><br />Enter your password to confirm that you wish to destroy this account.",
"delete_this_account_confirm": "Are you sure you want to delete this account? <br /><strong>This action is irreversible and you will not be able to recover any data</strong><br /><br />",
"delete_account_content_confirm": "Are you sure you want to delete this account's content (posts/topics/uploads)? <br /><strong>This action is irreversible and you will not be able to recover any data</strong><br /><br />",
"account-deleted": "Account deleted",
"account-content-deleted": "Account content deleted",
"fullname": "Full Name",
"website": "Website",

@ -262,6 +262,25 @@ define('admin/manage/users', ['translator', 'benchpress', 'autocomplete'], funct
});
});
$('.delete-user-content').on('click', function () {
var uids = getSelectedUids();
if (!uids.length) {
return;
}
bootbox.confirm('[[admin/manage/users:alerts.confirm-delete-content]]', function (confirm) {
if (confirm) {
socket.emit('admin.user.deleteUsersContent', uids, function (err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[admin/manage/users:alerts.delete-content-success]]');
});
}
});
});
$('.delete-user-and-content').on('click', function () {
var uids = getSelectedUids();
if (!uids.length) {

@ -59,6 +59,7 @@ define('forum/account/header', [
// TODO: These exported methods are used in forum/flags/detail -- refactor??
AccountHeader.banAccount = banAccount;
AccountHeader.deleteAccount = deleteAccount;
AccountHeader.deleteContent = deleteContent;
function hidePrivateLinks() {
if (!app.user.uid || app.user.uid !== parseInt(ajaxify.data.theirid, 10)) {
@ -201,6 +202,31 @@ define('forum/account/header', [
});
}
function deleteContent(theirid, onSuccess) {
theirid = theirid || ajaxify.data.theirid;
translator.translate('[[user:delete_account_content_confirm]]', function (translated) {
bootbox.confirm(translated, function (confirm) {
if (!confirm) {
return;
}
socket.emit('admin.user.deleteUsersContent', [theirid], function (err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[user:account-content-deleted]]');
if (typeof onSuccess === 'function') {
return onSuccess();
}
history.back();
});
});
});
}
function flagAccount() {
require(['flags'], function (flags) {
flags.showFlagModal({

@ -52,6 +52,10 @@ define('forum/flags/detail', ['forum/flags/list', 'components', 'translator', 'b
AccountHeader.deleteAccount(uid, ajaxify.refresh);
break;
case 'delete-content':
AccountHeader.deleteContent(uid, ajaxify.refresh);
break;
case 'delete-post':
postAction('delete', ajaxify.data.target.pid, ajaxify.data.target.tid);
break;

@ -126,6 +126,20 @@ User.deleteUsers = async function (socket, uids) {
});
};
User.deleteUsersContent = async function (socket, uids) {
if (!Array.isArray(uids)) {
throw new Error('[[error:invalid-data]]');
}
const isMembers = await groups.isMembers(uids, 'administrators');
if (isMembers.includes(true)) {
throw new Error('[[error:cant-delete-other-admins]]');
}
await Promise.all(uids.map(async (uid) => {
await user.deleteContent(socket.uid, uid);
}));
};
User.deleteUsersAndContent = async function (socket, uids) {
deleteUsers(socket, uids, async function (uid) {
await user.delete(socket.uid, uid);

@ -17,7 +17,13 @@ const file = require('../file');
module.exports = function (User) {
const deletesInProgress = {};
User.delete = async function (callerUid, uid) {
User.delete = async (callerUid, uid) => {
await User.deleteContent(callerUid, uid);
await removeFromSortedSets(uid);
return await User.deleteAccount(uid);
};
User.deleteContent = async function (callerUid, uid) {
if (parseInt(uid, 10) <= 0) {
throw new Error('[[error:invalid-uid]]');
}
@ -25,13 +31,10 @@ module.exports = function (User) {
throw new Error('[[error:already-deleting]]');
}
deletesInProgress[uid] = 'user.delete';
await removeFromSortedSets(uid);
await deletePosts(callerUid, uid);
await deleteTopics(callerUid, uid);
await deleteUploads(uid);
await deleteQueued(uid);
const userData = await User.deleteAccount(uid);
return userData;
};
async function deletePosts(callerUid, uid) {

@ -22,6 +22,7 @@
<li><a href="#" class="reset-lockout"><i class="fa fa-fw fa-unlock"></i> [[admin/manage/users:reset-lockout]]</a></li>
<li class="divider"></li>
<li><a href="#" class="delete-user"><i class="fa fa-fw fa-trash-o"></i> [[admin/manage/users:delete]]</a></li>
<li><a href="#" class="delete-user-content"><i class="fa fa-fw fa-trash-o"></i> [[admin/manage/users:delete-content]]</a></li>
<li><a href="#" class="delete-user-and-content"><i class="fa fa-fw fa-trash-o"></i> [[admin/manage/users:purge]]</a></li>
</ul>
</div>

Loading…
Cancel
Save