diff --git a/core/mci_view_factory.js b/core/mci_view_factory.js index 1ce0aadb..330d777c 100644 --- a/core/mci_view_factory.js +++ b/core/mci_view_factory.js @@ -29,49 +29,52 @@ function MCIViewFactory(client) { } MCIViewFactory.prototype.getPredefinedViewLabel = function(code) { - return { - BN : Config.general.boardName, - VL : 'ENiGMA½ v' + packageJson.version, - VN : packageJson.version, + try { + return { + BN : Config.general.boardName, + VL : 'ENiGMA½ v' + packageJson.version, + VN : packageJson.version, - UN : this.client.user.username, - UI : this.client.user.userId.toString(), - UG : _.values(this.client.user.groups).join(', '), - UR : this.client.user.properties.real_name, - LO : this.client.user.properties.location, - UA : this.client.user.getAge().toString(), - UB : moment(this.client.user.properties.birthdate).format(this.client.currentTheme.helpers.getDateFormat()), - US : this.client.user.properties.sex, - UE : this.client.user.properties.email_address, - UW : this.client.user.properties.web_address, - UF : this.client.user.properties.affiliation, - UT : this.client.user.properties.theme_id, - MS : moment(this.client.user.properties.timestamp).format(this.client.currentTheme.helpers.getDateFormat()), + UN : this.client.user.username, + UI : this.client.user.userId.toString(), + UG : _.values(this.client.user.groups).join(', '), + UR : this.client.user.properties.real_name, + LO : this.client.user.properties.location, + UA : this.client.user.getAge().toString(), + UB : moment(this.client.user.properties.birthdate).format(this.client.currentTheme.helpers.getDateFormat()), + US : this.client.user.properties.sex, + UE : this.client.user.properties.email_address, + UW : this.client.user.properties.web_address, + UF : this.client.user.properties.affiliation, + UT : this.client.user.properties.theme_id, + MS : moment(this.client.user.properties.timestamp).format(this.client.currentTheme.helpers.getDateFormat()), - SH : this.client.term.termHeight.toString(), - SW : this.client.term.termWidth.toString(), + SH : this.client.term.termHeight.toString(), + SW : this.client.term.termWidth.toString(), - ND : this.client.runtime.id.toString(), + ND : this.client.runtime.id.toString(), - // :TODO: change to CD for 'Current Date' - DT : moment().format(this.client.currentTheme.helpers.getDateFormat()), - CT : moment().format(this.client.currentTheme.helpers.getTimeFormat()), + // :TODO: change to CD for 'Current Date' + DT : moment().format(this.client.currentTheme.helpers.getDateFormat()), + CT : moment().format(this.client.currentTheme.helpers.getTimeFormat()), - OS : { - linux : 'Linux', - darwin : 'Mac OS X', - win32 : 'Windows', - sunos : 'SunOS', - freebsd : 'FreeBSD', - }[os.platform()] || os.type(), + OS : { + linux : 'Linux', + darwin : 'Mac OS X', + win32 : 'Windows', + sunos : 'SunOS', + freebsd : 'FreeBSD', + }[os.platform()] || os.type(), - OA : os.arch(), - SC : os.cpus()[0].model, + OA : os.arch(), + SC : os.cpus()[0].model, - IP : this.client.address().address, - }[code]; + IP : this.client.address().address, + }[code]; + } catch(e) { + } }; MCIViewFactory.prototype.createFromMCI = function(mci) { diff --git a/core/system_menu_method.js b/core/system_menu_method.js index 25cf577a..d70c8f8a 100644 --- a/core/system_menu_method.js +++ b/core/system_menu_method.js @@ -2,7 +2,7 @@ 'use strict'; var theme = require('../core/theme.js'); -var Log = require('../core/logger.js').log; +//var Log = require('../core/logger.js').log; var ansi = require('../core/ansi_term.js'); var async = require('async'); @@ -15,12 +15,12 @@ function login(callingMenu, formData, extraArgs) { client.user.authenticate(formData.value.username, formData.value.password, function authenticated(err) { if(err) { - Log.info( { username : formData.value.username }, 'Failed login attempt %s', err); + client.log.info( { username : formData.value.username }, 'Failed login attempt %s', err); client.gotoMenuModule( { name : callingMenu.menuConfig.fallback } ); } else { // use client.user so we can get correct case - Log.info( { username : callingMenu.client.user.username }, 'Successful login'); + client.log.info( { username : callingMenu.client.user.username }, 'Successful login'); async.parallel( [ @@ -29,9 +29,18 @@ function login(callingMenu, formData, extraArgs) { client.currentTheme = theme; callback(null); // always non-fatal }); + }, + function recordLogin(callback) { + client.user.persistProperty('last_login_timestamp', new Date().toISOString(), function persisted(err) { + callback(err); + }); } ], function complete(err, results) { + if(err) { + client.log.error(err); + // :TODO: drop the connection? + } client.gotoMenuModule( { name : callingMenu.menuConfig.next } ); } ); diff --git a/core/theme.js b/core/theme.js index b6086aae..91b0fdba 100644 --- a/core/theme.js +++ b/core/theme.js @@ -208,8 +208,6 @@ function displayThemedPause(options, cb) { } // :TODO: Support animated pause prompts. Probably via MCI with AnimatedView - // :TODO: support prompts with a height > 1 - // :TODO: Prompt should support MCI codes in general var artInfo; var vc; diff --git a/core/user.js b/core/user.js index 56f399af..ce943e18 100644 --- a/core/user.js +++ b/core/user.js @@ -296,6 +296,18 @@ User.prototype.persist = function(useTransaction, cb) { ); }; +User.prototype.persistProperty = function(propName, propValue, cb) { + // update live props + this.properties[propName] = propValue; + + userDb.run( + 'REPLACE INTO user_property (user_id, prop_name, prop_value) ' + + 'VALUES (?, ?, ?);', [ this.userId, propName, propValue ], function ran(err) { + cb(err); + } + ); +} + User.prototype.persistProperties = function(cb) { assert(this.userId > 0); diff --git a/mods/last_callers.js b/mods/last_callers.js new file mode 100644 index 00000000..53e540a7 --- /dev/null +++ b/mods/last_callers.js @@ -0,0 +1,87 @@ +/* jslint node: true */ +'use strict'; + +var MenuModule = require('../core/menu_module.js').MenuModule; +var userDb = require('../core/database.js').dbs.user; +var ViewController = require('../core/view_controller.js').ViewController; + +exports.moduleInfo = { + name : 'Last Callers', + desc : 'Last 10 callers to the system', + author : 'NuSkooler', +}; + +exports.getModule = LastCallersModule; + +function LastCallersModule(menuConfig) { + MenuModule.call(this, menuConfig); +} + +require('util').inherits(LastCallersModule, MenuModule); + +LastCallersModule.prototype.mciReady = function(mciData) { + LastCallersModule.super_.prototype.mciReady.call(this, mciData); + + var lastCallers = []; + var self = this; + + // :TODO: durp... need a table just for this so dupes are possible + + var userInfoStmt = userDb.prepare( + 'SELECT prop_name, prop_value ' + + 'FROM user_property ' + + 'WHERE user_id=? AND (prop_name=? OR prop_name=?);'); + + var caller; + + userDb.each( + 'SELECT u.id, u.user_name, up.prop_value ' + + 'FROM user u ' + + 'INNER JOIN user_property up ' + + 'ON u.id=up.user_id AND up.prop_name="last_login_timestamp" ' + + 'ORDER BY up.prop_value DESC' + + 'LIMIT 10;', + function userRows(err, userEntry) { + caller = { name : userEntry.user_name }; + + userInfoStmt.each(userEntry.id, 'location', 'affiliation', function propRow(err, propEntry) { + console.log(propEntry) + if(!err) { + caller[propEntry.prop_name] = propEntry.prop_value; + } + }, function complete(err) { + lastCallers.push(caller); + }); + }, + function complete(err) { + // + // TL1=name, TL2=location, TL3=affils + // TL4=name, TL5=location, ... + // ... + // TL28=name, TL29=location, TL30=affils + // + var lc = self.viewControllers.lastCallers = new ViewController( { client : self.client }); + + var loadOpts = { + callingMenu : self, + mciMap : mciData.menu, + noInput : true, + }; + + self.viewControllers.lastCallers.loadFromMenuConfig(loadOpts, function viewsReady(err) { + console.log(lastCallers); + var callerIndex = 0; + for(var i = 1; i < 30; i += 3) { + if(lastCallers.length > callerIndex) { + lc.getView(i).setText(lastCallers[callerIndex].name); + lc.getView(i + 1).setText(lastCallers[callerIndex].location); + lc.getView(i + 2).setText(lastCallers[callerIndex].affiliation); + ++callerIndex; + } else { + + } + } + }); + } + ); +}; diff --git a/mods/menu.json b/mods/menu.json index 459226ac..b178e311 100644 --- a/mods/menu.json +++ b/mods/menu.json @@ -203,7 +203,14 @@ "options" : { // :TODO: implement MCI codes for this "cls" : true - } + }, + "pause" : true, + "action" : "@menu:lastCallers" + }, + "lastCallers" :{ + "module" : "last_callers", + "art" : "LASTCALL.ANS", + "options" : { "cls" : true } }, "demoMain" : { "art" : "demo_selection_vm.ans", diff --git a/mods/themes/NU-MAYA/LASTCALL.ANS b/mods/themes/NU-MAYA/LASTCALL.ANS new file mode 100644 index 00000000..75b1a73a Binary files /dev/null and b/mods/themes/NU-MAYA/LASTCALL.ANS differ