feat: show ip on acp manage users

update url on search
show matching ip when searching by ip
add ip to export csv
v1.18.x
Barış Soner Uşaklı 4 years ago
parent 6695927ea9
commit 8ea58432c9

@ -47,6 +47,7 @@
"users.uid": "uid",
"users.username": "username",
"users.email": "email",
"users.ip": "IP",
"users.postcount": "postcount",
"users.reputation": "reputation",
"users.flags": "flags",

@ -426,7 +426,15 @@ define('admin/manage/users', [
params.page = query.page;
params.sortBy = params.sortBy || 'lastonline';
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) {
app.alertError(xhrErr.responseJSON.error);
}

@ -147,7 +147,11 @@ usersController.search = async function (req, res) {
const uids = searchData.users.map(user => user && user.uid);
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.page = page;
searchData.resultsPerPage = resultsPerPage;
@ -157,10 +161,14 @@ usersController.search = async function (req, res) {
};
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.getUsersWithFields(uids, userFields, callerUid),
db.sortedSetScores('users:online', uids),
getIPs(),
]);
userData.forEach((user, index) => {
if (user) {
@ -169,6 +177,8 @@ async function loadUserInfo(callerUid, uids) {
const timestamp = lastonline[index] || user.joindate;
user.lastonline = timestamp;
user.lastonlineISO = utils.toISOString(timestamp);
user.ips = ips[index];
user.ip = ips[index] && ips[index][0] ? ips[index][0] : null;
}
});
return userData;

@ -55,12 +55,14 @@ module.exports = function (User) {
path.join(baseDir, 'build/export', 'users.csv'),
'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) => {
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 = '';
usersData.forEach((user) => {
line += `${data.fields.map(field => user[field]).join(',')}\n`;
usersData.forEach((user, index) => {
const userIPs = ips[index] ? ips[index].join(',') : '';
line += `${data.fields.map(field => user[field]).join(',')},"${userIPs}"\n`;
});
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-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.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="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>
@ -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="notvalidated fa fa-check text-muted<!-- IF users.email:confirmed --> hidden<!-- ENDIF users.email:confirmed -->" title="not validated"></i>
{users.email}</td>
<td>{users.ip}</td>
<td class="text-right">{users.postcount}</td>
<td class="text-right">{users.reputation}</td>
<td class="text-right"><!-- IF users.flags -->{users.flags}<!-- ELSE -->0<!-- ENDIF users.flags --></td>

Loading…
Cancel
Save