mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-02-28 01:21:13 +01:00
feat: #11842, ability to change reputation of users
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
"purge": "Delete <strong>User(s)</strong> and <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",
|
||||||
|
"set-reputation": "Set Reputation",
|
||||||
"add-group": "Add Group",
|
"add-group": "Add Group",
|
||||||
"create": "Create User",
|
"create": "Create User",
|
||||||
"invite": "Invite by Email",
|
"invite": "Invite by Email",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
define('admin/manage/users', [
|
define('admin/manage/users', [
|
||||||
'translator', 'benchpress', 'autocomplete', 'api', 'slugify', 'bootbox', 'alerts', 'accounts/invite',
|
'translator', 'benchpress', 'autocomplete', 'api', 'slugify', 'bootbox', 'alerts', 'accounts/invite', 'helpers',
|
||||||
], function (translator, Benchpress, autocomplete, api, slugify, bootbox, alerts, AccountInvite) {
|
], function (translator, Benchpress, autocomplete, api, slugify, bootbox, alerts, AccountInvite, helpers) {
|
||||||
const Users = {};
|
const Users = {};
|
||||||
|
|
||||||
Users.init = function () {
|
Users.init = function () {
|
||||||
@@ -141,6 +141,53 @@ define('admin/manage/users', [
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.set-reputation').on('click', function () {
|
||||||
|
const uids = getSelectedUids();
|
||||||
|
if (!uids.length) {
|
||||||
|
alerts.error('[[error:no-users-selected]]');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let currentValue = '';
|
||||||
|
if (uids.length === 1) {
|
||||||
|
const user = ajaxify.data.users.find(u => u && u.uid === parseInt(uids[0], 10));
|
||||||
|
if (user) {
|
||||||
|
currentValue = String(user.reputation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const modal = bootbox.dialog({
|
||||||
|
message: `<input id="new-reputation" type="text" class="form-control" value="${currentValue}">`,
|
||||||
|
title: '[[admin/manage/users:set-reputation]]',
|
||||||
|
onEscape: true,
|
||||||
|
buttons: {
|
||||||
|
submit: {
|
||||||
|
label: '[[global:save]]',
|
||||||
|
callback: function () {
|
||||||
|
const newReputation = modal.find('#new-reputation').val();
|
||||||
|
if (!utils.isNumber(newReputation)) {
|
||||||
|
alerts.error('[[error:invalid-data]]');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
socket.emit('admin.user.setReputation', {
|
||||||
|
value: newReputation,
|
||||||
|
uids: uids,
|
||||||
|
}).then(() => {
|
||||||
|
uids.forEach((uid) => {
|
||||||
|
$(`[component="user/reputation"][data-uid="${uid}"]`).text(helpers.formattedNumber(newReputation));
|
||||||
|
const user = ajaxify.data.users.find(u => u && u.uid === parseInt(uid, 10));
|
||||||
|
if (user) {
|
||||||
|
user.reputation = newReputation;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(alerts.error);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
modal.on('shown.bs.modal', () => {
|
||||||
|
modal.find('#new-reputation').selectRange(0, modal.find('#new-reputation').val().length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$('.ban-user').on('click', function () {
|
$('.ban-user').on('click', function () {
|
||||||
const uids = getSelectedUids();
|
const uids = getSelectedUids();
|
||||||
if (!uids.length) {
|
if (!uids.length) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const groups = require('../../groups');
|
|||||||
const user = require('../../user');
|
const user = require('../../user');
|
||||||
const events = require('../../events');
|
const events = require('../../events');
|
||||||
const translator = require('../../translator');
|
const translator = require('../../translator');
|
||||||
|
const utils = require('../../utils');
|
||||||
const sockets = require('..');
|
const sockets = require('..');
|
||||||
|
|
||||||
const User = module.exports;
|
const User = module.exports;
|
||||||
@@ -146,6 +147,21 @@ User.loadGroups = async function (socket, uids) {
|
|||||||
return { users: userData };
|
return { users: userData };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
User.setReputation = async function (socket, data) {
|
||||||
|
if (!data || !Array.isArray(data.uids) || !utils.isNumber(data.value)) {
|
||||||
|
throw new Error('[[error:invalid-data]]');
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
db.setObjectBulk(
|
||||||
|
data.uids.map(uid => ([`user:${uid}`, { reputation: parseInt(data.value, 10) }]))
|
||||||
|
),
|
||||||
|
db.sortedSetAddBulk(
|
||||||
|
data.uids.map(uid => (['users:reputation', data.value, uid]))
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
User.exportUsersCSV = async function (socket) {
|
User.exportUsersCSV = async function (socket) {
|
||||||
await events.log({
|
await events.log({
|
||||||
type: 'exportUsersCSV',
|
type: 'exportUsersCSV',
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
<li><a href="#" class="dropdown-item rounded-1 password-reset-email"><i class="fa fa-fw fa-key"></i> [[admin/manage/users:password-reset-email]]</a></li>
|
<li><a href="#" class="dropdown-item rounded-1 password-reset-email"><i class="fa fa-fw fa-key"></i> [[admin/manage/users:password-reset-email]]</a></li>
|
||||||
<li><a href="#" class="dropdown-item rounded-1 force-password-reset"><i class="fa fa-fw fa-unlock-alt"></i> [[admin/manage/users:force-password-reset]]</a></li>
|
<li><a href="#" class="dropdown-item rounded-1 force-password-reset"><i class="fa fa-fw fa-unlock-alt"></i> [[admin/manage/users:force-password-reset]]</a></li>
|
||||||
<li><a href="#" class="dropdown-item rounded-1 manage-groups"><i class="fa fa-fw fa-users"></i> [[admin/manage/users:manage-groups]]</a></li>
|
<li><a href="#" class="dropdown-item rounded-1 manage-groups"><i class="fa fa-fw fa-users"></i> [[admin/manage/users:manage-groups]]</a></li>
|
||||||
|
<li><a href="#" class="dropdown-item rounded-1 set-reputation"><i class="fa fa-fw fa-star"></i> [[admin/manage/users:set-reputation]]</a></li>
|
||||||
<li class="dropdown-divider"></li>
|
<li class="dropdown-divider"></li>
|
||||||
<li><a href="#" class="dropdown-item rounded-1 ban-user"><i class="fa fa-fw fa-gavel"></i> [[admin/manage/users:ban]]</a></li>
|
<li><a href="#" class="dropdown-item rounded-1 ban-user"><i class="fa fa-fw fa-gavel"></i> [[admin/manage/users:ban]]</a></li>
|
||||||
<li><a href="#" class="dropdown-item rounded-1 ban-user-temporary"><i class="fa fa-fw fa-clock-o"></i> [[admin/manage/users:temp-ban]]</a></li>
|
<li><a href="#" class="dropdown-item rounded-1 ban-user-temporary"><i class="fa fa-fw fa-clock-o"></i> [[admin/manage/users:temp-ban]]</a></li>
|
||||||
@@ -152,7 +153,7 @@
|
|||||||
{{{ end }}}
|
{{{ end }}}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-end">{formattedNumber(users.postcount)}</td>
|
<td class="text-end">{formattedNumber(users.postcount)}</td>
|
||||||
<td class="text-end">{formattedNumber(users.reputation)}</td>
|
<td class="text-end" component="user/reputation" data-uid="{users.uid}">{formattedNumber(users.reputation)}</td>
|
||||||
<td class="text-end">{{{ if users.flags }}}{users.flags}{{{ else }}}0{{{ end }}}</td>
|
<td class="text-end">{{{ if users.flags }}}{users.flags}{{{ else }}}0{{{ end }}}</td>
|
||||||
<td><span class="timeago" title="{users.joindateISO}"></span></td>
|
<td><span class="timeago" title="{users.joindateISO}"></span></td>
|
||||||
<td><span class="timeago" title="{users.lastonlineISO}"></span></td>
|
<td><span class="timeago" title="{users.lastonlineISO}"></span></td>
|
||||||
|
|||||||
Reference in New Issue
Block a user