/
events.js
157 lines (140 loc) · 3.76 KB
/
events.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
'use strict';
const validator = require('validator');
const _ = require('lodash');
const db = require('./database');
const batch = require('./batch');
const user = require('./user');
const utils = require('./utils');
const events = module.exports;
events.types = [
'plugin-activate',
'plugin-deactivate',
'plugin-install',
'plugin-uninstall',
'restart',
'build',
'config-change',
'settings-change',
'category-purge',
'privilege-change',
'post-delete',
'post-restore',
'post-purge',
'post-change-owner',
'topic-delete',
'topic-restore',
'topic-purge',
'topic-rename',
'password-reset',
'user-makeAdmin',
'user-removeAdmin',
'user-ban',
'user-unban',
'user-delete',
'password-change',
'email-change',
'username-change',
'ip-blacklist-save',
'ip-blacklist-addRule',
'registration-approved',
'registration-rejected',
'group-join',
'group-request-membership',
'group-add-member',
'group-leave',
'group-owner-grant',
'group-owner-rescind',
'group-accept-membership',
'group-reject-membership',
'group-invite',
'group-invite-accept',
'group-invite-reject',
'group-kick',
'theme-set',
'export:uploads',
'account-locked',
'getUsersCSV',
// To add new types from plugins, just Array.push() to this array
];
/**
* Useful options in data: type, uid, ip, targetUid
* Everything else gets stringified and shown as pretty JSON string
*/
events.log = async function (data) {
const eid = await db.incrObjectField('global', 'nextEid');
data.timestamp = Date.now();
data.eid = eid;
await Promise.all([
db.sortedSetsAdd([
'events:time',
'events:time:' + data.type,
], data.timestamp, eid),
db.setObject('event:' + eid, data),
]);
};
events.getEvents = async function (filter, start, stop, from, to) {
// from/to optional
if (from === undefined) {
from = 0;
}
if (to === undefined) {
to = Date.now();
}
const eids = await db.getSortedSetRevRangeByScore('events:time' + (filter ? ':' + filter : ''), start, stop - start + 1, to, from);
let eventsData = await db.getObjects(eids.map(eid => 'event:' + eid));
eventsData = eventsData.filter(Boolean);
await addUserData(eventsData, 'uid', 'user');
await addUserData(eventsData, 'targetUid', 'targetUser');
eventsData.forEach(function (event) {
Object.keys(event).forEach(function (key) {
if (typeof event[key] === 'string') {
event[key] = validator.escape(String(event[key] || ''));
}
});
const 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();
});
return eventsData;
};
async function addUserData(eventsData, field, objectName) {
const uids = _.uniq(eventsData.map(event => event && event[field]));
if (!uids.length) {
return eventsData;
}
const [isAdmin, userData] = await Promise.all([
user.isAdministrator(uids),
user.getUsersFields(uids, ['username', 'userslug', 'picture']),
]);
const map = {};
userData.forEach(function (user, index) {
user.isAdmin = isAdmin[index];
map[user.uid] = user;
});
eventsData.forEach(function (event) {
if (map[event[field]]) {
event[objectName] = map[event[field]];
}
});
return eventsData;
}
events.deleteEvents = async function (eids) {
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),
]);
};
events.deleteAll = async function () {
await batch.processSortedSet('events:time', async function (eids) {
await events.deleteEvents(eids);
}, { alwaysStartAt: 0, batch: 500 });
};
require('./promisify')(events);