* New StatLog: Replaces various logs, system props, etc. into one class/methods
* Uew StatLog for last callers * Use new StatLog for +op props * Use new StatLog for user props such as posts & MCI to access such * Use StatLog for various new MCI codes for +op * Misc missing MCI codes
This commit is contained in:
parent
d4ce574be3
commit
8787703989
71
core/bbs.js
71
core/bbs.js
|
@ -149,49 +149,58 @@ function initialize(cb) {
|
||||||
function initDatabases(callback) {
|
function initDatabases(callback) {
|
||||||
database.initializeDatabases(callback);
|
database.initializeDatabases(callback);
|
||||||
},
|
},
|
||||||
function initSystemProperties(callback) {
|
function initStatLog(callback) {
|
||||||
require('./system_property.js').loadSystemProperties(callback);
|
require('./stat_log.js').init(callback);
|
||||||
},
|
},
|
||||||
function initThemes(callback) {
|
function initThemes(callback) {
|
||||||
// Have to pull in here so it's after Config init
|
// Have to pull in here so it's after Config init
|
||||||
var theme = require('./theme.js');
|
require('./theme.js').initAvailableThemes(function onThemesInit(err, themeCount) {
|
||||||
theme.initAvailableThemes(function onThemesInit(err, themeCount) {
|
|
||||||
logger.log.info({ themeCount : themeCount }, 'Themes initialized');
|
logger.log.info({ themeCount : themeCount }, 'Themes initialized');
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function loadSysOpInformation(callback) {
|
function loadSysOpInformation2(callback) {
|
||||||
//
|
//
|
||||||
// If user 1 has been created, we have a SysOp. Cache some information
|
// Copy over some +op information from the user DB -> system propertys.
|
||||||
// into Config.
|
// * Makes this accessible for MCI codes, easy non-blocking access, etc.
|
||||||
//
|
// * We do this every time as the op is free to change this information just
|
||||||
var user = require('./user.js'); // must late load
|
// like any other user
|
||||||
|
//
|
||||||
|
const user = require('./user.js');
|
||||||
|
|
||||||
user.getUserName(1, function unLoaded(err, sysOpUsername) {
|
async.waterfall(
|
||||||
if(err) {
|
[
|
||||||
callback(null); // non-fatal here
|
function getOpUserName(next) {
|
||||||
} else {
|
return user.getUserName(1, next);
|
||||||
//
|
},
|
||||||
// Load some select properties to cache
|
function getOpProps(opUserName, next) {
|
||||||
//
|
const propLoadOpts = {
|
||||||
var propLoadOpts = {
|
userId : 1,
|
||||||
userId : 1,
|
names : [ 'real_name', 'sex', 'email_address', 'location', 'affiliation' ],
|
||||||
names : [ 'real_name', 'sex', 'email_address' ],
|
};
|
||||||
};
|
user.loadProperties(propLoadOpts, (err, opProps) => {
|
||||||
|
return next(err, opUserName, opProps);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
],
|
||||||
|
(err, opUserName, opProps) => {
|
||||||
|
const StatLog = require('./stat_log.js');
|
||||||
|
|
||||||
user.loadProperties(propLoadOpts, function propsLoaded(err, props) {
|
if(err) {
|
||||||
if(!err) {
|
[ 'username', 'real_name', 'sex', 'email_address', 'location', 'affiliation' ].forEach(v => {
|
||||||
conf.config.general.sysOp = {
|
StatLog.setNonPeristentSystemStat(`sysop_${v}`, 'N/A');
|
||||||
username : sysOpUsername,
|
});
|
||||||
properties : props,
|
} else {
|
||||||
};
|
opProps.username = opUserName;
|
||||||
|
|
||||||
logger.log.info( { sysOp : conf.config.general.sysOp }, 'System Operator information cached');
|
_.each(opProps, (v, k) => {
|
||||||
}
|
StatLog.setNonPeristentSystemStat(`sysop_${k}`, v);
|
||||||
callback(null); // any error is again, non-fatal here
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
|
return callback(null);
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
},
|
},
|
||||||
function readyMessageNetworkSupport(callback) {
|
function readyMessageNetworkSupport(callback) {
|
||||||
require('./msg_network.js').startup(callback);
|
require('./msg_network.js').startup(callback);
|
||||||
|
|
|
@ -100,26 +100,36 @@ function createSystemTables() {
|
||||||
|
|
||||||
dbs.system.run('PRAGMA foreign_keys = ON;');
|
dbs.system.run('PRAGMA foreign_keys = ON;');
|
||||||
|
|
||||||
|
// Various stat/event logging - see stat_log.js
|
||||||
dbs.system.run(
|
dbs.system.run(
|
||||||
'CREATE TABLE IF NOT EXISTS system_property (' +
|
`CREATE TABLE IF NOT EXISTS system_stat (
|
||||||
' prop_name VARCHAR PRIMARY KEY NOT NULL,' +
|
stat_name VARCHAR PRIMARY KEY NOT NULL,
|
||||||
' prop_value VARCHAR NOT NULL' +
|
stat_value VARCHAR NOT NULL
|
||||||
');'
|
);`
|
||||||
);
|
);
|
||||||
|
|
||||||
//
|
|
||||||
// system_log can round log_timestamp for daily, monthly, etc.
|
|
||||||
// statistics as well as unique entries.
|
|
||||||
//
|
|
||||||
/*
|
|
||||||
dbs.system.run(
|
dbs.system.run(
|
||||||
'CREATE TABLE IF NOT EXISTS system_log (' +
|
`CREATE TABLE IF NOT EXISTS system_event_log (
|
||||||
' log_timestamp DATETIME PRIMARY KEY NOT NULL ( ' +
|
id INTEGER PRIMARY KEY,
|
||||||
' log_name VARCHARNOT NULL,' +
|
timestamp DATETIME NOT NULL,
|
||||||
' log_value VARCHAR NOT NULL,' +
|
log_name VARCHAR NOT NULL,
|
||||||
' UNIQUE(log_timestamp, log_name)' +
|
log_value VARCHAR NOT NULL,
|
||||||
');'
|
|
||||||
);*/
|
UNIQUE(timestamp, log_name)
|
||||||
|
);`
|
||||||
|
);
|
||||||
|
|
||||||
|
dbs.system.run(
|
||||||
|
`CREATE TABLE IF NOT EXISTS user_event_log (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
timestamp DATETIME NOT NULL,
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
log_name VARCHAR NOT NULL,
|
||||||
|
log_value VARCHAR NOT NULL,
|
||||||
|
|
||||||
|
UNIQUE(timestamp, user_id, log_name)
|
||||||
|
);`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createUserTables() {
|
function createUserTables() {
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var Config = require('./config.js').config;
|
var Config = require('./config.js').config;
|
||||||
|
const StatLog = require('./stat_log.js');
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var paths = require('path');
|
var paths = require('path');
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
var async = require('async');
|
|
||||||
var moment = require('moment');
|
var moment = require('moment');
|
||||||
var iconv = require('iconv-lite');
|
var iconv = require('iconv-lite');
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ function DropFile(client, fileType) {
|
||||||
moment(up.birthdate).format('MM/DD/YY'), // "Caller's Birthdate"
|
moment(up.birthdate).format('MM/DD/YY'), // "Caller's Birthdate"
|
||||||
'X:\\MAIN\\', // "Path to the MAIN directory (where User File is)"
|
'X:\\MAIN\\', // "Path to the MAIN directory (where User File is)"
|
||||||
'X:\\GEN\\', // "Path to the GEN directory"
|
'X:\\GEN\\', // "Path to the GEN directory"
|
||||||
Config.general.sysOp.username, // "Sysop's Name (name BBS refers to Sysop as)"
|
StatLog.getSystemStat('sysop_username'), // "Sysop's Name (name BBS refers to Sysop as)"
|
||||||
self.client.user.username, // "Alias name"
|
self.client.user.username, // "Alias name"
|
||||||
'00:05', // "Event time (hh:mm)" (note: wat?)
|
'00:05', // "Event time (hh:mm)" (note: wat?)
|
||||||
'Y', // "If its an error correcting connection (Y/N)"
|
'Y', // "If its an error correcting connection (Y/N)"
|
||||||
|
@ -143,7 +143,7 @@ function DropFile(client, fileType) {
|
||||||
'0', // "Total Doors Opened"
|
'0', // "Total Doors Opened"
|
||||||
'0', // "Total Messages Left"
|
'0', // "Total Messages Left"
|
||||||
|
|
||||||
].join('\r\n') + '\r\n', 'cp437');
|
].join('\r\n') + '\r\n', 'cp437');
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getDoor32Buffer = function() {
|
this.getDoor32Buffer = function() {
|
||||||
|
@ -178,7 +178,7 @@ function DropFile(client, fileType) {
|
||||||
//
|
//
|
||||||
// Note that usernames are just used for first/last names here
|
// Note that usernames are just used for first/last names here
|
||||||
//
|
//
|
||||||
var opUn = /[^\s]*/.exec(Config.general.sysOp.username)[0];
|
var opUn = /[^\s]*/.exec(StatLog.getSystemStat('sysop_username'))[0];
|
||||||
var un = /[^\s]*/.exec(self.client.user.username)[0];
|
var un = /[^\s]*/.exec(self.client.user.username)[0];
|
||||||
var secLevel = self.client.user.getLegacySecurityLevel().toString();
|
var secLevel = self.client.user.getLegacySecurityLevel().toString();
|
||||||
|
|
||||||
|
|
19
core/fse.js
19
core/fse.js
|
@ -1,6 +1,7 @@
|
||||||
/* jslint node: true */
|
/* jslint node: true */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
// ENiGMA½
|
||||||
const MenuModule = require('../core/menu_module.js').MenuModule;
|
const MenuModule = require('../core/menu_module.js').MenuModule;
|
||||||
const ViewController = require('../core/view_controller.js').ViewController;
|
const ViewController = require('../core/view_controller.js').ViewController;
|
||||||
const ansi = require('../core/ansi_term.js');
|
const ansi = require('../core/ansi_term.js');
|
||||||
|
@ -10,7 +11,10 @@ const getMessageAreaByTag = require('../core/message_area.js').getMessageAreaB
|
||||||
const updateMessageAreaLastReadId = require('../core/message_area.js').updateMessageAreaLastReadId;
|
const updateMessageAreaLastReadId = require('../core/message_area.js').updateMessageAreaLastReadId;
|
||||||
const getUserIdAndName = require('../core/user.js').getUserIdAndName;
|
const getUserIdAndName = require('../core/user.js').getUserIdAndName;
|
||||||
const cleanControlCodes = require('../core/string_util.js').cleanControlCodes;
|
const cleanControlCodes = require('../core/string_util.js').cleanControlCodes;
|
||||||
|
const StatLog = require('./stat_log.js');
|
||||||
|
|
||||||
|
|
||||||
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
@ -295,6 +299,21 @@ function FullScreenEditorModule(options) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.updateUserStats = function(cb) {
|
||||||
|
if(Message.isPrivateAreaTag(this.message.areaTag)) {
|
||||||
|
if(cb) {
|
||||||
|
return cb(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatLog.incrementUserStat(
|
||||||
|
self.client.user,
|
||||||
|
'post_count',
|
||||||
|
1,
|
||||||
|
cb
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
this.redrawFooter = function(options, cb) {
|
this.redrawFooter = function(options, cb) {
|
||||||
async.waterfall(
|
async.waterfall(
|
||||||
[
|
[
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// ENiGMA½
|
// ENiGMA½
|
||||||
const Config = require('./config.js').config;
|
const Config = require('./config.js').config;
|
||||||
const Log = require('./logger.js').log;
|
const Log = require('./logger.js').log;
|
||||||
const getMessageAreaByTag = require('./message_area.js').getMessageAreaByTag;
|
const getMessageAreaByTag = require('./message_area.js').getMessageAreaByTag;
|
||||||
const getMessageConferenceByTag = require('./message_area.js').getMessageConferenceByTag;
|
const getMessageConferenceByTag = require('./message_area.js').getMessageConferenceByTag;
|
||||||
const clientConnections = require('./client_connections.js');
|
const clientConnections = require('./client_connections.js');
|
||||||
const sysProp = require('./system_property.js');
|
const StatLog = require('./stat_log.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const packageJson = require('../package.json');
|
const packageJson = require('../package.json');
|
||||||
|
@ -34,9 +34,14 @@ function getPredefinedMCIValue(client, code) {
|
||||||
VL : function versionLabel() { return 'ENiGMA½ v' + packageJson.version; },
|
VL : function versionLabel() { return 'ENiGMA½ v' + packageJson.version; },
|
||||||
VN : function version() { return packageJson.version; },
|
VN : function version() { return packageJson.version; },
|
||||||
|
|
||||||
// :TODO: SysOp username
|
// +op info
|
||||||
// :TODO: SysOp real name
|
SN : function opUserName() { return StatLog.getSystemStat('sysop_username'); },
|
||||||
|
SR : function opRealName() { return StatLog.getSystemStat('sysop_real_name'); },
|
||||||
|
SL : function opLocation() { return StatLog.getSystemStat('sysop_location'); },
|
||||||
|
SA : function opAffils() { return StatLog.getSystemStat('sysop_affiliation'); },
|
||||||
|
SS : function opSex() { return StatLog.getSystemStat('sysop_sex'); },
|
||||||
|
SE : function opEmail() { return StatLog.getSystemStat('sysop_email_address'); },
|
||||||
|
// :TODO: op age, web, ?????
|
||||||
|
|
||||||
//
|
//
|
||||||
// Current user / session
|
// Current user / session
|
||||||
|
@ -60,6 +65,16 @@ function getPredefinedMCIValue(client, code) {
|
||||||
|
|
||||||
MS : function accountCreated() { return moment(client.user.properties.account_created).format(client.currentTheme.helpers.getDateFormat()); },
|
MS : function accountCreated() { return moment(client.user.properties.account_created).format(client.currentTheme.helpers.getDateFormat()); },
|
||||||
CS : function currentStatus() { return client.currentStatus; },
|
CS : function currentStatus() { return client.currentStatus; },
|
||||||
|
PS : function userPostCount() {
|
||||||
|
const postCount = client.user.properties.post_count || 0;
|
||||||
|
return postCount.toString();
|
||||||
|
},
|
||||||
|
PC : function userPostCallRatio() {
|
||||||
|
const postCount = client.user.properties.post_count || 0;
|
||||||
|
const callCount = client.user.properties.login_count;
|
||||||
|
const ratio = ~~((postCount / callCount) * 100);
|
||||||
|
return `${ratio}%`;
|
||||||
|
},
|
||||||
|
|
||||||
MD : function currentMenuDescription() {
|
MD : function currentMenuDescription() {
|
||||||
return _.has(client, 'currentMenuModule.menuConfig.desc') ? client.currentMenuModule.menuConfig.desc : '';
|
return _.has(client, 'currentMenuModule.menuConfig.desc') ? client.currentMenuModule.menuConfig.desc : '';
|
||||||
|
@ -73,11 +88,14 @@ function getPredefinedMCIValue(client, code) {
|
||||||
const conf = getMessageConferenceByTag(client.user.properties.message_conf_tag);
|
const conf = getMessageConferenceByTag(client.user.properties.message_conf_tag);
|
||||||
return conf ? conf.name : '';
|
return conf ? conf.name : '';
|
||||||
},
|
},
|
||||||
|
|
||||||
ML : function messageAreaDescription() {
|
ML : function messageAreaDescription() {
|
||||||
const area = getMessageAreaByTag(client.user.properties.message_area_tag);
|
const area = getMessageAreaByTag(client.user.properties.message_area_tag);
|
||||||
return area ? area.desc : '';
|
return area ? area.desc : '';
|
||||||
},
|
},
|
||||||
|
CM : function messageConfDescription() {
|
||||||
|
const conf = getMessageConferenceByTag(client.user.properties.message_conf_tag);
|
||||||
|
return conf ? conf.desc : '';
|
||||||
|
},
|
||||||
|
|
||||||
SH : function termHeight() { return client.term.termHeight.toString(); },
|
SH : function termHeight() { return client.term.termHeight.toString(); },
|
||||||
SW : function termWidth() { return client.term.termWidth.toString(); },
|
SW : function termWidth() { return client.term.termWidth.toString(); },
|
||||||
|
@ -103,7 +121,7 @@ function getPredefinedMCIValue(client, code) {
|
||||||
},
|
},
|
||||||
|
|
||||||
OA : function systemArchitecture() { return os.arch(); },
|
OA : function systemArchitecture() { return os.arch(); },
|
||||||
SC : function systemCpuModel() {
|
SC : function systemCpuModel() {
|
||||||
//
|
//
|
||||||
// Clean up CPU strings a bit for better display
|
// Clean up CPU strings a bit for better display
|
||||||
//
|
//
|
||||||
|
@ -114,11 +132,11 @@ function getPredefinedMCIValue(client, code) {
|
||||||
// :TODO: MCI for core count, e.g. os.cpus().length
|
// :TODO: MCI for core count, e.g. os.cpus().length
|
||||||
|
|
||||||
// :TODO: cpu load average (over N seconds): http://stackoverflow.com/questions/9565912/convert-the-output-of-os-cpus-in-node-js-to-percentage
|
// :TODO: cpu load average (over N seconds): http://stackoverflow.com/questions/9565912/convert-the-output-of-os-cpus-in-node-js-to-percentage
|
||||||
// :TODO: Node version/info
|
NV : function nodeVersion() { return process.version; },
|
||||||
|
|
||||||
AN : function activeNodes() { return clientConnections.getActiveConnections().length.toString(); },
|
AN : function activeNodes() { return clientConnections.getActiveConnections().length.toString(); },
|
||||||
|
|
||||||
TC : function totalCalls() { return sysProp.getSystemProperty('login_count').toString(); },
|
TC : function totalCalls() { return StatLog.getSystemStat('login_count').toString(); },
|
||||||
|
|
||||||
//
|
//
|
||||||
// Special handling for XY
|
// Special handling for XY
|
||||||
|
|
22
core/user.js
22
core/user.js
|
@ -358,28 +358,6 @@ User.prototype.persistAllProperties = function(cb) {
|
||||||
assert(this.userId > 0);
|
assert(this.userId > 0);
|
||||||
|
|
||||||
this.persistProperties(this.properties, cb);
|
this.persistProperties(this.properties, cb);
|
||||||
|
|
||||||
/*
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var stmt = userDb.prepare(
|
|
||||||
'REPLACE INTO user_property (user_id, prop_name, prop_value) ' +
|
|
||||||
'VALUES (?, ?, ?);');
|
|
||||||
|
|
||||||
async.each(Object.keys(this.properties), function property(propName, callback) {
|
|
||||||
stmt.run(self.userId, propName, self.properties[propName], function onRun(err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
}, function complete(err) {
|
|
||||||
if(err) {
|
|
||||||
cb(err);
|
|
||||||
} else {
|
|
||||||
stmt.finalize(function finalized() {
|
|
||||||
cb(null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
User.prototype.setNewAuthCredentials = function(password, cb) {
|
User.prototype.setNewAuthCredentials = function(password, cb) {
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
/* jslint node: true */
|
/* jslint node: true */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var setClientTheme = require('./theme.js').setClientTheme;
|
// ENiGMA½
|
||||||
var clientConnections = require('./client_connections.js').clientConnections;
|
const setClientTheme = require('./theme.js').setClientTheme;
|
||||||
var userDb = require('./database.js').dbs.user;
|
const clientConnections = require('./client_connections.js').clientConnections;
|
||||||
var sysProp = require('./system_property.js');
|
const userDb = require('./database.js').dbs.user;
|
||||||
var logger = require('./logger.js');
|
const StatLog = require('./stat_log.js');
|
||||||
var Config = require('./config.js').config;
|
const logger = require('./logger.js');
|
||||||
|
|
||||||
var async = require('async');
|
// deps
|
||||||
var _ = require('lodash');
|
const async = require('async');
|
||||||
var assert = require('assert');
|
|
||||||
|
|
||||||
exports.userLogin = userLogin;
|
exports.userLogin = userLogin;
|
||||||
|
|
||||||
|
@ -24,8 +23,8 @@ function userLogin(client, username, password, cb) {
|
||||||
|
|
||||||
cb(err);
|
cb(err);
|
||||||
} else {
|
} else {
|
||||||
var now = new Date();
|
const now = new Date();
|
||||||
var user = client.user;
|
const user = client.user;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Ensure this user is not already logged in.
|
// Ensure this user is not already logged in.
|
||||||
|
@ -60,46 +59,21 @@ function userLogin(client, username, password, cb) {
|
||||||
|
|
||||||
async.parallel(
|
async.parallel(
|
||||||
[
|
[
|
||||||
function setTheme(callback) {
|
function setTheme(callback) {
|
||||||
setClientTheme(client, user.properties.theme_id);
|
setClientTheme(client, user.properties.theme_id);
|
||||||
callback(null);
|
callback(null);
|
||||||
},
|
},
|
||||||
function updateSystemLoginCount(callback) {
|
function updateSystemLoginCount(callback) {
|
||||||
var sysLoginCount = sysProp.getSystemProperty('login_count') || 0;
|
StatLog.incrementSystemStat('login_count', 1, callback);
|
||||||
sysLoginCount = parseInt(sysLoginCount, 10) + 1;
|
|
||||||
sysProp.persistSystemProperty('login_count', sysLoginCount, callback);
|
|
||||||
},
|
},
|
||||||
function recordLastLogin(callback) {
|
function recordLastLogin(callback) {
|
||||||
user.persistProperty('last_login_timestamp', now.toISOString(), function persisted(err) {
|
StatLog.setUserStat(user, 'last_login_timestamp', StatLog.now, callback);
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
function updateUserLoginCount(callback) {
|
function updateUserLoginCount(callback) {
|
||||||
if(!user.properties.login_count) {
|
StatLog.incrementUserStat(user, 'login_count', 1, callback);
|
||||||
user.properties.login_count = 1;
|
|
||||||
} else {
|
|
||||||
user.properties.login_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
user.persistProperty('login_count', user.properties.login_count, function persisted(err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
function recordLoginHistory(callback) {
|
function recordLoginHistory(callback) {
|
||||||
userDb.serialize(function serialized() {
|
StatLog.appendSystemLogEntry('user_login_history', user.userId, 30, callback);
|
||||||
userDb.run(
|
|
||||||
'INSERT INTO user_login_history (user_id, user_name, timestamp) ' +
|
|
||||||
'VALUES(?, ?, ?);', [ user.userId, user.username, now.toISOString() ]
|
|
||||||
);
|
|
||||||
|
|
||||||
// keep 30 days of records
|
|
||||||
userDb.run(
|
|
||||||
'DELETE FROM user_login_history ' +
|
|
||||||
'WHERE timestamp <= DATETIME("now", "-30 day");'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
callback(null);
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
function complete(err) {
|
function complete(err) {
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
/* jslint node: true */
|
/* jslint node: true */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var MenuModule = require('../core/menu_module.js').MenuModule;
|
// ENiGMA½
|
||||||
var userDb = require('../core/database.js').dbs.user;
|
const MenuModule = require('../core/menu_module.js').MenuModule;
|
||||||
var ViewController = require('../core/view_controller.js').ViewController;
|
const ViewController = require('../core/view_controller.js').ViewController;
|
||||||
var getSystemLoginHistory = require('../core/stats.js').getSystemLoginHistory;
|
const StatLog = require('../core/stat_log.js');
|
||||||
|
const getUserName = require('../core/user.js').getUserName;
|
||||||
|
const loadProperties = require('../core/user.js').loadProperties;
|
||||||
|
|
||||||
var moment = require('moment');
|
// deps
|
||||||
var async = require('async');
|
const moment = require('moment');
|
||||||
var assert = require('assert');
|
const async = require('async');
|
||||||
var _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Available listFormat object members:
|
Available listFormat object members:
|
||||||
|
@ -41,11 +43,11 @@ function LastCallersModule(options) {
|
||||||
require('util').inherits(LastCallersModule, MenuModule);
|
require('util').inherits(LastCallersModule, MenuModule);
|
||||||
|
|
||||||
LastCallersModule.prototype.mciReady = function(mciData, cb) {
|
LastCallersModule.prototype.mciReady = function(mciData, cb) {
|
||||||
var self = this;
|
const self = this;
|
||||||
var vc = self.viewControllers.allViews = new ViewController( { client : self.client } );
|
const vc = self.viewControllers.allViews = new ViewController( { client : self.client } );
|
||||||
|
|
||||||
var loginHistory;
|
let loginHistory;
|
||||||
var callersView;
|
let callersView;
|
||||||
|
|
||||||
async.series(
|
async.series(
|
||||||
[
|
[
|
||||||
|
@ -53,7 +55,7 @@ LastCallersModule.prototype.mciReady = function(mciData, cb) {
|
||||||
LastCallersModule.super_.prototype.mciReady.call(self, mciData, callback);
|
LastCallersModule.super_.prototype.mciReady.call(self, mciData, callback);
|
||||||
},
|
},
|
||||||
function loadFromConfig(callback) {
|
function loadFromConfig(callback) {
|
||||||
var loadOpts = {
|
const loadOpts = {
|
||||||
callingMenu : self,
|
callingMenu : self,
|
||||||
mciMap : mciData.menu,
|
mciMap : mciData.menu,
|
||||||
noInput : true,
|
noInput : true,
|
||||||
|
@ -64,51 +66,53 @@ LastCallersModule.prototype.mciReady = function(mciData, cb) {
|
||||||
function fetchHistory(callback) {
|
function fetchHistory(callback) {
|
||||||
callersView = vc.getView(MciCodeIds.CallerList);
|
callersView = vc.getView(MciCodeIds.CallerList);
|
||||||
|
|
||||||
getSystemLoginHistory(callersView.dimens.height, function historyRetrieved(err, lh) {
|
StatLog.getSystemLogEntries('user_login_history', 'timestamp_desc', callersView.dimens.height, (err, lh) => {
|
||||||
loginHistory = lh;
|
loginHistory = lh;
|
||||||
callback(err);
|
return callback(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function fetchUserProperties(callback) {
|
function getUserNamesAndProperties(callback) {
|
||||||
async.each(loginHistory, function entry(histEntry, next) {
|
const getPropOpts = {
|
||||||
userDb.each(
|
names : [ 'location', 'affiliation' ]
|
||||||
'SELECT prop_name, prop_value ' +
|
};
|
||||||
'FROM user_property ' +
|
|
||||||
'WHERE user_id=? AND (prop_name="location" OR prop_name="affiliation");',
|
const dateTimeFormat = self.menuConfig.config.dateTimeFormat || 'ddd MMM DD';
|
||||||
[ histEntry.userId ],
|
|
||||||
function propRow(err, propEntry) {
|
async.each(
|
||||||
histEntry[propEntry.prop_name] = propEntry.prop_value;
|
loginHistory,
|
||||||
},
|
(item, next) => {
|
||||||
function complete(err) {
|
item.userId = parseInt(item.log_value);
|
||||||
next();
|
item.ts = moment(item.timestamp).format(dateTimeFormat);
|
||||||
}
|
|
||||||
);
|
getUserName(item.userId, (err, userName) => {
|
||||||
}, function complete(err) {
|
item.userName = userName;
|
||||||
callback(err);
|
getPropOpts.userId = item.userId;
|
||||||
});
|
|
||||||
|
loadProperties(getPropOpts, (err, props) => {
|
||||||
|
if(!err) {
|
||||||
|
item.location = props.location;
|
||||||
|
item.affiliation = item.affils = props.affiliation;
|
||||||
|
}
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
callback
|
||||||
|
);
|
||||||
},
|
},
|
||||||
function populateList(callback) {
|
function populateList(callback) {
|
||||||
var listFormat = self.menuConfig.config.listFormat || '{userName} - {location} - {affils} - {ts}';
|
const listFormat = self.menuConfig.config.listFormat || '{userName} - {location} - {affils} - {ts}';
|
||||||
var dateTimeFormat = self.menuConfig.config.dateTimeFormat || 'ddd MMM DD';
|
|
||||||
|
|
||||||
callersView.setItems(_.map(loginHistory, function formatCallEntry(ce) {
|
callersView.setItems(_.map(loginHistory, ce => listFormat.format(ce) ) );
|
||||||
return listFormat.format({
|
|
||||||
userId : ce.userId,
|
|
||||||
userName : ce.userName,
|
|
||||||
ts : moment(ce.timestamp).format(dateTimeFormat),
|
|
||||||
location : ce.location,
|
|
||||||
affils : ce.affiliation,
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
// :TODO: This is a hack until pipe codes are better implemented
|
// :TODO: This is a hack until pipe codes are better implemented
|
||||||
callersView.focusItems = callersView.items;
|
callersView.focusItems = callersView.items;
|
||||||
|
|
||||||
callersView.redraw();
|
callersView.redraw();
|
||||||
callback(null);
|
return callback(null);
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
function complete(err) {
|
(err) => {
|
||||||
if(err) {
|
if(err) {
|
||||||
self.client.log.error( { error : err.toString() }, 'Error loading last callers');
|
self.client.log.error( { error : err.toString() }, 'Error loading last callers');
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,9 @@ function AreaPostFSEModule(options) {
|
||||||
},
|
},
|
||||||
function saveMessage(callback) {
|
function saveMessage(callback) {
|
||||||
return persistMessage(msg, callback);
|
return persistMessage(msg, callback);
|
||||||
|
},
|
||||||
|
function updateStats(callback) {
|
||||||
|
self.updateUserStats(callback);
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
function complete(err) {
|
function complete(err) {
|
||||||
|
|
Loading…
Reference in New Issue