Merge branch 'master' of ssh://numinibsd/git/base/enigma-bbs
This commit is contained in:
commit
ab596842d6
|
@ -2,15 +2,27 @@
|
|||
'use strict';
|
||||
|
||||
//
|
||||
// ANSI Terminal Support
|
||||
// ANSI Terminal Support Resources
|
||||
//
|
||||
// Resources:
|
||||
// ANSI-BBS
|
||||
// * http://ansi-bbs.org/
|
||||
//
|
||||
// CTerm / SyncTERM
|
||||
// * https://github.com/protomouse/synchronet/blob/master/src/conio/cterm.txt
|
||||
//
|
||||
// BananaCom
|
||||
// * http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/bansi.txt
|
||||
//
|
||||
// ANSI.SYS
|
||||
// * http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/ansisys.txt
|
||||
// * http://academic.evergreen.edu/projects/biophysics/technotes/program/ansi_esc.htm
|
||||
//
|
||||
// General
|
||||
// * http://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
// * https://github.com/chjj/term.js/blob/master/src/term.js
|
||||
// * http://www.inwap.com/pdp10/ansicode.txt
|
||||
//
|
||||
// Other Implementations
|
||||
// * https://github.com/chjj/term.js/blob/master/src/term.js
|
||||
|
||||
// ENiGMA½
|
||||
const miscUtil = require('./misc_util.js');
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
// ENiGMA½
|
||||
const Config = require('./config.js').config;
|
||||
const stringFormat = require('./string_format.js');
|
||||
|
||||
// base/modules
|
||||
const fs = require('fs');
|
||||
|
@ -124,7 +125,7 @@ module.exports = class ArchiveUtil {
|
|||
|
||||
let args = _.clone(archiver.compressArgs); // don't muck with orig
|
||||
for(let i = 0; i < args.length; ++i) {
|
||||
args[i] = args[i].format({
|
||||
args[i] = stringFormat(args[i], {
|
||||
archivePath : archivePath,
|
||||
fileList : files.join(' '),
|
||||
});
|
||||
|
@ -144,7 +145,7 @@ module.exports = class ArchiveUtil {
|
|||
|
||||
let args = _.clone(archiver.decompressArgs); // don't muck with orig
|
||||
for(let i = 0; i < args.length; ++i) {
|
||||
args[i] = args[i].format({
|
||||
args[i] = stringFormat(args[i], {
|
||||
archivePath : archivePath,
|
||||
extractPath : extractPath,
|
||||
});
|
||||
|
|
21
core/bbs.js
21
core/bbs.js
|
@ -128,10 +128,10 @@ function initialize(cb) {
|
|||
if(err) {
|
||||
console.error('Could not create path: ' + conf.config.paths[pathKey] + ': ' + err.toString());
|
||||
}
|
||||
next(err);
|
||||
return next(err);
|
||||
});
|
||||
}, function dirCreationComplete(err) {
|
||||
callback(err);
|
||||
return callback(err);
|
||||
});
|
||||
},
|
||||
function basicInit(callback) {
|
||||
|
@ -142,22 +142,19 @@ function initialize(cb) {
|
|||
|
||||
process.on('SIGINT', shutdownSystem);
|
||||
|
||||
// Init some extensions
|
||||
require('string-format').extend(String.prototype, require('./string_util.js').stringFormatExtensions);
|
||||
|
||||
callback(null);
|
||||
return callback(null);
|
||||
},
|
||||
function initDatabases(callback) {
|
||||
database.initializeDatabases(callback);
|
||||
return database.initializeDatabases(callback);
|
||||
},
|
||||
function initStatLog(callback) {
|
||||
require('./stat_log.js').init(callback);
|
||||
return require('./stat_log.js').init(callback);
|
||||
},
|
||||
function initThemes(callback) {
|
||||
// Have to pull in here so it's after Config init
|
||||
require('./theme.js').initAvailableThemes(function onThemesInit(err, themeCount) {
|
||||
logger.log.info({ themeCount : themeCount }, 'Themes initialized');
|
||||
callback(err);
|
||||
return callback(err);
|
||||
});
|
||||
},
|
||||
function loadSysOpInformation(callback) {
|
||||
|
@ -204,10 +201,10 @@ function initialize(cb) {
|
|||
);
|
||||
},
|
||||
function initMCI(callback) {
|
||||
require('./predefined_mci.js').init(callback);
|
||||
return require('./predefined_mci.js').init(callback);
|
||||
},
|
||||
function readyMessageNetworkSupport(callback) {
|
||||
require('./msg_network.js').startup(callback);
|
||||
return require('./msg_network.js').startup(callback);
|
||||
},
|
||||
function readyEventScheduler(callback) {
|
||||
const EventSchedulerModule = require('./event_scheduler.js').EventSchedulerModule;
|
||||
|
@ -218,7 +215,7 @@ function initialize(cb) {
|
|||
}
|
||||
],
|
||||
function onComplete(err) {
|
||||
cb(err);
|
||||
return cb(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -292,7 +292,17 @@ function getDefaultConfig() {
|
|||
},
|
||||
|
||||
logging : {
|
||||
level : 'debug'
|
||||
level : 'debug',
|
||||
|
||||
rotatingFile : { // set to 'disabled' or false to disable
|
||||
type : 'rotating-file',
|
||||
fileName : 'enigma-bbs.log',
|
||||
period : '1d',
|
||||
count : 3,
|
||||
level : 'debug',
|
||||
}
|
||||
|
||||
// :TODO: syslog - https://github.com/mcavage/node-bunyan-syslog
|
||||
},
|
||||
|
||||
debug : {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
|
||||
const stringFormat = require('./string_format.js');
|
||||
|
||||
const events = require('events');
|
||||
const _ = require('lodash');
|
||||
const pty = require('ptyw.js');
|
||||
|
@ -100,7 +103,7 @@ Door.prototype.run = function() {
|
|||
let args = _.clone(self.exeInfo.args); // we need a copy so the original is not modified
|
||||
|
||||
for(let i = 0; i < args.length; ++i) {
|
||||
args[i] = self.exeInfo.args[i].format({
|
||||
args[i] = stringFormat(self.exeInfo.args[i], {
|
||||
dropFile : self.exeInfo.dropFile,
|
||||
node : self.exeInfo.node.toString(),
|
||||
srvPort : sockServer ? sockServer.address().port.toString() : '-1',
|
||||
|
|
43
core/fse.js
43
core/fse.js
|
@ -2,17 +2,16 @@
|
|||
'use strict';
|
||||
|
||||
// ENiGMA½
|
||||
const MenuModule = require('../core/menu_module.js').MenuModule;
|
||||
const ViewController = require('../core/view_controller.js').ViewController;
|
||||
const ansi = require('../core/ansi_term.js');
|
||||
const theme = require('../core/theme.js');
|
||||
const Message = require('../core/message.js');
|
||||
const getMessageAreaByTag = require('../core/message_area.js').getMessageAreaByTag;
|
||||
const updateMessageAreaLastReadId = require('../core/message_area.js').updateMessageAreaLastReadId;
|
||||
const getUserIdAndName = require('../core/user.js').getUserIdAndName;
|
||||
const cleanControlCodes = require('../core/string_util.js').cleanControlCodes;
|
||||
const MenuModule = require('./menu_module.js').MenuModule;
|
||||
const ViewController = require('./view_controller.js').ViewController;
|
||||
const ansi = require('./ansi_term.js');
|
||||
const theme = require('./theme.js');
|
||||
const Message = require('./message.js');
|
||||
const updateMessageAreaLastReadId = require('./message_area.js').updateMessageAreaLastReadId;
|
||||
const getUserIdAndName = require('./user.js').getUserIdAndName;
|
||||
const cleanControlCodes = require('./string_util.js').cleanControlCodes;
|
||||
const StatLog = require('./stat_log.js');
|
||||
|
||||
const stringFormat = require('./string_format.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
|
@ -851,6 +850,21 @@ function FullScreenEditorModule(options) {
|
|||
});
|
||||
};
|
||||
|
||||
this.getQuoteByHeader = function() {
|
||||
let quoteFormat = this.menuConfig.config.quoteFormats;
|
||||
if(Array.isArray(quoteFormat)) {
|
||||
quoteFormat = quoteFormat[ Math.floor(Math.random() * quoteFormat.length) ];
|
||||
} else if(!_.isString(quoteFormat)) {
|
||||
quoteFormat = 'On {dateTime} {userName} said...';
|
||||
}
|
||||
|
||||
const dtFormat = this.menuConfig.config.quoteDateTimeFormat || self.client.currentTheme.helpers.getDateTimeFormat();
|
||||
return stringFormat(quoteFormat, {
|
||||
dateTime : moment(self.replyToMessage.modTimestamp).format(dtFormat),
|
||||
userName : self.replyToMessage.fromUserName,
|
||||
});
|
||||
};
|
||||
|
||||
this.menuMethods = {
|
||||
//
|
||||
// Validation stuff
|
||||
|
@ -917,14 +931,7 @@ function FullScreenEditorModule(options) {
|
|||
|
||||
if(self.newQuoteBlock) {
|
||||
self.newQuoteBlock = false;
|
||||
|
||||
// :TODO: Make date/time format avail as FSE config -- also the line itself!
|
||||
var dtFormat = self.client.currentTheme.helpers.getDateTimeFormat();
|
||||
quoteMsgView.addText(
|
||||
'On {0} {1} said...'.format(
|
||||
moment(self.replyToMessage.modTimestamp).format(dtFormat),
|
||||
self.replyToMessage.fromUserName)
|
||||
);
|
||||
quoteMsgView.addText(self.getQuoteByHeader());
|
||||
}
|
||||
|
||||
var quoteText = self.viewControllers.quoteBuilder.getView(3).getItem(formData.value.quote);
|
||||
|
|
105
core/logger.js
105
core/logger.js
|
@ -1,63 +1,74 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var bunyan = require('bunyan');
|
||||
var paths = require('path');
|
||||
var fs = require('fs');
|
||||
// deps
|
||||
const bunyan = require('bunyan');
|
||||
const paths = require('path');
|
||||
const fs = require('fs');
|
||||
const _ = require('lodash');
|
||||
|
||||
module.exports = {
|
||||
init : function() {
|
||||
var Config = require('./config.js').config;
|
||||
//var ringBufferLimit = miscUtil.valueWithDefault(config.logRingBufferLimit, 100);
|
||||
var logPath = Config.paths.logs;
|
||||
module.exports = class Log {
|
||||
|
||||
//
|
||||
// Create something a bit more friendly if the log directory cannot be used
|
||||
//
|
||||
// :TODO: this seems cheesy...
|
||||
var logPathError;
|
||||
try {
|
||||
var pathStat = fs.statSync(logPath);
|
||||
if(!pathStat.isDirectory()) {
|
||||
logPathError = logPath + ' is not a directory!';
|
||||
}
|
||||
} catch(e) {
|
||||
if('ENOENT' === e.code) {
|
||||
logPathError = 'No such file or directory: ' + logPath;
|
||||
} else {
|
||||
logPathError = e.message;
|
||||
}
|
||||
static init() {
|
||||
const Config = require('./config.js').config;
|
||||
const logPath = Config.paths.logs;
|
||||
|
||||
const err = this.checkLogPath(logPath);
|
||||
if(err) {
|
||||
console.error(err.message); // eslint-disable-line no-console
|
||||
return process.exit();
|
||||
}
|
||||
|
||||
if(logPathError) {
|
||||
console.error(logPathError);
|
||||
process.exit();
|
||||
const logStreams = [];
|
||||
if(_.isObject(Config.logging.rotatingFile)) {
|
||||
Config.logging.rotatingFile.path = paths.join(logPath, Config.logging.rotatingFile.fileName);
|
||||
logStreams.push(Config.logging.rotatingFile);
|
||||
}
|
||||
|
||||
var logFile = paths.join(logPath, 'enigma-bbs.log');
|
||||
const serializers = {
|
||||
err : bunyan.stdSerializers.err, // handle 'err' fields with stack/etc.
|
||||
};
|
||||
|
||||
// :TODO: make this configurable --
|
||||
// user should be able to configure rotations, levels to file vs ringBuffer,
|
||||
// completely disable logging, etc.
|
||||
// try to remove sensitive info by default, e.g. 'password' fields
|
||||
[ 'formData', 'formValue' ].forEach(keyName => {
|
||||
serializers[keyName] = (fd) => Log.hideSensitive(fd);
|
||||
});
|
||||
|
||||
this.log = bunyan.createLogger({
|
||||
name : 'ENiGMA½ BBS',
|
||||
streams : [
|
||||
{
|
||||
type : 'rotating-file',
|
||||
path : logFile,
|
||||
period : Config.logging.period || '1d',
|
||||
count : 3,
|
||||
level : Config.logging.level || 'debug',
|
||||
}
|
||||
/*,
|
||||
{
|
||||
type : 'raw',
|
||||
stream : ringBuffer,
|
||||
level : 'trace'
|
||||
}*/
|
||||
],
|
||||
serializers: { err : bunyan.stdSerializers.err } // handle 'err' fields with stack/etc.
|
||||
streams : logStreams,
|
||||
serializers : serializers,
|
||||
});
|
||||
}
|
||||
|
||||
static checkLogPath(logPath) {
|
||||
try {
|
||||
if(!fs.statSync(logPath).isDirectory()) {
|
||||
return new Error(`${logPath} is not a directory`);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch(e) {
|
||||
if('ENOENT' === e.code) {
|
||||
return new Error(`${logPath} does not exist`);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
static hideSensitive(obj) {
|
||||
try {
|
||||
//
|
||||
// Use a regexp -- we don't know how nested fields we want to seek and destroy may be
|
||||
//
|
||||
return JSON.parse(
|
||||
JSON.stringify(obj).replace(/"(password)"\s?:\s?"([^"]+)"/, (match, valueName) => {
|
||||
return `"${valueName}":"********"`;
|
||||
})
|
||||
);
|
||||
} catch(e) {
|
||||
// be safe and return empty obj!
|
||||
return {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -66,7 +66,7 @@ var SPECIAL_KEY_MAP_DEFAULT = {
|
|||
'line feed' : [ 'return' ],
|
||||
exit : [ 'esc' ],
|
||||
backspace : [ 'backspace' ],
|
||||
'delete' : [ 'del' ],
|
||||
delete : [ 'del' ],
|
||||
tab : [ 'tab' ],
|
||||
up : [ 'up arrow' ],
|
||||
down : [ 'down arrow' ],
|
||||
|
@ -802,7 +802,6 @@ function MultiLineEditTextView(options) {
|
|||
self.emitEditPosition();
|
||||
};
|
||||
|
||||
//this.keyPressClearLine = function() {
|
||||
this.keyPressDeleteLine = function() {
|
||||
if(self.textLines.length > 0) {
|
||||
self.removeCharactersFromText(
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
// ENiGMA½
|
||||
const msgArea = require('./message_area.js');
|
||||
const MenuModule = require('./menu_module.js').MenuModule;
|
||||
const ViewController = require('../core/view_controller.js').ViewController;
|
||||
const ViewController = require('./view_controller.js').ViewController;
|
||||
const stringFormat = require('./string_format.js');
|
||||
|
||||
// deps
|
||||
const _ = require('lodash');
|
||||
|
@ -121,15 +122,6 @@ function NewScanModule(options) {
|
|||
const sortedAreas = msgArea.getSortedAvailMessageAreasByConfTag(conf.confTag, { client : self.client } );
|
||||
const currentArea = sortedAreas[self.currentScanAux.area];
|
||||
|
||||
function getFormatObj() {
|
||||
return {
|
||||
confName : conf.conf.name,
|
||||
confDesc : conf.conf.desc,
|
||||
areaName : currentArea.area.name,
|
||||
areaDesc : currentArea.area.desc
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Scan and update index until we find something. If results are found,
|
||||
// we'll goto the list module & show them.
|
||||
|
@ -147,7 +139,12 @@ function NewScanModule(options) {
|
|||
}
|
||||
},
|
||||
function updateStatusScanStarted(callback) {
|
||||
self.updateScanStatus(self.scanStartFmt.format(getFormatObj()));
|
||||
self.updateScanStatus(stringFormat(self.scanStartFmt, {
|
||||
confName : conf.conf.name,
|
||||
confDesc : conf.conf.desc,
|
||||
areaName : currentArea.area.name,
|
||||
areaDesc : currentArea.area.desc
|
||||
}));
|
||||
return callback(null);
|
||||
},
|
||||
function getNewMessagesCountInArea(callback) {
|
||||
|
|
|
@ -9,6 +9,7 @@ var ServerModule = require('../server_module.js').ServerModule;
|
|||
var userLogin = require('../user_login.js').userLogin;
|
||||
var enigVersion = require('../../package.json').version;
|
||||
var theme = require('../theme.js');
|
||||
const stringFormat = require('../string_format.js');
|
||||
|
||||
var ssh2 = require('ssh2');
|
||||
var fs = require('fs');
|
||||
|
@ -106,11 +107,11 @@ function SSHClient(clientConn) {
|
|||
if(err) {
|
||||
interactivePrompt.prompt = 'Access denied\n' + ctx.username + '\'s password: ';
|
||||
} else {
|
||||
var newUserNameList = '"' + (Config.users.newUserNames || []).join(', ') + '"';
|
||||
interactivePrompt.prompt =
|
||||
'Access denied\n' +
|
||||
artInfo.data.format( { newUserNames : newUserNameList } ) +
|
||||
'\n' + ctx.username + '\'s password: ';
|
||||
const newUserNameList = _.has(Config, 'users.newUserNames') && Config.users.newUserNames.length > 0 ?
|
||||
Config.users.newUserNames.map(newName => '"' + newName + '"').join(', ') :
|
||||
'(No new user names enabled!)';
|
||||
|
||||
interactivePrompt.prompt = `Access denied\n${stringFormat(artInfo.data, { newUserNames : newUserNameList })}\n${ctx.username}'s password'`;
|
||||
}
|
||||
return ctx.prompt(interactivePrompt, retryPrompt);
|
||||
});
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
const EnigError = require('./enig_error.js').EnigError;
|
||||
const pad = require('./string_util.js').pad;
|
||||
const stylizeString = require('./string_util.js').stylizeString;
|
||||
const renderStringLength = require('./string_util.js').renderStringLength;
|
||||
const renderSubstr = require('./string_util.js').renderSubstr;
|
||||
|
||||
// deps
|
||||
const _ = require('lodash');
|
||||
|
@ -124,7 +126,7 @@ function getPadAlign(align) {
|
|||
function formatString(value, tokens) {
|
||||
const fill = tokens.fill || (tokens['0'] ? '0' : ' ');
|
||||
const align = tokens.align || (tokens['0'] ? '=' : '<');
|
||||
const precision = Number(tokens.precision || value.length); // :TODO: consider pipe/ANSI length
|
||||
const precision = Number(tokens.precision || renderStringLength(value) + 1);
|
||||
|
||||
if('' !== tokens.type && 's' !== tokens.type) {
|
||||
throw new ValueError(`Unknown format code "${tokens.type}" for String object`);
|
||||
|
@ -146,7 +148,7 @@ function formatString(value, tokens) {
|
|||
throw new ValueError('"=" alignment not allowed in string format specifier');
|
||||
}
|
||||
|
||||
return pad(value.slice(0, precision), parseInt(tokens.width), fill, getPadAlign(align));
|
||||
return pad(renderSubstr(value, 0, precision), Number(tokens.width), fill, getPadAlign(align));
|
||||
}
|
||||
|
||||
const FormatNumRegExp = {
|
||||
|
@ -167,7 +169,10 @@ function formatNumberHelper(n, precision, type) {
|
|||
case 'x' : return n.toString(16);
|
||||
case 'e' : return n.toExponential(precision).replace(FormatNumRegExp.ExponentRep, '$&0');
|
||||
case 'f' : return n.toFixed(precision);
|
||||
case 'g' : return n.toPrecision(precision || 1);
|
||||
case 'g' :
|
||||
// we don't want useless trailing zeros. parseFloat -> back to string fixes this for us
|
||||
return parseFloat(n.toPrecision(precision || 1)).toString();
|
||||
|
||||
case '%' : return formatNumberHelper(n * 100, precision, 'f') + '%';
|
||||
case '' : return formatNumberHelper(n, precision, 'd');
|
||||
|
||||
|
@ -276,7 +281,7 @@ const REGEXP_BASIC_FORMAT = /{([^.!:}]+(?:\.[^.!:}]+)*)(?:\!([^:}]+))?(?:\:([^}]
|
|||
|
||||
function getValue(obj, path) {
|
||||
const value = _.get(obj, path);
|
||||
if(value) {
|
||||
if(!_.isUndefined(value)) {
|
||||
return _.isFunction(value) ? value() : value;
|
||||
}
|
||||
|
||||
|
@ -286,9 +291,16 @@ function getValue(obj, path) {
|
|||
module.exports = function format(fmt, obj) {
|
||||
|
||||
const re = REGEXP_BASIC_FORMAT;
|
||||
|
||||
let match;
|
||||
let pos;
|
||||
let out = '';
|
||||
let objPath ;
|
||||
let transformer;
|
||||
let formatSpec;
|
||||
let value;
|
||||
let tokens;
|
||||
|
||||
do {
|
||||
pos = re.lastIndex;
|
||||
match = re.exec(fmt);
|
||||
|
@ -298,16 +310,16 @@ module.exports = function format(fmt, obj) {
|
|||
out += fmt.slice(pos, match.index);
|
||||
}
|
||||
|
||||
const objPath = match[1];
|
||||
const transformer = match[2];
|
||||
const formatSpec = match[3];
|
||||
objPath = match[1];
|
||||
transformer = match[2];
|
||||
formatSpec = match[3];
|
||||
|
||||
let value = getValue(obj, objPath);
|
||||
value = getValue(obj, objPath);
|
||||
if(transformer) {
|
||||
value = transformValue(transformer, value);
|
||||
}
|
||||
|
||||
const tokens = tokenizeFormatSpec(formatSpec || '');
|
||||
tokens = tokenizeFormatSpec(formatSpec || '');
|
||||
|
||||
if(!isNaN(parseInt(value))) {
|
||||
out += formatNumber(value, tokens);
|
||||
|
|
|
@ -195,45 +195,6 @@ function stringFromNullTermBuffer(buf, encoding) {
|
|||
return iconv.decode(buf.slice(0, nullPos), encoding || 'utf-8');
|
||||
}
|
||||
|
||||
//
|
||||
// Extend String.format's object syntax with some modifiers
|
||||
// e.g.: '{username!styleL33t}'.format( { username : 'Leet User' } ) -> "L33t U53r"
|
||||
//
|
||||
var stringFormatExtensions = {
|
||||
styleUpper : function(s) {
|
||||
return stylizeString(s, 'upper');
|
||||
},
|
||||
styleLower : function(s) {
|
||||
return stylizeString(s, 'lower');
|
||||
},
|
||||
styleTitle : function(s) {
|
||||
return stylizeString(s, 'title');
|
||||
},
|
||||
styleFirstLower : function(s) {
|
||||
return stylizeString(s, 'first lower');
|
||||
},
|
||||
styleSmallVowels : function(s) {
|
||||
return stylizeString(s, 'small vowels');
|
||||
},
|
||||
styleBigVowels : function(s) {
|
||||
return stylizeString(s, 'big vowels');
|
||||
},
|
||||
styleSmallI : function(s) {
|
||||
return stylizeString(s, 'small i');
|
||||
},
|
||||
styleMixed : function(s) {
|
||||
return stylizeString(s, 'mixed');
|
||||
},
|
||||
styleL33t : function(s) {
|
||||
return stylizeString(s, 'l33t');
|
||||
}
|
||||
|
||||
// :TODO: Add padding/etc. modifiers.
|
||||
};
|
||||
|
||||
exports.stringFormatExtensions = stringFormatExtensions;
|
||||
|
||||
|
||||
// :TODO: Add other codes from ansi_escape_parser
|
||||
const ANSI_REGEXP = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
||||
const PIPE_REGEXP = /\|[A-Z\d]{2}/g;
|
||||
|
@ -244,7 +205,7 @@ const ANSI_OR_PIPE_REGEXP = new RegExp(ANSI_REGEXP.source + '|' + PIPE_REGEXP.so
|
|||
//
|
||||
function renderSubstr(str, start, length) {
|
||||
start = start || 0;
|
||||
length = length || str.length - start;
|
||||
length = Math.max(0, (length || str.length - start) - 1);
|
||||
|
||||
const re = ANSI_REGEXP;
|
||||
let pos;
|
||||
|
|
|
@ -240,14 +240,6 @@ TextView.prototype.setText = function(text) {
|
|||
};
|
||||
*/
|
||||
|
||||
TextView.prototype.setFormatObject = function(obj) {
|
||||
if(!_.isObject(obj) || !this.text) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setText(this.text.format(obj));
|
||||
};
|
||||
|
||||
TextView.prototype.clearText = function() {
|
||||
this.setText('');
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@ exports.userLogin = userLogin;
|
|||
function userLogin(client, username, password, cb) {
|
||||
client.user.authenticate(username, password, function authenticated(err) {
|
||||
if(err) {
|
||||
client.log.info( { username : username }, 'Failed login attempt: %s', err);
|
||||
client.log.info( { username : username, error : err.message }, 'Failed login attempt');
|
||||
|
||||
// :TODO: if username exists, record failed login attempt to properties
|
||||
// :TODO: check Config max failed logon attempts/etc. - set err.maxAttempts = true
|
||||
|
|
|
@ -6,6 +6,7 @@ var MCIViewFactory = require('./mci_view_factory.js').MCIViewFactory;
|
|||
var menuUtil = require('./menu_util.js');
|
||||
var asset = require('./asset.js');
|
||||
var ansi = require('./ansi_term.js');
|
||||
const Log = require('./logger.js');
|
||||
|
||||
// deps
|
||||
var events = require('events');
|
||||
|
@ -328,7 +329,14 @@ function ViewController(options) {
|
|||
}
|
||||
}
|
||||
|
||||
self.client.log.trace( { formValue : formValue, actionValue : actionValue }, 'Action match');
|
||||
self.client.log.trace(
|
||||
{
|
||||
formValue : formValue,
|
||||
actionValue : actionValue
|
||||
},
|
||||
'Action match'
|
||||
);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ const ViewController = require('../core/view_controller.js').ViewController;
|
|||
const ansi = require('../core/ansi_term.js');
|
||||
const theme = require('../core/theme.js');
|
||||
const getUserName = require('../core/user.js').getUserName;
|
||||
const stringFormat = require('../core/string_format.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
|
@ -99,7 +100,6 @@ function BBSListModule(options) {
|
|||
self.setViewText(MciViewIds.view[mciName], '');
|
||||
});
|
||||
} else {
|
||||
// :TODO: we really need pipe code support for TextView!!
|
||||
const youSubmittedFormat = config.youSubmittedFormat || '{submitter} (You!)';
|
||||
|
||||
Object.keys(SELECTED_MCI_NAME_TO_ENTRY).forEach(mciName => {
|
||||
|
@ -107,7 +107,7 @@ function BBSListModule(options) {
|
|||
if(MciViewIds.view[mciName]) {
|
||||
|
||||
if('SelectedBBSSubmitter' == mciName && entry.submitterUserId == self.client.user.userId) {
|
||||
self.setViewText(MciViewIds.view.SelectedBBSSubmitter, youSubmittedFormat.format(entry));
|
||||
self.setViewText(MciViewIds.view.SelectedBBSSubmitter, stringFormat(youSubmittedFormat, entry));
|
||||
} else {
|
||||
self.setViewText(MciViewIds.view[mciName], t);
|
||||
}
|
||||
|
@ -120,8 +120,8 @@ function BBSListModule(options) {
|
|||
const listFormat = config.listFormat || '{bbsName}';
|
||||
const focusListFormat = config.focusListFormat || '{bbsName}';
|
||||
|
||||
entriesView.setItems(self.entries.map( e => listFormat.format(e) ) );
|
||||
entriesView.setFocusItems(self.entries.map( e => focusListFormat.format(e) ) );
|
||||
entriesView.setItems(self.entries.map( e => stringFormat(listFormat, e) ) );
|
||||
entriesView.setFocusItems(self.entries.map( e => stringFormat(focusListFormat, e) ) );
|
||||
};
|
||||
|
||||
this.displayBBSList = function(clearScreen, cb) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
'use strict';
|
||||
|
||||
var MenuModule = require('../core/menu_module.js').MenuModule;
|
||||
const stringFormat = require('../core/string_format.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
|
@ -86,10 +87,10 @@ function ErcClientModule(options) {
|
|||
try {
|
||||
if(data.userName) {
|
||||
// user message
|
||||
text = self.chatEntryFormat.format(data);
|
||||
text = stringFormat(self.chatEntryFormat, data);
|
||||
} else {
|
||||
// system message
|
||||
text = self.systemEntryFormat.format(data);
|
||||
text = stringFormat(self.systemEntryFormat, data);
|
||||
}
|
||||
} catch(e) {
|
||||
return self.client.log.warn( { error : e.message }, 'ERC: chatEntryFormat error');
|
||||
|
|
|
@ -8,6 +8,7 @@ const StatLog = require('../core/stat_log.js');
|
|||
const getUserName = require('../core/user.js').getUserName;
|
||||
const loadProperties = require('../core/user.js').loadProperties;
|
||||
const isRootUserId = require('../core/user.js').isRootUserId;
|
||||
const stringFormat = require('../core/string_format.js');
|
||||
|
||||
// deps
|
||||
const moment = require('moment');
|
||||
|
@ -123,12 +124,9 @@ LastCallersModule.prototype.mciReady = function(mciData, cb) {
|
|||
);
|
||||
},
|
||||
function populateList(callback) {
|
||||
const listFormat = self.menuConfig.config.listFormat || '{userName} - {location} - {affils} - {ts}';
|
||||
const listFormat = self.menuConfig.config.listFormat || '{userName} - {location} - {affiliation} - {ts}';
|
||||
|
||||
callersView.setItems(_.map(loginHistory, ce => listFormat.format(ce) ) );
|
||||
|
||||
// :TODO: This is a hack until pipe codes are better implemented
|
||||
callersView.focusItems = callersView.items;
|
||||
callersView.setItems(_.map(loginHistory, ce => stringFormat(listFormat, ce) ) );
|
||||
|
||||
callersView.redraw();
|
||||
return callback(null);
|
||||
|
|
|
@ -8,6 +8,7 @@ const messageArea = require('../core/message_area.js');
|
|||
const displayThemeArt = require('../core/theme.js').displayThemeArt;
|
||||
const displayThemedPause = require('../core/theme.js').displayThemedPause;
|
||||
const resetScreen = require('../core/ansi_term.js').resetScreen;
|
||||
const stringFormat = require('../core/string_format.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
|
@ -152,7 +153,7 @@ MessageAreaListModule.prototype.mciReady = function(mciData, cb) {
|
|||
const areaListView = vc.getView(MCICodesIDs.AreaList);
|
||||
let i = 1;
|
||||
areaListView.setItems(_.map(self.messageAreas, v => {
|
||||
return listFormat.format({
|
||||
return stringFormat(listFormat, {
|
||||
index : i++,
|
||||
areaTag : v.area.areaTag,
|
||||
name : v.area.name,
|
||||
|
@ -162,7 +163,7 @@ MessageAreaListModule.prototype.mciReady = function(mciData, cb) {
|
|||
|
||||
i = 1;
|
||||
areaListView.setFocusItems(_.map(self.messageAreas, v => {
|
||||
return focusListFormat.format({
|
||||
return stringFormat(focusListFormat, {
|
||||
index : i++,
|
||||
areaTag : v.area.areaTag,
|
||||
name : v.area.name,
|
||||
|
|
|
@ -123,3 +123,7 @@ AreaViewFSEModule.prototype.restoreSavedState = function(savedState) {
|
|||
this.messageIndex = savedState.messageIndex;
|
||||
this.messageTotal = savedState.messageTotal;
|
||||
};
|
||||
|
||||
AreaViewFSEModule.prototype.getMenuResult = function() {
|
||||
return this.messageIndex;
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ const messageArea = require('../core/message_area.js');
|
|||
const displayThemeArt = require('../core/theme.js').displayThemeArt;
|
||||
const displayThemedPause = require('../core/theme.js').displayThemedPause;
|
||||
const resetScreen = require('../core/ansi_term.js').resetScreen;
|
||||
const stringFormat = require('../core/string_format.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
|
@ -121,7 +122,7 @@ MessageConfListModule.prototype.mciReady = function(mciData, cb) {
|
|||
const confListView = vc.getView(MCICodeIDs.ConfList);
|
||||
let i = 1;
|
||||
confListView.setItems(_.map(self.messageConfs, v => {
|
||||
return listFormat.format({
|
||||
return stringFormat(listFormat, {
|
||||
index : i++,
|
||||
confTag : v.conf.confTag,
|
||||
name : v.conf.name,
|
||||
|
@ -131,7 +132,7 @@ MessageConfListModule.prototype.mciReady = function(mciData, cb) {
|
|||
|
||||
i = 1;
|
||||
confListView.setFocusItems(_.map(self.messageConfs, v => {
|
||||
return focusListFormat.format({
|
||||
return stringFormat(focusListFormat, {
|
||||
index : i++,
|
||||
confTag : v.conf.confTag,
|
||||
name : v.conf.name,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
const MenuModule = require('../core/menu_module.js').MenuModule;
|
||||
const ViewController = require('../core/view_controller.js').ViewController;
|
||||
const messageArea = require('../core/message_area.js');
|
||||
const stringFormat = require('../core/string_format.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
|
@ -209,11 +210,11 @@ MessageListModule.prototype.mciReady = function(mciData, cb) {
|
|||
// which items are requested (e.g. their format at least) *as-needed* vs trying to get the format for all of them at once
|
||||
|
||||
msgListView.setItems(_.map(self.messageList, listEntry => {
|
||||
return listFormat.format(listEntry);
|
||||
return stringFormat(listFormat, listEntry);
|
||||
}));
|
||||
|
||||
msgListView.setFocusItems(_.map(self.messageList, listEntry => {
|
||||
return focusListFormat.format(listEntry);
|
||||
return stringFormat(focusListFormat, listEntry);
|
||||
}));
|
||||
|
||||
msgListView.on('index update', function indexUpdated(idx) {
|
||||
|
|
|
@ -154,7 +154,6 @@ function OnelinerzModule(options) {
|
|||
} );
|
||||
}));
|
||||
|
||||
entriesView.focusItems = entriesView.items; // :TODO: this is a hack
|
||||
entriesView.redraw();
|
||||
|
||||
return callback(null);
|
||||
|
|
|
@ -8,6 +8,7 @@ const theme = require('../core/theme.js');
|
|||
const resetScreen = require('../core/ansi_term.js').resetScreen;
|
||||
const StatLog = require('../core/stat_log.js');
|
||||
const renderStringLength = require('../core/string_util.js').renderStringLength;
|
||||
const stringFormat = require('../core/string_format.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
|
@ -158,8 +159,8 @@ exports.getModule = class RumorzModule extends MenuModule {
|
|||
const listFormat = config.listFormat || '{rumor}';
|
||||
const focusListFormat = config.focusListFormat || listFormat;
|
||||
|
||||
entriesView.setItems(entries.map( e => listFormat.format( { rumor : e.log_value } ) ) );
|
||||
entriesView.setFocusItems(entries.map(e => focusListFormat.format( { rumor : e.log_value } ) ) );
|
||||
entriesView.setItems(entries.map( e => stringFormat(listFormat, { rumor : e.log_value } ) ) );
|
||||
entriesView.setFocusItems(entries.map(e => stringFormat(focusListFormat, { rumor : e.log_value } ) ) );
|
||||
entriesView.redraw();
|
||||
|
||||
return callback(null);
|
||||
|
|
Binary file not shown.
|
@ -5,10 +5,10 @@ var MenuModule = require('../core/menu_module.js').MenuModule;
|
|||
//var userDb = require('../core/database.js').dbs.user;
|
||||
var getUserList = require('../core/user.js').getUserList;
|
||||
var ViewController = require('../core/view_controller.js').ViewController;
|
||||
const stringFormat = require('../core/string_format.js');
|
||||
|
||||
var moment = require('moment');
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var _ = require('lodash');
|
||||
|
||||
/*
|
||||
|
@ -92,11 +92,11 @@ UserListModule.prototype.mciReady = function(mciData, cb) {
|
|||
}
|
||||
|
||||
userListView.setItems(_.map(userList, function formatUserEntry(ue) {
|
||||
return listFormat.format(getUserFmtObj(ue));
|
||||
return stringFormat(listFormat, getUserFmtObj(ue));
|
||||
}));
|
||||
|
||||
userListView.setFocusItems(_.map(userList, function formatUserEntry(ue) {
|
||||
return focusListFormat.format(getUserFmtObj(ue));
|
||||
return stringFormat(focusListFormat, getUserFmtObj(ue));
|
||||
}));
|
||||
|
||||
userListView.redraw();
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
const MenuModule = require('../core/menu_module.js').MenuModule;
|
||||
const ViewController = require('../core/view_controller.js').ViewController;
|
||||
const getActiveNodeList = require('../core/client_connections.js').getActiveNodeList;
|
||||
const stringFormat = require('../core/string_format.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
|
@ -63,7 +64,7 @@ WhosOnlineModule.prototype.mciReady = function(mciData, cb) {
|
|||
});
|
||||
oe.userName = nonAuthUser;
|
||||
}
|
||||
return listFormat.format(oe);
|
||||
return stringFormat(listFormat, oe);
|
||||
}));
|
||||
|
||||
onlineListView.focusItems = onlineListView.items;
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
"ptyw.js": "^0.3.7",
|
||||
"sqlite3": "^3.1.1",
|
||||
"ssh2": "^0.4.13",
|
||||
"string-format": "davidchambers/string-format#mini-language",
|
||||
"temp": "^0.8.3",
|
||||
"inquirer" : "^1.1.0",
|
||||
"fs-extra" : "0.26.x",
|
||||
|
|
Loading…
Reference in New Issue