feat: #7743, events

v1.18.x
Barış Soner Uşaklı 6 years ago
parent 97d7a85060
commit 102d4b0247

@ -98,10 +98,19 @@ function listPlugins() {
} }
function listEvents(count) { function listEvents(count) {
async.series([ async.waterfall([
db.init, db.init,
async.apply(events.output, count), async.apply(events.getEvents, '', 0, (count || 10) - 1),
]); function (eventData) {
console.log(('\nDisplaying last ' + count + ' administrative events...').bold);
eventData.forEach(function (event) {
console.log(' * ' + String(event.timestampISO).green + ' ' + String(event.type).yellow + (event.text ? ' ' + event.text : '') + ' (uid: '.reset + (event.uid ? event.uid : 0) + ')');
});
process.exit();
},
], function (err) {
throw err;
});
} }
function info() { function info() {

@ -1,17 +1,15 @@
'use strict'; 'use strict';
var async = require('async'); const validator = require('validator');
var validator = require('validator'); const _ = require('lodash');
var winston = require('winston');
var _ = require('lodash');
var db = require('./database'); const db = require('./database');
var batch = require('./batch'); const batch = require('./batch');
var user = require('./user'); const user = require('./user');
var utils = require('./utils'); const utils = require('./utils');
var events = module.exports; const events = module.exports;
events.types = [ events.types = [
'plugin-activate', 'plugin-activate',
@ -55,163 +53,92 @@ events.types = [
* Useful options in data: type, uid, ip, targetUid * Useful options in data: type, uid, ip, targetUid
* Everything else gets stringified and shown as pretty JSON string * Everything else gets stringified and shown as pretty JSON string
*/ */
events.log = function (data, callback) { events.log = async function (data) {
callback = callback || function () {}; const eid = await db.incrObjectField('global', 'nextEid');
data.timestamp = Date.now();
async.waterfall([ data.eid = eid;
function (next) {
db.incrObjectField('global', 'nextEid', next); await Promise.all([
}, db.sortedSetsAdd([
function (eid, next) { 'events:time',
data.timestamp = Date.now(); 'events:time:' + data.type,
data.eid = eid; ], data.timestamp, eid),
db.setObject('event:' + eid, data),
async.parallel([ ]);
function (next) {
db.sortedSetsAdd([
'events:time',
'events:time:' + data.type,
], data.timestamp, eid, next);
},
function (next) {
db.setObject('event:' + eid, data, next);
},
], next);
},
], function (err) {
callback(err);
});
}; };
events.getEvents = function (filter, start, stop, from, to, callback) { events.getEvents = async function (filter, start, stop, from, to) {
// from/to optional // from/to optional
if (typeof from === 'function' && !to && !callback) { if (from === undefined) {
callback = from;
from = 0; from = 0;
}
if (to === undefined) {
to = Date.now(); to = Date.now();
} }
async.waterfall([ const eids = await db.getSortedSetRevRangeByScore('events:time' + (filter ? ':' + filter : ''), start, stop - start + 1, to, from);
function (next) { let eventsData = await db.getObjects(eids.map(eid => 'event:' + eid));
db.getSortedSetRevRangeByScore('events:time' + (filter ? ':' + filter : ''), start, stop - start + 1, to, from, next); eventsData = eventsData.filter(Boolean);
}, await addUserData(eventsData, 'uid', 'user');
function (eids, next) { await addUserData(eventsData, 'targetUid', 'targetUser');
db.getObjects(eids.map(eid => 'event:' + eid), next); eventsData.forEach(function (event) {
}, Object.keys(event).forEach(function (key) {
function (eventsData, next) { if (typeof event[key] === 'string') {
eventsData = eventsData.filter(Boolean); event[key] = validator.escape(String(event[key] || ''));
addUserData(eventsData, 'uid', 'user', next); }
}, });
function (eventsData, next) { var e = utils.merge(event);
addUserData(eventsData, 'targetUid', 'targetUser', next); e.eid = undefined;
}, e.uid = undefined;
function (eventsData, next) { e.type = undefined;
eventsData.forEach(function (event) { e.ip = undefined;
Object.keys(event).forEach(function (key) { e.user = undefined;
if (typeof event[key] === 'string') { event.jsonString = JSON.stringify(e, null, 4);
event[key] = validator.escape(String(event[key] || '')); event.timestampISO = new Date(parseInt(event.timestamp, 10)).toUTCString();
} });
}); return eventsData;
var e = utils.merge(event);
e.eid = undefined;
e.uid = undefined;
e.type = undefined;
e.ip = undefined;
e.user = undefined;
event.jsonString = JSON.stringify(e, null, 4);
event.timestampISO = new Date(parseInt(event.timestamp, 10)).toUTCString();
});
next(null, eventsData);
},
], callback);
}; };
function addUserData(eventsData, field, objectName, callback) { async function addUserData(eventsData, field, objectName) {
var uids = _.uniq(eventsData.map(event => event && event[field])); const uids = _.uniq(eventsData.map(event => event && event[field]));
if (!uids.length) { if (!uids.length) {
return callback(null, eventsData); return eventsData;
} }
async.waterfall([ const [isAdmin, userData] = await Promise.all([
function (next) { user.isAdministrator(uids),
async.parallel({ user.getUsersFields(uids, ['username', 'userslug', 'picture']),
isAdmin: function (next) { ]);
user.isAdministrator(uids, next);
},
userData: function (next) {
user.getUsersFields(uids, ['username', 'userslug', 'picture'], next);
},
}, next);
},
function (results, next) {
var userData = results.userData;
var map = {};
userData.forEach(function (user, index) {
user.isAdmin = results.isAdmin[index];
map[user.uid] = user;
});
eventsData.forEach(function (event) {
if (map[event[field]]) {
event[objectName] = map[event[field]];
}
});
next(null, eventsData);
},
], callback);
}
events.deleteEvents = function (eids, callback) { const map = {};
callback = callback || function () {}; userData.forEach(function (user, index) {
var keys; user.isAdmin = isAdmin[index];
async.waterfall([ map[user.uid] = user;
function (next) { });
keys = eids.map(eid => '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(sets, eids, next);
},
], next);
},
], callback);
};
events.deleteAll = function (callback) {
callback = callback || function () {};
batch.processSortedSet('events:time', function (eids, next) {
events.deleteEvents(eids, next);
}, { alwaysStartAt: 0 }, callback);
};
events.output = function (numEvents) {
numEvents = parseInt(numEvents, 10);
if (isNaN(numEvents)) {
numEvents = 10;
}
console.log(('\nDisplaying last ' + numEvents + ' administrative events...').bold); eventsData.forEach(function (event) {
events.getEvents('', 0, numEvents - 1, function (err, events) { if (map[event[field]]) {
if (err) { event[objectName] = map[event[field]];
winston.error('Error fetching events', err);
throw err;
} }
});
return eventsData;
}
events.forEach(function (event) { events.deleteEvents = async function (eids) {
console.log(' * ' + String(event.timestampISO).green + ' ' + String(event.type).yellow + (event.text ? ' ' + event.text : '') + ' (uid: '.reset + (event.uid ? event.uid : 0) + ')'); const keys = eids.map(eid => 'event:' + eid);
}); const eventData = await db.getObjectsFields(keys, ['type']);
const sets = _.uniq(['events:time'].concat(eventData.map(e => 'events:time:' + e.type)));
await Promise.all([
db.deleteAll(keys),
db.sortedSetRemove(sets, eids),
]);
};
process.exit(0); events.deleteAll = async function () {
}); await batch.processSortedSet('events:time', async function (eids) {
await events.deleteEvents(eids);
}, { alwaysStartAt: 0, batch: 500 });
}; };
require('./promisify')(events); require('./promisify')(events);

Loading…
Cancel
Save