diff --git a/art/themes/luciano_blocktronics/theme.hjson b/art/themes/luciano_blocktronics/theme.hjson index bf28baab..6555f417 100644 --- a/art/themes/luciano_blocktronics/theme.hjson +++ b/art/themes/luciano_blocktronics/theme.hjson @@ -156,12 +156,15 @@ mainMenuUserList: { config: { - listFormat: "|00|11{userName:<17.17}|03{affils:<21.21}|11{note:<19.19}|03{lastLoginTs}" - focusListFormat: "|00|19|15{userName:<17.17}{affils:<21.21}{note:<19.19}{lastLoginTs}" dateTimeFormat: MMM Do h:mma } mci: { - VM1: { height: 15, width: 50} + VM1: { + height: 15, + width: 50 + itemFormat: "|00|11{userName:<17.17}|03{affils:<21.21}|11{note:<19.19}|03{lastLoginTs}" + focusItemFormat: "|00|19|15{userName:<17.17}{affils:<21.21}{note:<19.19}{lastLoginTs}" + } } } diff --git a/core/last_callers.js b/core/last_callers.js index ebc98d5f..268fde5f 100644 --- a/core/last_callers.js +++ b/core/last_callers.js @@ -2,10 +2,11 @@ 'use strict'; // ENiGMA½ -const { MenuModule } = require('./menu_module.js'); -const StatLog = require('./stat_log.js'); -const User = require('./user.js'); -const sysDb = require('./database.js').dbs.system; +const { MenuModule } = require('./menu_module.js'); +const StatLog = require('./stat_log.js'); +const User = require('./user.js'); +const sysDb = require('./database.js').dbs.system; +const { Errors } = require('./enig_error.js'); // deps const moment = require('moment'); @@ -19,8 +20,8 @@ exports.moduleInfo = { packageName : 'codes.l33t.enigma.lastcallers' }; -const MciCodeIds = { - CallerList : 1, +const MciViewIds = { + callerList : 1, }; exports.getModule = class LastCallersModule extends MenuModule { @@ -55,7 +56,10 @@ exports.getModule = class LastCallersModule extends MenuModule { }); }, (loginHistory, next) => { - const callersView = this.viewControllers.callers.getView(MciCodeIds.CallerList); + const callersView = this.viewControllers.callers.getView(MciViewIds.callerList); + if(!callersView) { + return cb(Errors.MissingMci(`Missing caller list MCI ${MciViewIds.callerList}`)); + } callersView.setItems(loginHistory); callersView.redraw(); return next(null); @@ -80,7 +84,7 @@ exports.getModule = class LastCallersModule extends MenuModule { } fetchHistory(cb) { - const callersView = this.viewControllers.callers.getView(MciCodeIds.CallerList); + const callersView = this.viewControllers.callers.getView(MciViewIds.callerList); if(!callersView || 0 === callersView.dimens.height) { return cb(null); } @@ -178,12 +182,12 @@ exports.getModule = class LastCallersModule extends MenuModule { return cb(null, null); } - item.userName = item.text = (userName || 'N/A'); + item.userName = item.text = userName; User.loadProperties(item.userId, getPropOpts, (err, props) => { - item.location = (props && props.location) || 'N/A'; - item.affiliation = item.affils = (props && props.affiliation) || 'N/A'; - item.realName = (props && props.real_name) || 'N/A'; + item.location = (props && props.location) || ''; + item.affiliation = item.affils = (props && props.affiliation) || ''; + item.realName = (props && props.real_name) || ''; if(!indicatorSumsSql) { return next(null, item); diff --git a/core/user.js b/core/user.js index 18acc02c..6c2b964d 100644 --- a/core/user.js +++ b/core/user.js @@ -537,8 +537,8 @@ module.exports = class User { } static getUserList(options, cb) { - let userList = []; - let orderClause = 'ORDER BY ' + (options.order || 'user_name'); + const userList = []; + const orderClause = 'ORDER BY ' + (options.order || 'user_name'); userDb.each( `SELECT id, user_name @@ -562,7 +562,11 @@ module.exports = class User { [ user.userId ], (err, row) => { if(row) { - user[row.prop_name] = row.prop_value; + if(options.propsCamelCase) { + user[_.camelCase(row.prop_name)] = row.prop_value; + } else { + user[row.prop_name] = row.prop_value; + } } }, err => { diff --git a/core/user_list.js b/core/user_list.js index 8af9690b..43922998 100644 --- a/core/user_list.js +++ b/core/user_list.js @@ -1,11 +1,12 @@ /* jslint node: true */ 'use strict'; -const MenuModule = require('./menu_module.js').MenuModule; -const User = require('./user.js'); -const ViewController = require('./view_controller.js').ViewController; -const stringFormat = require('./string_format.js'); +// ENiGMA½ +const { MenuModule } = require('./menu_module.js'); +const { getUserList } = require('./user.js'); +const { Errors } = require('./enig_error.js'); +// deps const moment = require('moment'); const async = require('async'); const _ = require('lodash'); @@ -29,7 +30,7 @@ exports.moduleInfo = { }; const MciViewIds = { - UserList : 1, + userList : 1, }; exports.getModule = class UserListModule extends MenuModule { @@ -43,68 +44,51 @@ exports.getModule = class UserListModule extends MenuModule { return cb(err); } - const self = this; - const vc = self.viewControllers.allViews = new ViewController( { client : self.client } ); - - let userList = []; - - const USER_LIST_OPTS = { - properties : [ 'location', 'affiliation', 'last_login_timestamp' ], - }; - async.series( [ - function loadFromConfig(callback) { - var loadOpts = { - callingMenu : self, - mciMap : mciData.menu, - }; - - vc.loadFromMenuConfig(loadOpts, callback); + (next) => { + return this.prepViewController('userList', 0, mciData.menu, next); }, - function fetchUserList(callback) { - // :TODO: Currently fetching all users - probably always OK, but this could be paged - User.getUserList(USER_LIST_OPTS, function got(err, ul) { - userList = ul; - callback(err); - }); - }, - function populateList(callback) { - var userListView = vc.getView(MciViewIds.UserList); - - var listFormat = self.menuConfig.config.listFormat || '{userName} - {affils}'; - var focusListFormat = self.menuConfig.config.focusListFormat || listFormat; // :TODO: default changed color! - var dateTimeFormat = self.menuConfig.config.dateTimeFormat || 'ddd MMM DD'; - - function getUserFmtObj(ue) { - return { - userId : ue.userId, - userName : ue.userName, - affils : ue.affiliation, - location : ue.location, - // :TODO: the rest! - note : ue.note || '', - lastLoginTs : moment(ue.last_login_timestamp).format(dateTimeFormat), - }; + (next) => { + const userListView = this.viewControllers.userList.getView(MciViewIds.userList); + if(!userListView) { + return cb(Errors.MissingMci(`Missing user list MCI ${MciViewIds.userList}`)); } - userListView.setItems(_.map(userList, function formatUserEntry(ue) { - return stringFormat(listFormat, getUserFmtObj(ue)); - })); + const fetchOpts = { + properties : [ 'real_name', 'location', 'affiliation', 'last_login_timestamp' ], + propsCamelCase : true, // e.g. real_name -> realName + }; + getUserList(fetchOpts, (err, userList) => { + if(err) { + return next(err); + } - userListView.setFocusItems(_.map(userList, function formatUserEntry(ue) { - return stringFormat(focusListFormat, getUserFmtObj(ue)); - })); + const dateTimeFormat = _.get( + this, 'menuConfig.config.dateTimeFormat', this.client.currentTheme.helpers.getDateTimeFormat('short')); - userListView.redraw(); - callback(null); + userList = userList.map(entry => { + return Object.assign( + entry, + { + text : entry.userName, + affils : entry.affiliation, + lastLoginTs : moment(entry.lastLoginTimestamp).format(dateTimeFormat), + } + ); + }); + + userListView.setItems(userList); + userListView.redraw(); + return next(null); + }); } ], - function complete(err) { + err => { if(err) { - self.client.log.error( { error : err.toString() }, 'Error loading user list'); + this.client.log.error( { error : err.message }, 'Error loading user list'); } - cb(err); + return cb(err); } ); }); diff --git a/core/whos_online.js b/core/whos_online.js index db3fc5c4..1078bc51 100644 --- a/core/whos_online.js +++ b/core/whos_online.js @@ -38,13 +38,13 @@ exports.getModule = class WhosOnlineModule extends MenuModule { return this.prepViewController('online', 0, mciData.menu, next); }, (next) => { - const onlineListView = this.viewControllers.online.getView(MciViewIds.OnlineList); + const onlineListView = this.viewControllers.online.getView(MciViewIds.onlineList); if(!onlineListView) { - return cb(Errors.MissingMci(`Missing online list MCI ${MciViewIds.OnlineList}`)); + return cb(Errors.MissingMci(`Missing online list MCI ${MciViewIds.onlineList}`)); } const onlineList = getActiveNodeList(true).slice(0, onlineListView.height).map( - oe => Object.assign(oe, { timeOn : _.upperFirst(oe.timeOn.humanize()) }) + oe => Object.assign(oe, { text : oe.userName, timeOn : _.upperFirst(oe.timeOn.humanize()) }) ); onlineListView.setItems(onlineList); diff --git a/docs/_includes/nav.md b/docs/_includes/nav.md index d781ed45..d7ada9e2 100644 --- a/docs/_includes/nav.md +++ b/docs/_includes/nav.md @@ -66,6 +66,7 @@ - [Existing Mods]({{ site.baseurl }}{% link modding/existing-mods.md %}) - [Last Callers]({{ site.baseurl }}{% link modding/last-callers.md %}) - [Who's Online]({{ site.baseurl }}{% link modding/whos-online.md %}) + - [User List]({{ site.baseurl }}{% link modding/user-list.md %}) - [Oputil]({{ site.baseurl }}{% link oputil/index.md %}) diff --git a/docs/modding/last-callers.md b/docs/modding/last-callers.md index 8778b1e0..f754a912 100644 --- a/docs/modding/last-callers.md +++ b/docs/modding/last-callers.md @@ -27,10 +27,11 @@ Remember that entries such as `actionIndicators` and `actionIndicatorDefault` ma ### Theming The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`): * `userId`: User ID. -* `realName`: User's real name or "N/A". +* `userName`: Login username. +* `realName`: User's real name. * `ts`: Timestamp in `dateTimeFormat` format. -* `location`: User's location or "N/A". -* `affiliation` or `affils`: Users affiliations or "N/A". +* `location`: User's location. +* `affiliation` or `affils`: Users affiliations. * `actions`: A string built by concatenating action indicators for a users logged in session. For example, given a indincator of `userDownload` mapped to "D", the string may be "-D----". The format was made popular on Amiga style boards. diff --git a/docs/modding/user-list.md b/docs/modding/user-list.md new file mode 100644 index 00000000..9aae4750 --- /dev/null +++ b/docs/modding/user-list.md @@ -0,0 +1,24 @@ +--- +layout: page +title: User List +--- +## The User List Module +The built in `user_list` module provides basic user list functionality. + +## Configuration +### Config Block +Available `config` block entries: +* `dateTimeFormat`: [moment.js](https://momentjs.com) style format. Defaults to current theme → system `short` format. + +### Theming +The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`): +* `userId`: User ID. +* `userName`: Login username. +* `realName`: User's real name. +* `lastLoginTimestamp`: Full last login timestamp for formatting use. +* `lastLoginTs`: Last login timestamp formatted with `dateTimeFormat` style. +* `location`: User's location. +* `affiliation` or `affils`: Users affiliations. + + + diff --git a/docs/modding/whos-online.md b/docs/modding/whos-online.md index feec5f7e..87a2b1ef 100644 --- a/docs/modding/whos-online.md +++ b/docs/modding/whos-online.md @@ -8,6 +8,7 @@ The built in `whos_online` module provides a basic who's online mod. ### Theming The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`): * `userId`: User ID. +* `userName`: Login username. * `node`: Node ID the user is connected to. * `timeOn`: A human friendly amount of time the user has been online. * `realName`: User's real name.