* ButtonView is now MCI BT. BN is pre-defined "Board Name"
* Client current theme info loaded & used for e.g. passwordChar * Code cleanup
This commit is contained in:
parent
5eee568586
commit
586f3d60b3
25
core/bbs.js
25
core/bbs.js
|
@ -12,6 +12,7 @@ var iconv = require('iconv-lite');
|
|||
var paths = require('path');
|
||||
var async = require('async');
|
||||
var util = require('util');
|
||||
var async = require('async');
|
||||
|
||||
exports.bbsMain = bbsMain;
|
||||
|
||||
|
@ -194,10 +195,26 @@ function prepareClient(client, cb) {
|
|||
// :TODO: it feels like this should go somewhere else... and be a bit more elegant.
|
||||
if('*' === conf.config.preLoginTheme) {
|
||||
var theme = require('./theme.js');
|
||||
theme.getRandomTheme(function onRandTheme(err, themeId) {
|
||||
client.user.properties.art_theme_id = themeId || '';
|
||||
cb(null);
|
||||
});
|
||||
|
||||
async.waterfall(
|
||||
[
|
||||
function getRandTheme(callback) {
|
||||
theme.getRandomTheme(function randTheme(err, themeId) {
|
||||
client.user.properties.art_theme_id = themeId || '';
|
||||
callback(null);
|
||||
});
|
||||
},
|
||||
function setCurrentThemeInfo(callback) {
|
||||
theme.getThemeInfo(client.user.properties.art_theme_id, function themeInfo(err, info) {
|
||||
client.currentThemeInfo = info;
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
],
|
||||
function complete(err) {
|
||||
cb(err);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
client.user.properties.art_theme_id = conf.config.preLoginTheme;
|
||||
cb(null);
|
||||
|
|
|
@ -224,6 +224,10 @@ Client.prototype.gotoMenuModule = function(options, cb) {
|
|||
});
|
||||
};
|
||||
|
||||
Client.prototype.fallbackMenuModule = function(cb) {
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Default error handlers
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -31,6 +31,8 @@ module.exports = {
|
|||
usernameMin : 2,
|
||||
usernameMax : 22,
|
||||
passwordMin : 6,
|
||||
requireActivation : true, // require SysOp activation?
|
||||
defaultTheme : 'NU-MAYA',
|
||||
},
|
||||
|
||||
paths : {
|
||||
|
|
|
@ -86,7 +86,6 @@ function connectEntry(client) {
|
|||
term.write(ansi.clearScreen());
|
||||
|
||||
client.gotoMenuModule({ name : Config.entryMod } );
|
||||
//moduleUtil.goto(Config.entryMod, client);
|
||||
}, timeout);
|
||||
});
|
||||
}, 500);
|
||||
|
|
|
@ -7,7 +7,11 @@ var ButtonView = require('./button_view.js').ButtonView;
|
|||
var VerticalMenuView = require('./vertical_menu_view.js').VerticalMenuView;
|
||||
var Config = require('./config.js').config;
|
||||
var packageJson = require('../package.json');
|
||||
|
||||
|
||||
var assert = require('assert');
|
||||
var os = require('os');
|
||||
var _ = require('lodash');
|
||||
|
||||
exports.MCIViewFactory = MCIViewFactory;
|
||||
|
||||
|
@ -15,12 +19,30 @@ function MCIViewFactory(client) {
|
|||
this.client = client;
|
||||
}
|
||||
|
||||
MCIViewFactory.prototype.getPredefinedViewLabel = function(name) {
|
||||
MCIViewFactory.prototype.getPredefinedViewLabel = function(code) {
|
||||
var label;
|
||||
switch(name) {
|
||||
switch(code) {
|
||||
// :TODO: Fix conflict with ButtonView (BN); chagne to BT
|
||||
case 'BN' : label = Config.bbsName; break;
|
||||
case 'VL' : label = 'ENiGMA½ v' + packageJson.version; break;
|
||||
case 'VN' : label = packageJson.version; break;
|
||||
|
||||
case 'UN' : label = this.client.user.username; break;
|
||||
case 'UR' : label = this.client.user.properties.real_name; break;
|
||||
case 'LO' : label = this.client.user.properties.location; break;
|
||||
|
||||
case 'OS' :
|
||||
switch(os.platform()) {
|
||||
case 'linux' : label = 'Linux'; break;
|
||||
case 'darwin' : label = 'OS X'; break;
|
||||
case 'win32' : label = 'Windows'; break;
|
||||
case 'sunos' : label = 'SunOS'; break;
|
||||
default : label = os.type(); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'OA' : label = os.arch(); break;
|
||||
case 'SC' : label = os.cpus()[0].model; break;
|
||||
}
|
||||
|
||||
return label;
|
||||
|
@ -56,6 +78,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci) {
|
|||
}
|
||||
|
||||
switch(mci.code) {
|
||||
// Text Label (Text View)
|
||||
case 'TL' :
|
||||
setOption(0, 'textStyle');
|
||||
setOption(1, 'justify');
|
||||
|
@ -67,6 +90,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci) {
|
|||
view = new TextView(options);
|
||||
break;
|
||||
|
||||
// Edit Text
|
||||
case 'ET' :
|
||||
if(setOption(0, 'maxLength')) {
|
||||
options.maxLength = parseInt(options.maxLength, 10);
|
||||
|
@ -75,11 +99,29 @@ MCIViewFactory.prototype.createFromMCI = function(mci) {
|
|||
|
||||
setOption(1, 'textStyle');
|
||||
|
||||
if(options.textStyle === 'P') {
|
||||
// Supply from theme, if available
|
||||
// :TODO: Move this logic elsewhere
|
||||
if(this.client.currentThemeInfo && this.client.currentThemeInfo.config) {
|
||||
var themePwChar = this.client.currentThemeInfo.config.passwordChar;
|
||||
if(_.isString(themePwChar)) {
|
||||
options.textMaskChar = themePwChar.substr(0, 1);
|
||||
} else if(_.isNumber(themePwChar)) {
|
||||
options.textMaskChar = String.fromCharCode(themePwChar);
|
||||
} else {
|
||||
options.textMaskChar = '*';
|
||||
}
|
||||
} else {
|
||||
options.textMaskChar = '*';
|
||||
}
|
||||
}
|
||||
|
||||
setFocusOption(0, 'focusTextStyle');
|
||||
|
||||
view = new EditTextView(options);
|
||||
break;
|
||||
|
||||
// Pre-defined Label (Text View)
|
||||
case 'PL' :
|
||||
if(mci.args.length > 0) {
|
||||
options.text = this.getPredefinedViewLabel(mci.args[0]);
|
||||
|
@ -97,7 +139,8 @@ MCIViewFactory.prototype.createFromMCI = function(mci) {
|
|||
}
|
||||
break;
|
||||
|
||||
case 'BN' :
|
||||
// Button
|
||||
case 'BT' :
|
||||
if(mci.args.length > 0) {
|
||||
options.dimens = { width : parseInt(mci.args[0], 10) };
|
||||
}
|
||||
|
@ -110,6 +153,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci) {
|
|||
view = new ButtonView(options);
|
||||
break;
|
||||
|
||||
// Vertial Menu
|
||||
case 'VM' :
|
||||
setOption(0, 'itemSpacing');
|
||||
setOption(1, 'justify');
|
||||
|
@ -119,6 +163,13 @@ MCIViewFactory.prototype.createFromMCI = function(mci) {
|
|||
|
||||
view = new VerticalMenuView(options);
|
||||
break;
|
||||
|
||||
default :
|
||||
options.text = this.getPredefinedViewLabel(mci.code);
|
||||
if(options.text) {
|
||||
view = new TextView(options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return view;
|
||||
|
|
|
@ -27,7 +27,7 @@ function MenuModule(options) {
|
|||
self.beforeArt();
|
||||
callback(null);
|
||||
},
|
||||
function displayArt(callback) {
|
||||
function displayArt(callback) {
|
||||
theme.displayThemeArt(self.menuConfig.art, self.client, function onArt(err, mciMap) {
|
||||
// :TODO: If the art simply is not found, or failed to load... we need to continue
|
||||
if(err) {
|
||||
|
|
|
@ -60,7 +60,7 @@ function TextView(options) {
|
|||
this.setText(options.text || '');
|
||||
|
||||
if(this.isPasswordTextStyle) {
|
||||
this.textMaskChar = miscUtil.valueWithDefault(this.textMaskChar, '*').substr(0, 1);
|
||||
this.textMaskChar = miscUtil.valueWithDefault(options.textMaskChar, '*').substr(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,11 @@ var Config = require('./config.js').config;
|
|||
var art = require('./art.js');
|
||||
var miscUtil = require('./misc_util.js');
|
||||
var Log = require('./logger.js').log;
|
||||
|
||||
var fs = require('fs');
|
||||
var paths = require('path');
|
||||
var async = require('async');
|
||||
var _ = require('lodash');
|
||||
|
||||
exports.getThemeInfo = getThemeInfo;
|
||||
exports.getThemeArt = getThemeArt;
|
||||
|
@ -23,6 +25,7 @@ function getThemeInfo(themeID, cb) {
|
|||
cb(err);
|
||||
} else {
|
||||
try {
|
||||
// :TODO: strip comments/etc. ala menu.json
|
||||
var info = JSON.parse(data);
|
||||
cb(null, info);
|
||||
} catch(e) {
|
||||
|
@ -85,7 +88,7 @@ function getRandomTheme(cb) {
|
|||
|
||||
function getThemeArt(name, themeID, options, cb) {
|
||||
// allow options to be optional
|
||||
if(typeof cb === 'undefined') {
|
||||
if(_.isUndefined(cb)) {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
|
|
17
core/user.js
17
core/user.js
|
@ -2,6 +2,8 @@
|
|||
'use strict';
|
||||
|
||||
var userDb = require('./database.js').dbs.user;
|
||||
var Config = require('./config.js').config;
|
||||
|
||||
var crypto = require('crypto');
|
||||
var assert = require('assert');
|
||||
var async = require('async');
|
||||
|
@ -55,6 +57,12 @@ User.StandardPropertyGroups = {
|
|||
password : [ 'pw_pbkdf2_salt', 'pw_pbkdf2_dk' ],
|
||||
};
|
||||
|
||||
User.AccountStatus = {
|
||||
disabled : -1,
|
||||
inactive : 0,
|
||||
active : 1,
|
||||
};
|
||||
|
||||
User.prototype.authenticate = function(username, password, cb) {
|
||||
var self = this;
|
||||
|
||||
|
@ -154,6 +162,9 @@ User.prototype.create = function(options, cb) {
|
|||
|
||||
var self = this;
|
||||
|
||||
// :TODO: set various defaults, e.g. default activation status, etc.
|
||||
self.properties.account_status = Config.users.requireActivation ? User.AccountStatus.inactive : User.AccountStatus.active;
|
||||
|
||||
async.series(
|
||||
[
|
||||
function beginTransaction(callback) {
|
||||
|
@ -171,6 +182,12 @@ User.prototype.create = function(options, cb) {
|
|||
callback(err);
|
||||
} else {
|
||||
self.userId = this.lastID;
|
||||
|
||||
// Do not SGRValuesre activation for userId 1 (root/admin)
|
||||
if(1 === self.userId) {
|
||||
self.properties.account_status = User.AccountStatus.active;
|
||||
}
|
||||
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,8 @@ function ApplyModule(menuConfig) {
|
|||
affiliation : args.affils,
|
||||
email_address : args.email,
|
||||
web_address : args.web,
|
||||
art_theme_id : Config.users.defaultTheme, // :TODO: allow '*' = random
|
||||
account_status : user.User.AccountStatus.inactive,
|
||||
|
||||
// :TODO: Other defaults
|
||||
// :TODO: should probably have a place to create defaults/etc.
|
||||
|
@ -64,9 +66,15 @@ function ApplyModule(menuConfig) {
|
|||
|
||||
newUser.create({ password : args.pw }, function created(err) {
|
||||
if(err) {
|
||||
console.log(err)
|
||||
self.client.gotoMenuModule( { name : args.next.error } );
|
||||
} else {
|
||||
Log.info( { username : args.username, userId : newUser.userId }, 'New user created');
|
||||
|
||||
if(user.User.AccountStatus.inactive === self.client.user.properties.account_status) {
|
||||
self.client.gotoMenuModule( { name : args.next.inactive } );
|
||||
} else {
|
||||
self.client.gotoMenuModule( { name : args.next.active } );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -2,6 +2,6 @@
|
|||
"name" : "Nu Mayan",
|
||||
"author" : "NuSkooler",
|
||||
"config" : {
|
||||
"passwordChar" : "*"
|
||||
"passwordChar" : "φ"
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ var Log = require('../core/logger.js').log;
|
|||
var MenuModule = require('../core/menu_module.js').MenuModule;
|
||||
var ViewController = require('../core/view_controller.js').ViewController;
|
||||
|
||||
//var async = require('async');
|
||||
var async = require('async');
|
||||
|
||||
// :TODO: clean up requires
|
||||
|
||||
|
@ -33,6 +33,8 @@ function LoginModule(menuConfig) {
|
|||
this.menuMethods.attemptLogin = function(args) {
|
||||
self.client.user.authenticate(args.username, args.password, function onAuth(err) {
|
||||
if(err) {
|
||||
// :TODO: change to simple login/username prompts - no buttons.
|
||||
|
||||
Log.info( { username : args.username }, 'Failed login attempt %s', err);
|
||||
|
||||
// :TODO: localize:
|
||||
|
@ -52,6 +54,20 @@ function LoginModule(menuConfig) {
|
|||
Log.info( { username : self.client.user.username }, 'Successful login');
|
||||
|
||||
// :TODO: persist information about login to user
|
||||
|
||||
async.parallel(
|
||||
[
|
||||
function loadThemeConfig(callback) {
|
||||
theme.getThemeInfo(self.client.user.properties.art_theme_id, function themeInfo(err, info) {
|
||||
self.client.currentThemeInfo = info;
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
],
|
||||
function complete(err, results) {
|
||||
self.client.gotoMenuModule( { name : args.next.success } );
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Some concept/ideas:
|
||||
"mci" : {
|
||||
"BN1" : {
|
||||
"BT1" : {
|
||||
...
|
||||
"draw" : "@script:blah.js/drawButton"
|
||||
// @method:scriptName[.js]/methodName (foreign .js)
|
||||
|
@ -16,6 +16,7 @@
|
|||
}
|
||||
|
||||
..note that script/methods should be part of a *theme* - or at least checked first with fallback
|
||||
.....why?
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -60,16 +61,16 @@
|
|||
"module" : "login",
|
||||
"form" : {
|
||||
"0" : {
|
||||
"BN3BN4ET1ET2TL5" :{
|
||||
"BT3BT4ET1ET2TL5" :{
|
||||
"mci" :{
|
||||
"ET1" : {
|
||||
"focus" : true
|
||||
},
|
||||
"BN3" : {
|
||||
"BT3" : {
|
||||
"submit" : true,
|
||||
"text" : "Login"
|
||||
},
|
||||
"BN4" : {
|
||||
"BT4" : {
|
||||
"submit" : true,
|
||||
"text" : "Cancel"
|
||||
}
|
||||
|
@ -79,10 +80,16 @@
|
|||
{
|
||||
"value" : { "3" : null },
|
||||
"action" : "@method:attemptLogin",
|
||||
"args" : { "username" : "{1}", "password" : "{2}" } // :TODO: rename to actionArgs ?
|
||||
"args" : {
|
||||
"next" : {
|
||||
"success" : "newUserActive"
|
||||
},
|
||||
"username" : "{1}",
|
||||
"password" : "{2}"
|
||||
} // :TODO: rename to actionArgs ?
|
||||
}
|
||||
],
|
||||
"4" : [ // cancel
|
||||
"4" : [ // Cancel
|
||||
{
|
||||
"value" : { "4" : null },
|
||||
"action" : "@menu:matrix"
|
||||
|
@ -105,16 +112,16 @@
|
|||
"module" : "apply",
|
||||
"form" : {
|
||||
"0" : {
|
||||
"BN12BN13ET1ET10ET2ET3ET4ET5ET6ET7ET8ET9TL11" : {
|
||||
"BT12BT13ET1ET10ET2ET3ET4ET5ET6ET7ET8ET9TL11" : {
|
||||
"mci" : {
|
||||
"ET1" : {
|
||||
"focus" : true
|
||||
},
|
||||
"BN12" : {
|
||||
"BT12" : {
|
||||
"submit" : true,
|
||||
"text" : "Apply"
|
||||
},
|
||||
"BN13" : {
|
||||
"BT13" : {
|
||||
"submit" : true,
|
||||
"text" : "Cancel"
|
||||
}
|
||||
|
@ -124,10 +131,12 @@
|
|||
{
|
||||
"value" : { "12" : null },
|
||||
"action" : "@method:submitApplication",
|
||||
// :TODO: Need a way to supply next menu based on data from @method
|
||||
// @method:submitApplication|nextMenu1|nextMenu2|nextMenu3 ? method could cb(indexValue)
|
||||
|
||||
"args" : {
|
||||
"next" : {
|
||||
"inactive" : "userNeedsActivated",
|
||||
"active" : "newUserActive",
|
||||
"error" : "newUserCreateError"
|
||||
},
|
||||
"username" : "{1}",
|
||||
"realName" : "{2}",
|
||||
"age" : "{3}",
|
||||
|
@ -143,7 +152,7 @@
|
|||
],
|
||||
"13" : [ // Cancel
|
||||
{
|
||||
"value" : { "13" : null },
|
||||
"value" : { "13" : null }, // :TODO: allow just "13" (number)
|
||||
"action" : "@menu:matrix"
|
||||
}
|
||||
]
|
||||
|
@ -154,5 +163,20 @@
|
|||
"options" : {
|
||||
"clearScreen" : true
|
||||
}
|
||||
},
|
||||
"newUserActive" : {
|
||||
"art" : "NEWACT",
|
||||
"options" : {
|
||||
"clearScreen" : true
|
||||
},
|
||||
"form" : {
|
||||
"0" : {
|
||||
"UN1UR2" : {
|
||||
"mci" : {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,91 +43,5 @@ StandardMenuModule.prototype.mciReady = function(mciMap) {
|
|||
console.log(formData);
|
||||
});*/
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
menuUtil.getFormConfig(self.menuConfig, mciMap, function onFormConfig(err, formConfig) {
|
||||
console.log(formConfig);
|
||||
var vc = self.addViewController(new ViewController(self.client));
|
||||
vc.loadFromMCIMap(mciMap);
|
||||
vc.setViewOrder();
|
||||
|
||||
Object.keys(formConfig.mci).forEach(function onFormMci(mci) {
|
||||
var viewId = parseInt(mci[2]);
|
||||
if(formConfig.mci[mci].items && formConfig.mci[mci].items.length > 0) {
|
||||
vc.getView(viewId).setItems(formConfig.mci[mci].items);
|
||||
}
|
||||
});
|
||||
|
||||
//vc.getView(1).setItems(['Login', 'New User', 'Goodbye!']);
|
||||
vc.getView(1).submit = true;
|
||||
vc.switchFocus(1);
|
||||
});
|
||||
*/
|
||||
|
||||
/*
|
||||
{
|
||||
"menuName" : {
|
||||
"form" : [
|
||||
{
|
||||
"mciReq" : [ "MC1", "MC2", ... ],
|
||||
"MC1" : {
|
||||
"text" : "...",
|
||||
"focus" : true,
|
||||
"submit" : true,
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
if(mciMap.ET1 && mciMap.ET2 && mciMap.BN1 && mciMap.BN2 && mciMap.BN3) {
|
||||
//
|
||||
// Form via EditTextViews and ButtonViews
|
||||
// * ET1 - userName
|
||||
// * ET2 - password
|
||||
// * BN1 - Login
|
||||
// * BN2 - New
|
||||
// * BN3 - Bye!
|
||||
//
|
||||
} else if(mciMap.VM1) {
|
||||
//
|
||||
// Menu via VerticalMenuView
|
||||
//
|
||||
// * VM1 - menu with the following items:
|
||||
// 0 - Login
|
||||
// 1 - New
|
||||
// 2 - Bye!
|
||||
//
|
||||
//var vc = new ViewController(client);
|
||||
var vc = self.addViewController(new ViewController(self.client));
|
||||
|
||||
vc.on('submit', function onSubmit(form) {
|
||||
console.log(form);
|
||||
|
||||
var viewModuleMap = {
|
||||
'0' : 'login',
|
||||
'1' : 'new',
|
||||
'2' : 'logoff',
|
||||
};
|
||||
|
||||
if(0 === form.id && 1 === form.submitId) {
|
||||
console.log(viewModuleMap[form.value[1]]);
|
||||
self.client.gotoMenuModule(viewModuleMap[form.value[1]]);
|
||||
}
|
||||
});
|
||||
|
||||
vc.loadFromMCIMap(mciMap);
|
||||
vc.setViewOrder();
|
||||
// :TODO: Localize
|
||||
vc.getView(1).setItems(['Login', 'New User', 'Goodbye!']);
|
||||
vc.getView(1).submit = true;
|
||||
vc.switchFocus(1);
|
||||
}
|
||||
*/
|
||||
});
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue