Merge branch 'master' of ssh://numinibsd/git/base/enigma-bbs

This commit is contained in:
Bryan Ashby 2016-01-03 19:41:35 -07:00
commit a39beda354
9 changed files with 292 additions and 87 deletions

View File

@ -9,6 +9,7 @@ var MultiLineEditTextView = require('../core/multi_line_edit_text_view.js').Mul
var Message = require('../core/message.js');
var getMessageAreaByName = require('../core/message_area.js').getMessageAreaByName;
var updateMessageAreaLastReadId = require('../core/message_area.js').updateMessageAreaLastReadId;
var getUserIdAndName = require('../core/user.js').getUserIdAndName;
var async = require('async');
var assert = require('assert');
@ -67,7 +68,6 @@ var MCICodeIds = {
To : 2,
Subject : 3,
AreaName : 4,
DateTime : 5,
MsgNum : 6,
MsgTotal : 7,
@ -103,20 +103,40 @@ function FullScreenEditorModule(options) {
// editorType : email | area
// editorMode : view | edit | quote
//
// extraArgs - view mode
// menuConfig.config or extraArgs
// messageAreaName
// messageIndex / messageTotal
// toUserId
//
//
this.editorType = config.editorType;
this.editorMode = config.editorMode;
if(_.isObject(options.extraArgs)) {
//console.log(options.extraArgs)
this.messageAreaName = options.extraArgs.messageAreaName || Message.WellKnownAreaNames.Private;
this.messageIndex = options.extraArgs.messageIndex || 0;
this.messageTotal = options.extraArgs.messageTotal || 0;
this.editorType = config.editorType;
this.editorMode = config.editorMode;
if(config.messageAreaName) {
this.messageAreaName = config.messageAreaName;
}
this.messageIndex = config.messageIndex || 0;
this.messageTotal = config.messageTotal || 0;
this.toUserId = config.toUserId || 0;
// extraArgs can override some config
if(_.isObject(options.extraArgs)) {
if(options.extraArgs.messageAreaName) {
this.messageAreaName = options.extraArgs.messageAreaName;
}
if(options.extraArgs.messageIndex) {
this.messageIndex = options.extraArgs.messageIndex;
}
if(options.extraArgs.messageTotal) {
this.messageTotal = options.extraArgs.messageTotal;
}
if(options.extraArgs.toUserId) {
this.toUserId = options.extraArgs.toUserId;
}
}
console.log(this.toUserId)
console.log(this.messageAreaName)
this.isReady = false;
@ -129,7 +149,7 @@ function FullScreenEditorModule(options) {
};
this.isLocalEmail = function() {
return 'email' === self.editorType && Message.WellKnownAreaNames.Private === self.messageAreaName;
return Message.WellKnownAreaNames.Private === self.messageAreaName;
};
this.isReply = function() {
@ -214,21 +234,21 @@ function FullScreenEditorModule(options) {
this.setMessage = function(message) {
self.message = message;
if(!self.message.isPrivate()) {
updateMessageAreaLastReadId(self.client.user.userId, self.messageAreaName, self.message.messageId);
}
updateMessageAreaLastReadId(
self.client.user.userId, self.messageAreaName, self.message.messageId,
function lastReadUpdated() {
if(self.isReady) {
self.initHeaderViewMode();
self.initFooterViewMode();
if(self.isReady) {
self.initHeaderViewMode();
self.initFooterViewMode();
var bodyMessageView = self.viewControllers.body.getView(1);
if(bodyMessageView && _.has(self, 'message.message')) {
bodyMessageView.setText(self.message.message);
//bodyMessageView.redraw();
var bodyMessageView = self.viewControllers.body.getView(1);
if(bodyMessageView && _.has(self, 'message.message')) {
bodyMessageView.setText(self.message.message);
//bodyMessageView.redraw();
}
}
}
});
};
this.getMessage = function(cb) {
@ -242,12 +262,25 @@ function FullScreenEditorModule(options) {
},
function populateLocalUserInfo(callback) {
if(self.isLocalEmail()) {
msg.setLocalFromUserId(self.client.user.userId);
msg.setLocalToUserId(self.toUserId);
self.message.setLocalFromUserId(self.client.user.userId);
if(self.toUserId > 0) {
self.message.setLocalToUserId(self.toUserId);
callback(null);
} else {
// we need to look it up
getUserIdAndName(self.message.toUserName, function userInfo(err, toUserId) {
if(err) {
callback(err);
} else {
self.message.setLocalToUserId(toUserId);
callback(null);
}
});
}
} else {
callback(null);
}
// :TODO: DO THAT!
callback(null);
}
],
function complete(err) {

View File

@ -4,6 +4,7 @@
var msgDb = require('./database.js').dbs.message;
var Config = require('./config.js').config;
var Message = require('./message.js');
var Log = require('./logger.js').log;
var async = require('async');
var _ = require('lodash');
@ -105,6 +106,19 @@ function changeMessageArea(client, areaName, cb) {
);
}
function getMessageFromRow(row) {
return {
messageId : row.message_id,
messageUuid : row.message_uuid,
replyToMsgId : row.reply_to_message_id,
toUserName : row.to_user_name,
fromUserName : row.from_user_name,
subject : row.subject,
modTimestamp : row.modified_timestamp,
viewCount : row.view_count,
};
}
function getNewMessagesInAreaForUser(userId, areaName, cb) {
//
// If |areaName| is Message.WellKnownAreaNames.Private,
@ -135,19 +149,12 @@ function getNewMessagesInAreaForUser(userId, areaName, cb) {
}
sql += ' ORDER BY message_id;';
console.log(sql)
msgDb.each(sql, function msgRow(err, row) {
if(!err) {
msgList.push( {
messageId : row.message_id,
messageUuid : row.message_uuid,
replyToMsgId : row.reply_to_message_id,
toUserName : row.to_user_name,
fromUserName : row.from_user_name,
subject : row.subject,
modTimestamp : row.modified_timestamp,
viewCount : row.view_count,
} );
msgList.push(getMessageFromRow(row));
}
}, callback);
}
@ -191,16 +198,7 @@ function getMessageListForArea(options, areaName, cb) {
[ areaName.toLowerCase() ],
function msgRow(err, row) {
if(!err) {
msgList.push( {
messageId : row.message_id,
messageUuid : row.message_uuid,
replyToMsgId : row.reply_to_message_id,
toUserName : row.to_user_name,
fromUserName : row.from_user_name,
subject : row.subject,
modTimestamp : row.modified_timestamp,
viewCount : row.view_count,
} );
msgList.push(getMessageFromRow(row));
}
},
callback
@ -222,11 +220,13 @@ function getMessageAreaLastReadId(userId, areaName, cb) {
'FROM user_message_area_last_read ' +
'WHERE user_id = ? AND area_name = ?;',
[ userId, areaName ],
cb // (err, lastId)
function complete(err, row) {
cb(err, row ? row.message_id : 0);
}
);
}
function updateMessageAreaLastReadId(userId, areaName, messageId) {
function updateMessageAreaLastReadId(userId, areaName, messageId, cb) {
// :TODO: likely a better way to do this...
async.waterfall(
[
@ -241,10 +241,25 @@ function updateMessageAreaLastReadId(userId, areaName, messageId) {
msgDb.run(
'REPLACE INTO user_message_area_last_read (user_id, area_name, message_id) ' +
'VALUES (?, ?, ?);',
[ userId, areaName, messageId ]
[ userId, areaName, messageId ],
callback
);
} else {
callback(null);
}
}
]
],
function complete(err) {
if(err) {
Log.debug(
{ error : err.toString(), userId : userId, areaName : areaName, messageId : messageId },
'Failed updating area last read ID');
} else {
Log.trace(
{ userId : userId, areaName : areaName, messageId : messageId },
'Area last read ID updated');
}
cb(err);
}
);
}

View File

@ -19,14 +19,16 @@ exports.getModule = NewScanModule;
/*
* :TODO:
* * Update message ID when reading (this should be working!)
* * New scan all areas
* * User configurable new scan: Area selection (avail from messages area)
* * User configurable new scan: Area selection (avail from messages area) (sep module)
* * Add status TL/VM (either/both should update if present)
* *
*/
var MciCodeIds = {
ScanStatusLabel : 1, // TL1
ScanStatusList : 2, // VM2 (appends)
};
function NewScanModule(options) {
MenuModule.call(this, options);
@ -35,9 +37,27 @@ function NewScanModule(options) {
var config = this.menuConfig.config;
this.currentStep = 'messageAreas';
this.currentScanAux = 0; // Message.WellKnownAreaNames.Private
this.currentScanAux = 0; // e.g. Message.WellKnownAreaNames.Private when currentSteps = messageAreas
this.scanStartFmt = config.scanStartFmt || 'Scanning {desc}...';
this.scanFinishNoneFmt = config.scanFinishNoneFmt || 'Nothing new';
this.scanFinishNewFmt = config.scanFinishNewFmt || '{count} entries found';
this.scanCompleteMsg = config.scanCompleteMsg || 'Finished newscan';
this.updateScanStatus = function(statusText) {
var vc = self.viewControllers.allViews;
var view = vc.getView(MciCodeIds.ScanStatusLabel);
if(view) {
view.setText(statusText);
}
view = vc.getView(MciCodeIds.ScanStatusList);
// :TODO: MenuView needs appendItem()
if(view) {
}
};
this.newScanMessageArea = function(cb) {
var availMsgAreas = msgArea.getAvailableMessageAreas( { includePrivate : true } );
var currentArea = availMsgAreas[self.currentScanAux];
@ -54,16 +74,31 @@ function NewScanModule(options) {
self.currentScanAux += 1;
callback(null);
} else {
self.updateScanStatus(self.scanCompleteMsg);
callback(new Error('No more areas'));
}
},
function updateStatus(callback) {
// :TODO: Update status text
function updateStatusScanStarted(callback) {
self.updateScanStatus(self.scanStartFmt.format({
desc : currentArea.desc,
}));
callback(null);
},
function newScanAreaAndGetMessages(callback) {
msgArea.getNewMessagesInAreaForUser(
self.client.user.userId, currentArea.name, function msgs(err, msgList) {
if(!err) {
if(0 === msgList.length) {
self.updateScanStatus(self.scanFinishNoneFmt.format({
desc : currentArea.desc,
}));
} else {
self.updateScanStatus(self.scanFinishNewFmt.format({
desc : currentArea.desc,
count : msgList.length,
}));
}
}
callback(err, msgList);
}
);

View File

@ -369,9 +369,6 @@
art: LETTER
options: { pause: true }
next: newUserFeedbackToSysOp
extraArgs: {
messageAreaName: private_mail
}
}
newUserFeedbackToSysOp: {
@ -395,7 +392,9 @@
help: MSGEHLP
},
editorMode: edit
editorType: area
editorType: email
messageAreaName: private_mail
toUserId: 1 /* always to +op */
}
form: {
0: {
@ -505,6 +504,7 @@
options: { pause: true }
next: fullLoginSequenceLastCallers
}
fullLoginSequenceLastCallers: {
desc: Last Callers
module: last_callers
@ -517,8 +517,34 @@
module: whos_online
art: WHOSON
options: { pause: true }
next: fullLoginSequenceSysStats
next: fullLoginSequenceNewScanConfirm
}
fullLoginSequenceNewScanConfirm: {
desc: Logging In
prompt: loginGlobalNewScan
submit: [
{
value: { promptValue: 0 }
action: @menu:fullLoginSequenceNewScan
}
{
value: { promptValue: 1 }
action: @menu:fullLoginSequenceUserStats
}
]
}
fullLoginSequenceNewScan: {
desc: Performing New Scan
module: @systemModule:new_scan
art: NEWSCAN
next: fullLoginSequenceSysStats
config: {
messageListMenu: newScanMessageList
}
}
fullLoginSequenceSysStats: {
desc: System Stats
art: SYSSTAT
@ -532,6 +558,40 @@
next: mainMenu
}
newScanMessageList: {
desc: Viewing New Message List
module: msg_list
art: NEWMSGS
config: {
menuViewPost: messageAreaViewPost
}
form: {
0: {
mci: {
VM1: {
focus: true
submit: true
argName: message
}
}
submit: {
*: [
{
value: { message: null }
action: @method:selectMessage
}
]
}
actionKeys: [
{
keys: [ "escape", "q", "shift + q" ]
action: @systemMethod:prevMenu
}
]
}
}
}
///////////////////////////////////////////////////////////////////////
// Main Menu
///////////////////////////////////////////////////////////////////////
@ -743,6 +803,10 @@
value: { command: "4" }
action: @menu:doorTradeWars2002BBSLink
}
{
value: { command: "DL" }
action: @menu:doorDarkLands
}
]
}
@ -763,6 +827,24 @@
io: socket
}
}
doorDarkLands: {
desc: Playing Dark Lands
module: abracadabra
config: {
name: DARKLANDS
dropFileType: DOOR
cmd: /home/nuskooler/dev/enigma-bbs/doors/darklands/start.sh
args: [
"{node}",
"{dropFile}",
"{srvPort}",
],
nodeMax: 1
tooManyArt: DOORMANY
io: socket
}
}
doorLORD: {
desc: Playing L.O.R.D.
@ -860,7 +942,6 @@
module: msg_list
art: MSGLIST
config: {
listType: public
menuViewPost: messageAreaViewPost
}
form: {

View File

@ -45,7 +45,7 @@ function AreaPostFSEModule(options) {
if(err) {
// :TODO:... sooooo now what?
} else {
console.log(msg);
console.log(msg); // :TODO: remove me -- probably log that one was saved, however.
}
self.nextMenu();

View File

@ -52,9 +52,21 @@ function MessageListModule(options) {
var self = this;
var config = this.menuConfig.config;
this.listType = config.listType || 'public';
this.messageAreaName = config.messageAreaName;
this.messageList = [];
if(options.extraArgs) {
//
// |extraArgs| can override |messageAreaName| provided by config
// as well as supply a pre-defined message list
//
if(options.extraArgs.messageAreaName) {
this.messageAreaName = options.extraArgs.messageAreaName;
}
if(options.extraArgs.messageList) {
this.messageList = options.extraArgs.messageList;
}
}
this.menuMethods = {
selectMessage : function(formData, extraArgs) {
@ -85,9 +97,11 @@ require('util').inherits(MessageListModule, MenuModule);
MessageListModule.prototype.enter = function(client) {
MessageListModule.super_.prototype.enter.call(this, client);
if('private' === this.listType) {
this.messageAreaName = Message.WellKnownAreaNames.Private;
} else {
//
// Config can specify |messageAreaName| else it comes from
// the user's current area
//
if(!this.messageAreaName) {
this.messageAreaName = client.user.properties.message_area_name;
}
};
@ -110,14 +124,21 @@ MessageListModule.prototype.mciReady = function(mciData, cb) {
vc.loadFromMenuConfig(loadOpts, callback);
},
function fetchMessagesInArea(callback) {
messageArea.getMessageListForArea( { client : self.client }, self.messageAreaName, function msgs(err, msgList) {
if(msgList && 0 === msgList.length) {
callback(new Error('No messages in area'));
} else {
self.messageList = msgList;
callback(err);
}
});
//
// Config can supply messages else we'll need to populate the list now
//
if(_.isArray(self.messageList)) {
callback(0 === self.messageList.length ? new Error('No messages in area') : null);
} else {
messageArea.getMessageListForArea( { client : self.client }, self.messageAreaName, function msgs(err, msgList) {
if(msgList && 0 === msgList.length) {
callback(new Error('No messages in area'));
} else {
self.messageList = msgList;
callback(err);
}
});
}
},
function getLastReadMesageId(callback) {
messageArea.getMessageAreaLastReadId(self.client.user.userId, self.messageAreaName, function lastRead(err, lastReadId) {

View File

@ -46,6 +46,19 @@
}
}
loginGlobalNewScan: {
art: GNSPMPT
mci: {
TM1: {
argName: promptValue
items: [ "yes", "no" ]
focus: true
hotKeys: { Y: 0, N: 1 }
hotKeySubmit: true
}
}
}
"menuCommand" : {
art: MNUPRMT
"mci" : {

8
oputil.js Normal file → Executable file
View File

@ -1,3 +1,5 @@
#!/usr/bin/env node
/* jslint node: true */
'use strict';
@ -85,7 +87,7 @@ function handleUserCommand() {
function setNewPass(userId, callback) {
assert(_.isNumber(userId));
assert(userId > 0);
var u = new user.User();
u.userId = userId;
@ -114,6 +116,10 @@ function main() {
process.exitCode = ExitCodes.SUCCESS;
if(true === argv.version) {
return console.info(require('./package.json').version);
}
if(0 === argv._.length ||
'help' === argv._[0])
{

View File

@ -13,7 +13,7 @@
"telnet"
],
"dependencies": {
"async": "^1.5.0",
"async": "^1.5.1",
"binary": "0.3.x",
"buffers": "0.1.x",
"bunyan": "1.5.x",
@ -21,15 +21,16 @@
"hjson": "1.7.x",
"iconv-lite": "^0.4.13",
"lodash": "^3.10.1",
"minimist": "1.2.x",
"mkdirp": "0.5.x",
"moment": "^2.10.6",
"moment": "^2.11.0",
"node-uuid": "^1.4.7",
"ptyw.js": "^0.3.4",
"ptyw.js": "^0.3.7",
"sqlite3": "^3.1.1",
"ssh2": "^0.4.12",
"ssh2": "^0.4.13",
"string-format": "davidchambers/string-format#mini-language"
},
"engines" : {
"node" : ">=0.12.2"
"engines": {
"node": ">=0.12.2"
}
}