mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: change user search to use filters array
This commit is contained in:
@@ -493,8 +493,8 @@ define('admin/manage/users', [
|
|||||||
params.query = $('#user-search').val();
|
params.query = $('#user-search').val();
|
||||||
params.searchBy = $('#user-search-by').val();
|
params.searchBy = $('#user-search-by').val();
|
||||||
} else {
|
} else {
|
||||||
params.query = undefined;
|
delete params.query;
|
||||||
params.searchBy = undefined;
|
delete params.searchBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
return decodeURIComponent($.param(params));
|
return decodeURIComponent($.param(params));
|
||||||
@@ -520,7 +520,6 @@ define('admin/manage/users', [
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFilter() {
|
|
||||||
function getFilters() {
|
function getFilters() {
|
||||||
var filters = [];
|
var filters = [];
|
||||||
$('#filter-by').find('[data-filter-by]').each(function () {
|
$('#filter-by').find('[data-filter-by]').each(function () {
|
||||||
@@ -531,6 +530,7 @@ define('admin/manage/users', [
|
|||||||
return filters;
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleFilter() {
|
||||||
var currentFilters = getFilters();
|
var currentFilters = getFilters();
|
||||||
$('#filter-by').on('click', 'li', function () {
|
$('#filter-by').on('click', 'li', function () {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
@@ -551,7 +551,7 @@ define('admin/manage/users', [
|
|||||||
currentFilters = getFilters();
|
currentFilters = getFilters();
|
||||||
if (changed) {
|
if (changed) {
|
||||||
var params = utils.params();
|
var params = utils.params();
|
||||||
params.filter = filters;
|
params.filters = filters;
|
||||||
var qs = buildSearchQuery(params);
|
var qs = buildSearchQuery(params);
|
||||||
ajaxify.go('admin/manage/users?' + qs);
|
ajaxify.go('admin/manage/users?' + qs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ define('forum/topic/change-owner', [
|
|||||||
changeOwner();
|
changeOwner();
|
||||||
});
|
});
|
||||||
|
|
||||||
autocomplete.user(modal.find('#username'), { notBanned: true }, function (ev, ui) {
|
autocomplete.user(modal.find('#username'), { filters: ['notbanned'] }, function (ev, ui) {
|
||||||
toUid = ui.item.user.uid;
|
toUid = ui.item.user.uid;
|
||||||
checkButtonEnable();
|
checkButtonEnable();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -61,17 +61,20 @@ define('forum/users', ['translator', 'benchpress'], function (translator, Benchp
|
|||||||
return loadPage(query);
|
return loadPage(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
query.term = username;
|
query.query = username;
|
||||||
query.sortBy = getSortBy();
|
query.sortBy = getSortBy();
|
||||||
|
var filters = [];
|
||||||
if ($('.search .online-only').is(':checked') || (activeSection === 'online')) {
|
if ($('.search .online-only').is(':checked') || (activeSection === 'online')) {
|
||||||
query.onlineOnly = true;
|
filters.push('online');
|
||||||
}
|
}
|
||||||
if (activeSection === 'banned') {
|
if (activeSection === 'banned') {
|
||||||
query.bannedOnly = true;
|
filters.push('banned');
|
||||||
}
|
}
|
||||||
if (activeSection === 'flagged') {
|
if (activeSection === 'flagged') {
|
||||||
query.flaggedOnly = true;
|
filters.push('flagged');
|
||||||
|
}
|
||||||
|
if (filters.length) {
|
||||||
|
query.filters = filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPage(query);
|
loadPage(query);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ async function getUsers(req, res) {
|
|||||||
resultsPerPage = 50;
|
resultsPerPage = 50;
|
||||||
}
|
}
|
||||||
let sortBy = validator.escape(req.query.sortBy || '');
|
let sortBy = validator.escape(req.query.sortBy || '');
|
||||||
const filterBy = Array.isArray(req.query.filter) ? req.query.filter : [req.query.filter];
|
const filterBy = Array.isArray(req.query.filters) ? req.query.filters : [req.query.filters];
|
||||||
const start = Math.max(0, page - 1) * resultsPerPage;
|
const start = Math.max(0, page - 1) * resultsPerPage;
|
||||||
const stop = start + resultsPerPage - 1;
|
const stop = start + resultsPerPage - 1;
|
||||||
|
|
||||||
@@ -129,12 +129,14 @@ usersController.search = async function (req, res) {
|
|||||||
if (![50, 100, 250, 500].includes(resultsPerPage)) {
|
if (![50, 100, 250, 500].includes(resultsPerPage)) {
|
||||||
resultsPerPage = 50;
|
resultsPerPage = 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchData = await user.search({
|
const searchData = await user.search({
|
||||||
uid: req.uid,
|
uid: req.uid,
|
||||||
query: req.query.query,
|
query: req.query.query,
|
||||||
searchBy: req.query.searchBy,
|
searchBy: req.query.searchBy,
|
||||||
sortBy: req.query.sortBy,
|
sortBy: req.query.sortBy,
|
||||||
sortDirection: sortDirection,
|
sortDirection: sortDirection,
|
||||||
|
filters: req.query.filters,
|
||||||
page: page,
|
page: page,
|
||||||
resultsPerPage: resultsPerPage,
|
resultsPerPage: resultsPerPage,
|
||||||
findUids: async function (query, searchBy, hardCap) {
|
findUids: async function (query, searchBy, hardCap) {
|
||||||
@@ -229,7 +231,7 @@ function render(req, res, data) {
|
|||||||
data.adminInviteOnly = registrationType === 'admin-invite-only';
|
data.adminInviteOnly = registrationType === 'admin-invite-only';
|
||||||
data['sort_' + data.sortBy] = true;
|
data['sort_' + data.sortBy] = true;
|
||||||
data['searchBy_' + validator.escape(String(req.query.searchBy))] = true;
|
data['searchBy_' + validator.escape(String(req.query.searchBy))] = true;
|
||||||
const filterBy = Array.isArray(req.query.filter) ? req.query.filter : [req.query.filter];
|
const filterBy = Array.isArray(req.query.filters) ? req.query.filters : [req.query.filters];
|
||||||
filterBy.forEach(function (filter) {
|
filterBy.forEach(function (filter) {
|
||||||
data['filterBy_' + validator.escape(String(filter))] = true;
|
data['filterBy_' + validator.escape(String(filter))] = true;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ usersController.index = async function (req, res, next) {
|
|||||||
flagged: usersController.getFlaggedUsers,
|
flagged: usersController.getFlaggedUsers,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (req.query.term) {
|
if (req.query.query) {
|
||||||
await usersController.search(req, res, next);
|
await usersController.search(req, res, next);
|
||||||
} else if (sectionToController[section]) {
|
} else if (sectionToController[section]) {
|
||||||
await sectionToController[section](req, res, next);
|
await sectionToController[section](req, res, next);
|
||||||
@@ -35,19 +35,25 @@ usersController.search = async function (req, res) {
|
|||||||
privileges.global.can('search:users', req.uid),
|
privileges.global.can('search:users', req.uid),
|
||||||
user.isPrivileged(req.uid),
|
user.isPrivileged(req.uid),
|
||||||
]);
|
]);
|
||||||
|
let filters = req.query.filters || [];
|
||||||
if (!allowed || ((req.query.searchBy === 'ip' || req.query.searchBy === 'email' || req.query.bannedOnly === 'true' || req.query.flaggedOnly === 'true') && !isPrivileged)) {
|
filters = Array.isArray(filters) ? filters : [filters];
|
||||||
|
if (!allowed ||
|
||||||
|
((
|
||||||
|
req.query.searchBy === 'ip' ||
|
||||||
|
req.query.searchBy === 'email' ||
|
||||||
|
filters.includes('banned') ||
|
||||||
|
filters.includes('flagged')
|
||||||
|
) && !isPrivileged)
|
||||||
|
) {
|
||||||
throw new Error('[[error:no-privileges]]');
|
throw new Error('[[error:no-privileges]]');
|
||||||
}
|
}
|
||||||
const [searchData, isAdminOrGlobalMod] = await Promise.all([
|
const [searchData, isAdminOrGlobalMod] = await Promise.all([
|
||||||
user.search({
|
user.search({
|
||||||
query: req.query.term,
|
query: req.query.query,
|
||||||
searchBy: req.query.searchBy || 'username',
|
searchBy: req.query.searchBy || 'username',
|
||||||
page: req.query.page || 1,
|
page: req.query.page || 1,
|
||||||
sortBy: req.query.sortBy || 'joindate',
|
sortBy: req.query.sortBy || 'joindate',
|
||||||
onlineOnly: req.query.onlineOnly === 'true',
|
filters: filters,
|
||||||
bannedOnly: req.query.bannedOnly === 'true',
|
|
||||||
flaggedOnly: req.query.flaggedOnly === 'true',
|
|
||||||
}),
|
}),
|
||||||
user.isAdminOrGlobalMod(req.uid),
|
user.isAdminOrGlobalMod(req.uid),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const privileges = require('../../privileges');
|
|||||||
|
|
||||||
module.exports = function (SocketUser) {
|
module.exports = function (SocketUser) {
|
||||||
SocketUser.search = async function (socket, data) {
|
SocketUser.search = async function (socket, data) {
|
||||||
|
// TODO: depracate and use usersController.search
|
||||||
if (!data) {
|
if (!data) {
|
||||||
throw new Error('[[error:invalid-data]]');
|
throw new Error('[[error:invalid-data]]');
|
||||||
}
|
}
|
||||||
@@ -14,7 +15,16 @@ module.exports = function (SocketUser) {
|
|||||||
user.isPrivileged(socket.uid),
|
user.isPrivileged(socket.uid),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!allowed || ((data.searchBy === 'ip' || data.searchBy === 'email' || data.bannedOnly || data.flaggedOnly) && !isPrivileged)) {
|
let filters = data.filters || [];
|
||||||
|
filters = Array.isArray(filters) ? filters : [filters];
|
||||||
|
if (!allowed ||
|
||||||
|
((
|
||||||
|
data.searchBy === 'ip' ||
|
||||||
|
data.searchBy === 'email' ||
|
||||||
|
filters.includes('banned') ||
|
||||||
|
filters.includes('flagged')
|
||||||
|
) && !isPrivileged)
|
||||||
|
) {
|
||||||
throw new Error('[[error:no-privileges]]');
|
throw new Error('[[error:no-privileges]]');
|
||||||
}
|
}
|
||||||
const result = await user.search({
|
const result = await user.search({
|
||||||
@@ -22,10 +32,7 @@ module.exports = function (SocketUser) {
|
|||||||
page: data.page,
|
page: data.page,
|
||||||
searchBy: data.searchBy,
|
searchBy: data.searchBy,
|
||||||
sortBy: data.sortBy,
|
sortBy: data.sortBy,
|
||||||
onlineOnly: data.onlineOnly,
|
filters: data.filters,
|
||||||
bannedOnly: data.bannedOnly,
|
|
||||||
notBanned: data.notBanned,
|
|
||||||
flaggedOnly: data.flaggedOnly,
|
|
||||||
paginate: data.paginate,
|
paginate: data.paginate,
|
||||||
uid: socket.uid,
|
uid: socket.uid,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,6 +10,25 @@ const groups = require('../groups');
|
|||||||
const utils = require('../utils');
|
const utils = require('../utils');
|
||||||
|
|
||||||
module.exports = function (User) {
|
module.exports = function (User) {
|
||||||
|
const filterFnMap = {
|
||||||
|
online: user => user.status !== 'offline' && (Date.now() - user.lastonline < 300000),
|
||||||
|
banned: user => user.banned,
|
||||||
|
notbanned: user => !user.banned,
|
||||||
|
flagged: user => parseInt(user.flags, 10) > 0,
|
||||||
|
verified: user => !!user['email:confirmed'],
|
||||||
|
unverified: user => !user['email:confirmed'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const filterFieldMap = {
|
||||||
|
online: ['status', 'lastonline'],
|
||||||
|
banned: ['banned'],
|
||||||
|
notbanned: ['banned'],
|
||||||
|
flagged: ['flags'],
|
||||||
|
verified: ['email:confirmed'],
|
||||||
|
unverified: ['email:confirmed'],
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
User.search = async function (data) {
|
User.search = async function (data) {
|
||||||
const query = data.query || '';
|
const query = data.query || '';
|
||||||
const searchBy = data.searchBy || 'username';
|
const searchBy = data.searchBy || 'username';
|
||||||
@@ -69,21 +88,19 @@ module.exports = function (User) {
|
|||||||
|
|
||||||
async function filterAndSortUids(uids, data) {
|
async function filterAndSortUids(uids, data) {
|
||||||
uids = uids.filter(uid => parseInt(uid, 10));
|
uids = uids.filter(uid => parseInt(uid, 10));
|
||||||
|
let filters = data.filters || [];
|
||||||
|
filters = Array.isArray(filters) ? filters : [data.filters];
|
||||||
const fields = [];
|
const fields = [];
|
||||||
|
|
||||||
if (data.sortBy) {
|
if (data.sortBy) {
|
||||||
fields.push(data.sortBy);
|
fields.push(data.sortBy);
|
||||||
}
|
}
|
||||||
if (data.onlineOnly) {
|
|
||||||
fields.push('status', 'lastonline');
|
filters.forEach(function (filter) {
|
||||||
}
|
if (filterFieldMap[filter]) {
|
||||||
if (data.bannedOnly || data.notBanned) {
|
fields.push(...filterFieldMap[filter]);
|
||||||
fields.push('banned');
|
|
||||||
}
|
|
||||||
if (data.flaggedOnly) {
|
|
||||||
fields.push('flags');
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (data.groupName) {
|
if (data.groupName) {
|
||||||
const isMembers = await groups.isMembers(uids, data.groupName);
|
const isMembers = await groups.isMembers(uids, data.groupName);
|
||||||
@@ -96,21 +113,12 @@ module.exports = function (User) {
|
|||||||
|
|
||||||
fields.push('uid');
|
fields.push('uid');
|
||||||
let userData = await User.getUsersFields(uids, fields);
|
let userData = await User.getUsersFields(uids, fields);
|
||||||
if (data.onlineOnly) {
|
|
||||||
userData = userData.filter(user => user.status !== 'offline' && (Date.now() - user.lastonline < 300000));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.bannedOnly) {
|
filters.forEach(function (filter) {
|
||||||
userData = userData.filter(user => user.banned);
|
if (filterFnMap[filter]) {
|
||||||
}
|
userData = userData.filter(filterFnMap[filter]);
|
||||||
|
|
||||||
if (data.notBanned) {
|
|
||||||
userData = userData.filter(user => !user.banned);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.flaggedOnly) {
|
|
||||||
userData = userData.filter(user => parseInt(user.flags, 10) > 0);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (data.sortBy) {
|
if (data.sortBy) {
|
||||||
sortUsers(userData, data.sortBy, data.sortDirection);
|
sortUsers(userData, data.sortBy, data.sortDirection);
|
||||||
|
|||||||
@@ -369,14 +369,14 @@ describe('User', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should error for unprivileged user', function (done) {
|
it('should error for unprivileged user', function (done) {
|
||||||
socketUser.search({ uid: testUid }, { bannedOnly: true, query: '123' }, function (err) {
|
socketUser.search({ uid: testUid }, { filters: ['banned'], query: '123' }, function (err) {
|
||||||
assert.equal(err.message, '[[error:no-privileges]]');
|
assert.equal(err.message, '[[error:no-privileges]]');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should error for unprivileged user', function (done) {
|
it('should error for unprivileged user', function (done) {
|
||||||
socketUser.search({ uid: testUid }, { flaggedOnly: true, query: '123' }, function (err) {
|
socketUser.search({ uid: testUid }, { filters: ['flagged'], query: '123' }, function (err) {
|
||||||
assert.equal(err.message, '[[error:no-privileges]]');
|
assert.equal(err.message, '[[error:no-privileges]]');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -430,9 +430,7 @@ describe('User', function () {
|
|||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
socketUser.search({ uid: adminUid }, {
|
socketUser.search({ uid: adminUid }, {
|
||||||
query: 'ipsearch',
|
query: 'ipsearch',
|
||||||
onlineOnly: true,
|
filters: ['online', 'banned', 'flagged'],
|
||||||
bannedOnly: true,
|
|
||||||
flaggedOnly: true,
|
|
||||||
}, function (err, data) {
|
}, function (err, data) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(data.users[0].username, 'ipsearch_filter');
|
assert.equal(data.users[0].username, 'ipsearch_filter');
|
||||||
|
|||||||
Reference in New Issue
Block a user