parent
79083004e4
commit
2c8e8a1f1c
@ -0,0 +1,43 @@
|
||||
"use strict";
|
||||
/* global define, socket, app, templates */
|
||||
|
||||
|
||||
define('admin/advanced/events', ['forum/infinitescroll'], function(infinitescroll) {
|
||||
var Events = {};
|
||||
|
||||
Events.init = function() {
|
||||
|
||||
$('[data-action="clear"]').on('click', function() {
|
||||
socket.emit('admin.deleteAllEvents', function(err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
$('.events-list').empty();
|
||||
});
|
||||
});
|
||||
|
||||
infinitescroll.init(function(direction) {
|
||||
if (direction < 0 || !$('.events').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
infinitescroll.loadMore('admin.getMoreEvents', $('[data-next]').attr('data-next'), function(data, done) {
|
||||
console.log(data.events);
|
||||
if (data.events && data.events.length) {
|
||||
templates.parse('admin/advanced/events', 'events', {events: data.events}, function(html) {
|
||||
console.log(html);
|
||||
$('.events-list').append(html);
|
||||
done();
|
||||
});
|
||||
|
||||
$('[data-next]').attr('data-next', data.next);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
return Events;
|
||||
});
|
@ -1,154 +1,128 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs'),
|
||||
winston = require('winston'),
|
||||
path = require('path'),
|
||||
nconf = require('nconf'),
|
||||
user = require('./user');
|
||||
var async = require('async'),
|
||||
|
||||
db = require('./database'),
|
||||
batch = require('./batch'),
|
||||
user = require('./user'),
|
||||
utils = require('../public/src/utils');
|
||||
|
||||
(function(events) {
|
||||
var logFileName = 'logs/events.log';
|
||||
|
||||
events.logPasswordChange = function(uid) {
|
||||
events.logWithUser(uid, 'changed password');
|
||||
};
|
||||
|
||||
events.logAdminChangeUserPassword = function(adminUid, theirUid, callback) {
|
||||
logAdminEvent(adminUid, theirUid, 'changed password of', callback);
|
||||
};
|
||||
|
||||
events.logAdminUserDelete = function(adminUid, theirUid, callback) {
|
||||
logAdminEvent(adminUid, theirUid, 'deleted', callback);
|
||||
};
|
||||
|
||||
function logAdminEvent(adminUid, theirUid, message, callback) {
|
||||
user.getMultipleUserFields([adminUid, theirUid], ['username'], function(err, userData) {
|
||||
if(err) {
|
||||
return winston.error('Error logging event. ' + err.message);
|
||||
(function(events) {
|
||||
events.log = function(data, callback) {
|
||||
callback = callback || function() {};
|
||||
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
db.incrObjectField('global', 'nextEid', next);
|
||||
},
|
||||
function(eid, next) {
|
||||
data.timestamp = Date.now();
|
||||
data.eid = eid;
|
||||
|
||||
async.parallel([
|
||||
function(next) {
|
||||
db.sortedSetAdd('events:time', data.timestamp, eid, next);
|
||||
},
|
||||
function(next) {
|
||||
db.setObject('event:' + eid, data, next);
|
||||
}
|
||||
], next);
|
||||
}
|
||||
|
||||
var msg = userData[0].username + '(uid ' + adminUid + ') ' + message + ' ' + userData[1].username + '(uid ' + theirUid + ')';
|
||||
events.log(msg, callback);
|
||||
], function(err, result) {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
events.logPasswordReset = function(uid) {
|
||||
events.logWithUser(uid, 'reset password');
|
||||
};
|
||||
|
||||
events.logEmailChange = function(uid, oldEmail, newEmail) {
|
||||
events.logWithUser(uid,'changed email from "' + oldEmail + '" to "' + newEmail +'"');
|
||||
};
|
||||
|
||||
events.logUsernameChange = function(uid, oldUsername, newUsername) {
|
||||
events.logWithUser(uid,'changed username from "' + oldUsername + '" to "' + newUsername +'"');
|
||||
};
|
||||
|
||||
events.logAdminLogin = function(uid) {
|
||||
events.logWithUser(uid, 'logged into admin panel');
|
||||
};
|
||||
|
||||
events.logPostEdit = function(uid, pid) {
|
||||
events.logWithUser(uid, 'edited post (pid ' + pid + ')');
|
||||
};
|
||||
|
||||
events.logPostDelete = function(uid, pid) {
|
||||
events.logWithUser(uid, 'deleted post (pid ' + pid + ')');
|
||||
};
|
||||
|
||||
events.logPostRestore = function(uid, pid) {
|
||||
events.logWithUser(uid, 'restored post (pid ' + pid + ')');
|
||||
};
|
||||
|
||||
events.logPostPurge = function(uid, pid) {
|
||||
events.logWithUser(uid, 'purged post (pid ' + pid + ')');
|
||||
};
|
||||
|
||||
events.logTopicMove = function(uid, tid) {
|
||||
events.logWithUser(uid, 'moved topic (tid ' + tid + ')');
|
||||
};
|
||||
|
||||
events.logTopicDelete = function(uid, tid) {
|
||||
events.logWithUser(uid, 'deleted topic (tid ' + tid + ')');
|
||||
};
|
||||
|
||||
events.logTopicRestore = function(uid, tid) {
|
||||
events.logWithUser(uid, 'restored topic (tid ' + tid + ')');
|
||||
};
|
||||
|
||||
events.logAccountLock = function(uid, until) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + until);
|
||||
|
||||
events.logWithUser(uid, 'locked out until ' + date.toString());
|
||||
};
|
||||
|
||||
events.logWithUser = function(uid, string) {
|
||||
user.getUserField(uid, 'username', function(err, username) {
|
||||
if(err) {
|
||||
return winston.error('Error logging event. ' + err.message);
|
||||
events.getEvents = function(start, stop, callback) {
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
db.getSortedSetRevRange('events:time', start, stop, next);
|
||||
},
|
||||
function(eids, next) {
|
||||
var keys = eids.map(function(eid) {
|
||||
return 'event:' + eid;
|
||||
});
|
||||
db.getObjects(keys, next);
|
||||
},
|
||||
function(eventsData, next) {
|
||||
eventsData.forEach(function(event) {
|
||||
var e = utils.merge(event);
|
||||
e.eid = e.uid = e.type = e.ip = undefined;
|
||||
event.jsonString = JSON.stringify(e, null, 4);
|
||||
event.timestampISO = new Date(parseInt(event.timestamp, 10)).toUTCString();
|
||||
});
|
||||
addUserData(eventsData, 'uid', 'user', next);
|
||||
},
|
||||
function(eventsData, next) {
|
||||
addUserData(eventsData, 'targetUid', 'targetUser', next);
|
||||
}
|
||||
|
||||
var msg = username + '(uid ' + uid + ') ' + string;
|
||||
events.log(msg);
|
||||
});
|
||||
], callback);
|
||||
};
|
||||
|
||||
events.log = function(msg, callback) {
|
||||
var logFile = path.join(nconf.get('base_dir'), logFileName);
|
||||
|
||||
msg = '[' + new Date().toUTCString() + '] - ' + msg;
|
||||
|
||||
fs.appendFile(logFile, msg + '\n', function(err) {
|
||||
if(err) {
|
||||
winston.error('Error logging event. ' + err.message);
|
||||
if (typeof callback === 'function') {
|
||||
callback(err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
function addUserData(eventsData, field, objectName, callback) {
|
||||
var uids = eventsData.map(function(event) {
|
||||
return event && event[field];
|
||||
}).filter(function(uid, index, array) {
|
||||
return uid && array.indexOf(uid) === index;
|
||||
});
|
||||
};
|
||||
|
||||
events.getLog = function(end, len, callback) {
|
||||
var logFile = path.join(nconf.get('base_dir'), logFileName);
|
||||
if (!uids.length) {
|
||||
return callback(null, eventsData);
|
||||
}
|
||||
|
||||
fs.stat(logFile, function(err, stat) {
|
||||
if (err) {
|
||||
return callback(null, 'No logs found!');
|
||||
async.parallel({
|
||||
isAdmin: function(next) {
|
||||
user.isAdministrator(uids, next);
|
||||
},
|
||||
userData: function(next) {
|
||||
user.getMultipleUserFields(uids, ['username', 'userslug', 'picture'], next);
|
||||
}
|
||||
|
||||
var buffer = '';
|
||||
var size = stat.size;
|
||||
if (end === -1) {
|
||||
end = size;
|
||||
}, function(err, results) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
end = parseInt(end, 10);
|
||||
var start = Math.max(0, end - len);
|
||||
var userData = results.userData;
|
||||
|
||||
var rs = fs.createReadStream(logFile, {start: start, end: end});
|
||||
rs.addListener('data', function(lines) {
|
||||
buffer += lines.toString();
|
||||
var map = {};
|
||||
userData.forEach(function(user, index) {
|
||||
user.isAdmin = results.isAdmin[index];
|
||||
map[user.uid] = user;
|
||||
});
|
||||
|
||||
rs.addListener('end', function() {
|
||||
var firstNewline = buffer.indexOf('\n');
|
||||
if (firstNewline !== -1) {
|
||||
buffer = buffer.slice(firstNewline);
|
||||
buffer = buffer.split('\n').reverse().join('\n');
|
||||
eventsData.forEach(function(event) {
|
||||
if (map[event[field]]) {
|
||||
event[objectName] = map[event[field]];
|
||||
}
|
||||
|
||||
callback(null, {data: buffer, next: end - buffer.length});
|
||||
});
|
||||
callback(null, eventsData);
|
||||
});
|
||||
}
|
||||
|
||||
events.deleteEvents = function(eids, callback) {
|
||||
callback = callback || function() {};
|
||||
async.parallel([
|
||||
function(next) {
|
||||
var keys = eids.map(function(eid) {
|
||||
return 'event:' + eid;
|
||||
});
|
||||
db.deleteAll(keys, next);
|
||||
},
|
||||
function(next) {
|
||||
db.sortedSetRemove('events:time', eids, next);
|
||||
}
|
||||
], callback);
|
||||
};
|
||||
|
||||
events.deleteAll = function(callback) {
|
||||
callback = callback || function() {};
|
||||
|
||||
batch.processSortedSet('events:time', function(eids, next) {
|
||||
events.deleteEvents(eids, callback);
|
||||
}, {alwaysStartAt: 0}, callback);
|
||||
};
|
||||
|
||||
|
||||
}(module.exports));
|
||||
|
@ -1,31 +1,32 @@
|
||||
<div class="events">
|
||||
<div class="col-sm-9">
|
||||
<div class="col-lg-9">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><i class="fa fa-calendar-o"></i> Events</div>
|
||||
<div class="panel-body" data-next="{next}">
|
||||
<pre>{eventdata}</pre>
|
||||
<!-- IF !events.length -->
|
||||
<div class="alert alert-info">There are no events</div>
|
||||
<!-- ENDIF !events.length -->
|
||||
<div class="events-list">
|
||||
<!-- BEGIN events -->
|
||||
<div>
|
||||
<span>#{events.eid} </span><span class="label label-info">{events.type}</span>
|
||||
<a href="{config.relative_path}/user/{events.user.userslug}"><img class="user-img" src="{events.user.picture}"/></a> <a href="{config.relative_path}/user/{events.user.userslug}">{events.user.username}</a> (uid {events.user.uid}) (IP {events.ip})
|
||||
<span class="pull-right">{events.timestampISO}</span>
|
||||
<br/><br/>
|
||||
<pre>{events.jsonString}</pre>
|
||||
</div>
|
||||
<!-- END events -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<div class="panel panel-default affix">
|
||||
<div class="panel-heading">Events Control Panel</div>
|
||||
<div class="panel-body">
|
||||
<button class="btn btn-warning" data-action="clear"><i class="fa fa-eraser"></i> Delete Events</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
require(['forum/infinitescroll'], function(infinitescroll) {
|
||||
|
||||
infinitescroll.init(function(direction) {
|
||||
if (direction < 0 || !$('.events').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
infinitescroll.loadMore('admin.getMoreEvents', $('[data-next]').attr('data-next'), function(events, done) {
|
||||
if (events.data && events.data.length) {
|
||||
$('.panel-body pre').append(events.data);
|
||||
$('[data-next]').attr('data-next', events.next);
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
Loading…
Reference in New Issue