mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-11 16:35:47 +01:00
feat: account content deletion, closes #8381
This commit is contained in:
@@ -12,8 +12,9 @@
|
|||||||
"unban": "Unban User(s)",
|
"unban": "Unban User(s)",
|
||||||
"reset-lockout": "Reset Lockout",
|
"reset-lockout": "Reset Lockout",
|
||||||
"reset-flags": "Reset Flags",
|
"reset-flags": "Reset Flags",
|
||||||
"delete": "Delete User(s)",
|
"delete": "Delete <strong>User(s)</strong>",
|
||||||
"purge": "Delete User(s) and Content",
|
"delete-content": "Delete User(s) <strong>Content</strong>",
|
||||||
|
"purge": "Delete <strong>User(s)</strong> and <strong>Content</strong>",
|
||||||
"download-csv": "Download CSV",
|
"download-csv": "Download CSV",
|
||||||
"manage-groups": "Manage Groups",
|
"manage-groups": "Manage Groups",
|
||||||
"add-group": "Add Group",
|
"add-group": "Add Group",
|
||||||
@@ -93,9 +94,11 @@
|
|||||||
"alerts.validate-email-success": "Emails validated",
|
"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.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.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.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.create": "Create User",
|
||||||
"alerts.button-create": "Create",
|
"alerts.button-create": "Create",
|
||||||
"alerts.button-cancel": "Cancel",
|
"alerts.button-cancel": "Cancel",
|
||||||
|
|||||||
@@ -13,9 +13,12 @@
|
|||||||
"ban_account_confirm": "Do you really want to ban this user?",
|
"ban_account_confirm": "Do you really want to ban this user?",
|
||||||
"unban_account": "Unban Account",
|
"unban_account": "Unban Account",
|
||||||
"delete_account": "Delete 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_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_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-deleted": "Account deleted",
|
||||||
|
"account-content-deleted": "Account content deleted",
|
||||||
|
|
||||||
"fullname": "Full Name",
|
"fullname": "Full Name",
|
||||||
"website": "Website",
|
"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 () {
|
$('.delete-user-and-content').on('click', function () {
|
||||||
var uids = getSelectedUids();
|
var uids = getSelectedUids();
|
||||||
if (!uids.length) {
|
if (!uids.length) {
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ define('forum/account/header', [
|
|||||||
// TODO: These exported methods are used in forum/flags/detail -- refactor??
|
// TODO: These exported methods are used in forum/flags/detail -- refactor??
|
||||||
AccountHeader.banAccount = banAccount;
|
AccountHeader.banAccount = banAccount;
|
||||||
AccountHeader.deleteAccount = deleteAccount;
|
AccountHeader.deleteAccount = deleteAccount;
|
||||||
|
AccountHeader.deleteContent = deleteContent;
|
||||||
|
|
||||||
function hidePrivateLinks() {
|
function hidePrivateLinks() {
|
||||||
if (!app.user.uid || app.user.uid !== parseInt(ajaxify.data.theirid, 10)) {
|
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() {
|
function flagAccount() {
|
||||||
require(['flags'], function (flags) {
|
require(['flags'], function (flags) {
|
||||||
flags.showFlagModal({
|
flags.showFlagModal({
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ define('forum/flags/detail', ['forum/flags/list', 'components', 'translator', 'b
|
|||||||
AccountHeader.deleteAccount(uid, ajaxify.refresh);
|
AccountHeader.deleteAccount(uid, ajaxify.refresh);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'delete-content':
|
||||||
|
AccountHeader.deleteContent(uid, ajaxify.refresh);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'delete-post':
|
case 'delete-post':
|
||||||
postAction('delete', ajaxify.data.target.pid, ajaxify.data.target.tid);
|
postAction('delete', ajaxify.data.target.pid, ajaxify.data.target.tid);
|
||||||
break;
|
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) {
|
User.deleteUsersAndContent = async function (socket, uids) {
|
||||||
deleteUsers(socket, uids, async function (uid) {
|
deleteUsers(socket, uids, async function (uid) {
|
||||||
await user.delete(socket.uid, uid);
|
await user.delete(socket.uid, uid);
|
||||||
|
|||||||
@@ -17,7 +17,13 @@ const file = require('../file');
|
|||||||
module.exports = function (User) {
|
module.exports = function (User) {
|
||||||
const deletesInProgress = {};
|
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) {
|
if (parseInt(uid, 10) <= 0) {
|
||||||
throw new Error('[[error:invalid-uid]]');
|
throw new Error('[[error:invalid-uid]]');
|
||||||
}
|
}
|
||||||
@@ -25,13 +31,10 @@ module.exports = function (User) {
|
|||||||
throw new Error('[[error:already-deleting]]');
|
throw new Error('[[error:already-deleting]]');
|
||||||
}
|
}
|
||||||
deletesInProgress[uid] = 'user.delete';
|
deletesInProgress[uid] = 'user.delete';
|
||||||
await removeFromSortedSets(uid);
|
|
||||||
await deletePosts(callerUid, uid);
|
await deletePosts(callerUid, uid);
|
||||||
await deleteTopics(callerUid, uid);
|
await deleteTopics(callerUid, uid);
|
||||||
await deleteUploads(uid);
|
await deleteUploads(uid);
|
||||||
await deleteQueued(uid);
|
await deleteQueued(uid);
|
||||||
const userData = await User.deleteAccount(uid);
|
|
||||||
return userData;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
async function deletePosts(callerUid, uid) {
|
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><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 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"><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>
|
<li><a href="#" class="delete-user-and-content"><i class="fa fa-fw fa-trash-o"></i> [[admin/manage/users:purge]]</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user