mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-02-26 16:41:21 +01:00
feat: show ip on acp manage users
update url on search show matching ip when searching by ip add ip to export csv
This commit is contained in:
@@ -47,6 +47,7 @@
|
|||||||
"users.uid": "uid",
|
"users.uid": "uid",
|
||||||
"users.username": "username",
|
"users.username": "username",
|
||||||
"users.email": "email",
|
"users.email": "email",
|
||||||
|
"users.ip": "IP",
|
||||||
"users.postcount": "postcount",
|
"users.postcount": "postcount",
|
||||||
"users.reputation": "reputation",
|
"users.reputation": "reputation",
|
||||||
"users.flags": "flags",
|
"users.flags": "flags",
|
||||||
|
|||||||
@@ -426,7 +426,15 @@ define('admin/manage/users', [
|
|||||||
params.page = query.page;
|
params.page = query.page;
|
||||||
params.sortBy = params.sortBy || 'lastonline';
|
params.sortBy = params.sortBy || 'lastonline';
|
||||||
var qs = decodeURIComponent($.param(params));
|
var qs = decodeURIComponent($.param(params));
|
||||||
$.get(config.relative_path + '/api/admin/manage/users?' + qs, renderSearchResults).fail(function (xhrErr) {
|
$.get(config.relative_path + '/api/admin/manage/users?' + qs, function (data) {
|
||||||
|
renderSearchResults(data);
|
||||||
|
const url = config.relative_path + '/admin/manage/users?' + qs;
|
||||||
|
if (history.pushState) {
|
||||||
|
history.pushState({
|
||||||
|
url: url,
|
||||||
|
}, null, window.location.protocol + '//' + window.location.host + url);
|
||||||
|
}
|
||||||
|
}).fail(function (xhrErr) {
|
||||||
if (xhrErr && xhrErr.responseJSON && xhrErr.responseJSON.error) {
|
if (xhrErr && xhrErr.responseJSON && xhrErr.responseJSON.error) {
|
||||||
app.alertError(xhrErr.responseJSON.error);
|
app.alertError(xhrErr.responseJSON.error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,7 +147,11 @@ usersController.search = async function (req, res) {
|
|||||||
|
|
||||||
const uids = searchData.users.map(user => user && user.uid);
|
const uids = searchData.users.map(user => user && user.uid);
|
||||||
searchData.users = await loadUserInfo(req.uid, uids);
|
searchData.users = await loadUserInfo(req.uid, uids);
|
||||||
|
if (req.query.searchBy === 'ip') {
|
||||||
|
searchData.users.forEach((user) => {
|
||||||
|
user.ip = user.ips.find(ip => ip.includes(String(req.query.query)));
|
||||||
|
});
|
||||||
|
}
|
||||||
searchData.query = validator.escape(String(req.query.query || ''));
|
searchData.query = validator.escape(String(req.query.query || ''));
|
||||||
searchData.page = page;
|
searchData.page = page;
|
||||||
searchData.resultsPerPage = resultsPerPage;
|
searchData.resultsPerPage = resultsPerPage;
|
||||||
@@ -157,10 +161,14 @@ usersController.search = async function (req, res) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function loadUserInfo(callerUid, uids) {
|
async function loadUserInfo(callerUid, uids) {
|
||||||
const [isAdmin, userData, lastonline] = await Promise.all([
|
async function getIPs() {
|
||||||
|
return await Promise.all(uids.map(uid => db.getSortedSetRevRange(`uid:${uid}:ip`, 0, -1)));
|
||||||
|
}
|
||||||
|
const [isAdmin, userData, lastonline, ips] = await Promise.all([
|
||||||
user.isAdministrator(uids),
|
user.isAdministrator(uids),
|
||||||
user.getUsersWithFields(uids, userFields, callerUid),
|
user.getUsersWithFields(uids, userFields, callerUid),
|
||||||
db.sortedSetScores('users:online', uids),
|
db.sortedSetScores('users:online', uids),
|
||||||
|
getIPs(),
|
||||||
]);
|
]);
|
||||||
userData.forEach((user, index) => {
|
userData.forEach((user, index) => {
|
||||||
if (user) {
|
if (user) {
|
||||||
@@ -169,6 +177,8 @@ async function loadUserInfo(callerUid, uids) {
|
|||||||
const timestamp = lastonline[index] || user.joindate;
|
const timestamp = lastonline[index] || user.joindate;
|
||||||
user.lastonline = timestamp;
|
user.lastonline = timestamp;
|
||||||
user.lastonlineISO = utils.toISOString(timestamp);
|
user.lastonlineISO = utils.toISOString(timestamp);
|
||||||
|
user.ips = ips[index];
|
||||||
|
user.ip = ips[index] && ips[index][0] ? ips[index][0] : null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return userData;
|
return userData;
|
||||||
|
|||||||
@@ -55,12 +55,14 @@ module.exports = function (User) {
|
|||||||
path.join(baseDir, 'build/export', 'users.csv'),
|
path.join(baseDir, 'build/export', 'users.csv'),
|
||||||
'w'
|
'w'
|
||||||
);
|
);
|
||||||
fs.promises.appendFile(fd, `${data.fields.join(',')}\n`);
|
fs.promises.appendFile(fd, `${data.fields.join(',')},ip\n`);
|
||||||
await batch.processSortedSet('users:joindate', async (uids) => {
|
await batch.processSortedSet('users:joindate', async (uids) => {
|
||||||
const usersData = await User.getUsersFields(uids, data.fields.slice());
|
const usersData = await User.getUsersFields(uids, data.fields.slice());
|
||||||
|
const ips = await Promise.all(uids.map(uid => db.getSortedSetRevRange(`uid:${uid}:ip`, 0, -1)));
|
||||||
let line = '';
|
let line = '';
|
||||||
usersData.forEach((user) => {
|
usersData.forEach((user, index) => {
|
||||||
line += `${data.fields.map(field => user[field]).join(',')}\n`;
|
const userIPs = ips[index] ? ips[index].join(',') : '';
|
||||||
|
line += `${data.fields.map(field => user[field]).join(',')},"${userIPs}"\n`;
|
||||||
});
|
});
|
||||||
|
|
||||||
await fs.promises.appendFile(fd, line);
|
await fs.promises.appendFile(fd, line);
|
||||||
|
|||||||
@@ -89,6 +89,7 @@
|
|||||||
<th class="text-right text-muted">[[admin/manage/users:users.uid]]</th>
|
<th class="text-right text-muted">[[admin/manage/users:users.uid]]</th>
|
||||||
<th class="text-muted">[[admin/manage/users:users.username]]</th>
|
<th class="text-muted">[[admin/manage/users:users.username]]</th>
|
||||||
<th class="text-muted">[[admin/manage/users:users.email]]</th>
|
<th class="text-muted">[[admin/manage/users:users.email]]</th>
|
||||||
|
<th class="text-muted">[[admin/manage/users:users.ip]]</th>
|
||||||
<th data-sort="postcount" class="text-right pointer">[[admin/manage/users:users.postcount]] {{{if sort_postcount}}}<i class="fa fa-sort-{{{if reverse}}}down{{{else}}}up{{{end}}}">{{{end}}}</th>
|
<th data-sort="postcount" class="text-right pointer">[[admin/manage/users:users.postcount]] {{{if sort_postcount}}}<i class="fa fa-sort-{{{if reverse}}}down{{{else}}}up{{{end}}}">{{{end}}}</th>
|
||||||
<th data-sort="reputation" class="text-right pointer">[[admin/manage/users:users.reputation]] {{{if sort_reputation}}}<i class="fa fa-sort-{{{if reverse}}}down{{{else}}}up{{{end}}}">{{{end}}}</th>
|
<th data-sort="reputation" class="text-right pointer">[[admin/manage/users:users.reputation]] {{{if sort_reputation}}}<i class="fa fa-sort-{{{if reverse}}}down{{{else}}}up{{{end}}}">{{{end}}}</th>
|
||||||
<th data-sort="flags" class="text-right pointer">[[admin/manage/users:users.flags]] {{{if sort_flags}}}<i class="fa fa-sort-{{{if reverse}}}down{{{else}}}up{{{end}}}">{{{end}}}</th>
|
<th data-sort="flags" class="text-right pointer">[[admin/manage/users:users.flags]] {{{if sort_flags}}}<i class="fa fa-sort-{{{if reverse}}}down{{{else}}}up{{{end}}}">{{{end}}}</th>
|
||||||
@@ -107,6 +108,7 @@
|
|||||||
<i class="validated fa fa-check text-success<!-- IF !users.email:confirmed --> hidden<!-- ENDIF !users.email:confirmed -->" title="validated"></i>
|
<i class="validated fa fa-check text-success<!-- IF !users.email:confirmed --> hidden<!-- ENDIF !users.email:confirmed -->" title="validated"></i>
|
||||||
<i class="notvalidated fa fa-check text-muted<!-- IF users.email:confirmed --> hidden<!-- ENDIF users.email:confirmed -->" title="not validated"></i>
|
<i class="notvalidated fa fa-check text-muted<!-- IF users.email:confirmed --> hidden<!-- ENDIF users.email:confirmed -->" title="not validated"></i>
|
||||||
{users.email}</td>
|
{users.email}</td>
|
||||||
|
<td>{users.ip}</td>
|
||||||
<td class="text-right">{users.postcount}</td>
|
<td class="text-right">{users.postcount}</td>
|
||||||
<td class="text-right">{users.reputation}</td>
|
<td class="text-right">{users.reputation}</td>
|
||||||
<td class="text-right"><!-- IF users.flags -->{users.flags}<!-- ELSE -->0<!-- ENDIF users.flags --></td>
|
<td class="text-right"><!-- IF users.flags -->{users.flags}<!-- ELSE -->0<!-- ENDIF users.flags --></td>
|
||||||
|
|||||||
Reference in New Issue
Block a user