v1.18.x
Barış Soner Uşaklı 6 years ago
commit 7bc69e9182

@ -13,6 +13,11 @@ define('admin/advanced/events', function () {
$('.events-list').empty();
});
});
$('#filter').on('change', function () {
var filter = $(this).val();
ajaxify.go('admin/advanced/events' + (filter ? '?filter=' + filter : ''));
});
};
return Events;

@ -14,24 +14,35 @@ eventsController.get = function (req, res, next) {
var start = (page - 1) * itemsPerPage;
var stop = start + itemsPerPage - 1;
var currentFilter = req.query.filter || '';
async.waterfall([
function (next) {
async.parallel({
eventCount: function (next) {
db.sortedSetCard('events:time', next);
db.sortedSetCard('events:time' + (currentFilter ? ':' + currentFilter : ''), next);
},
events: function (next) {
events.getEvents(start, stop, next);
events.getEvents(currentFilter, start, stop, next);
},
}, next);
},
function (results) {
var types = [''].concat(events.types);
var filters = types.map(function (type) {
return {
value: type,
name: type || 'all',
selected: type === currentFilter,
};
});
var pageCount = Math.max(1, Math.ceil(results.eventCount / itemsPerPage));
res.render('admin/advanced/events', {
events: results.events,
pagination: pagination.create(page, pageCount),
next: 20,
pagination: pagination.create(page, pageCount, req.query),
filters: filters,
});
},
], next);

@ -4,6 +4,7 @@
var async = require('async');
var validator = require('validator');
var winston = require('winston');
var _ = require('lodash');
var db = require('./database');
var batch = require('./batch');
@ -12,6 +13,39 @@ var utils = require('./utils');
var events = module.exports;
events.types = [
'plugin-activate',
'plugin-deactivate',
'restart',
'build',
'config-change',
'settings-change',
'category-purge',
'privilege-change',
'post-delete',
'post-restore',
'post-purge',
'topic-delete',
'topic-restore',
'topic-purge',
'topic-rename',
'password-reset',
'user-ban',
'user-unban',
'user-delete',
'password-change',
'email-change',
'username-change',
'registration-approved',
'registration-rejected',
'accept-membership',
'reject-membership',
'theme-set',
'export:uploads',
'account-locked',
'getUsersCSV',
];
/**
* Useful options in data: type, uid, ip, targetUid
* Everything else gets stringified and shown as pretty JSON string
@ -31,6 +65,9 @@ events.log = function (data, callback) {
function (next) {
db.sortedSetAdd('events:time', data.timestamp, eid, next);
},
function (next) {
db.sortedSetAdd('events:time:' + data.type, data.timestamp, eid, next);
},
function (next) {
db.setObject('event:' + eid, data, next);
},
@ -41,10 +78,10 @@ events.log = function (data, callback) {
});
};
events.getEvents = function (start, stop, callback) {
events.getEvents = function (filter, start, stop, callback) {
async.waterfall([
function (next) {
db.getSortedSetRevRange('events:time', start, stop, next);
db.getSortedSetRevRange('events:time' + (filter ? ':' + filter : ''), start, stop, next);
},
function (eids, next) {
var keys = eids.map(function (eid) {
@ -123,15 +160,24 @@ function addUserData(eventsData, field, objectName, callback) {
events.deleteEvents = function (eids, callback) {
callback = callback || function () {};
async.parallel([
var keys;
async.waterfall([
function (next) {
var keys = eids.map(function (eid) {
keys = eids.map(function (eid) {
return 'event:' + eid;
});
db.getObjectsFields(keys, ['type'], next);
},
function (eventData, next) {
var sets = _.uniq(['events:time'].concat(eventData.map(e => 'events:time:' + e.type)));
async.parallel([
function (next) {
db.deleteAll(keys, next);
},
function (next) {
db.sortedSetRemove('events:time', eids, next);
db.sortedSetRemove(sets, eids, next);
},
], next);
},
], callback);
};
@ -146,7 +192,7 @@ events.deleteAll = function (callback) {
events.output = function () {
console.log('\nDisplaying last ten administrative events...'.bold);
events.getEvents(0, 9, function (err, events) {
events.getEvents('', 0, 9, function (err, events) {
if (err) {
winston.error('Error fetching events', err);
throw err;

@ -84,8 +84,10 @@ Categories.setPrivilege = function (socket, data, callback) {
function onSetComplete() {
events.log({
uid: socket.uid,
type: 'privilege-change',
ip: socket.ip,
privilege: data.privilege.toString(),
cid: data.cid,
action: data.set ? 'grant' : 'rescind',
target: data.member,
}, callback);

@ -0,0 +1,46 @@
'use strict';
var db = require('../../database');
var async = require('async');
var batch = require('../../batch');
module.exports = {
name: 'add filters to events',
timestamp: Date.UTC(2018, 9, 4),
method: function (callback) {
const progress = this.progress;
batch.processSortedSet('events:time', function (eids, next) {
async.eachSeries(eids, function (eid, next) {
progress.incr();
db.getObject('event:' + eid, function (err, eventData) {
if (err) {
return next(err);
}
if (!eventData) {
return db.sortedSetRemove('events:time', eid, next);
}
// privilege events we're missing type field
if (!eventData.type && eventData.privilege) {
eventData.type = 'privilege-change';
async.waterfall([
function (next) {
db.setObjectField('event:' + eid, 'type', 'privilege-change', next);
},
function (next) {
db.sortedSetAdd('events:time:' + eventData.type, eventData.timestamp, eid, next);
},
], next);
return;
}
db.sortedSetAdd('events:time:' + (eventData.type || ''), eventData.timestamp, eid, next);
});
}, next);
}, {
progress: this.progress,
}, callback);
},
};

@ -1,8 +1,13 @@
<div class="row events">
<div class="col-lg-9">
<select id="filter" class="form-control">
<!-- BEGIN filters -->
<option value="{filters.value}" <!-- IF filters.selected -->selected<!-- ENDIF filters.selected -->>{filters.name}</option>
<!-- END filters -->
</select>
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fa-calendar-o"></i> [[admin/advanced/events:events]]</div>
<div class="panel-body" data-next="{next}">
<div class="panel-body">
<!-- IF !events.length -->
<div class="alert alert-info">[[admin/advanced/events:no-events]]</div>
<!-- ENDIF !events.length -->

Loading…
Cancel
Save