From a45142f2fd36c932ce9c4e5df1f774d1d468cdc8 Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Sun, 1 Jan 2017 21:53:04 -0700 Subject: [PATCH] * Use more standard code paths & emit index events in ToggleMenuView * Fix fetching areas & internal message attach area name * Use proper config in new MenuModule methods * More good progress on uploading --- core/config.js | 2 +- core/file_area.js | 27 +++-- core/menu_module.js | 4 +- core/menu_view.js | 2 - core/toggle_menu_view.js | 54 ++++++---- mods/file_transfer_protocol_select.js | 13 ++- mods/upload.js | 148 ++++++++++++++++++++++++++ 7 files changed, 205 insertions(+), 45 deletions(-) create mode 100644 mods/upload.js diff --git a/core/config.js b/core/config.js index 0a7a2217..c7a717ca 100644 --- a/core/config.js +++ b/core/config.js @@ -404,7 +404,7 @@ function getDefaultConfig() { }, areas: { - systemm_message_attachment : { + system_message_attachment : { name : 'Message attachments', desc : 'File attachments to messages', storageTags : 'sys_msg_attach', // may be string or array of strings diff --git a/core/file_area.js b/core/file_area.js index 4903f571..e3aa2081 100644 --- a/core/file_area.js +++ b/core/file_area.js @@ -19,8 +19,10 @@ const paths = require('path'); const temp = require('temp').track(); // track() cleans up temp dir/files for us const iconv = require('iconv-lite'); +exports.isInternalArea = isInternalArea; exports.getAvailableFileAreas = getAvailableFileAreas; exports.getSortedAvailableFileAreas = getSortedAvailableFileAreas; +exports.getAreaDefaultStorageDirectory = getAreaDefaultStorageDirectory; exports.getDefaultFileAreaTag = getDefaultFileAreaTag; exports.getFileAreaByTag = getFileAreaByTag; exports.getFileEntryPath = getFileEntryPath; @@ -30,20 +32,23 @@ exports.scanFileAreaForChanges = scanFileAreaForChanges; const WellKnownAreaTags = exports.WellKnownAreaTags = { Invalid : '', - MessageAreaAttach : 'message_area_attach', + MessageAreaAttach : 'system_message_attachment', }; +function isInternalArea(areaTag) { + return areaTag === WellKnownAreaTags.MessageAreaAttach; +} + function getAvailableFileAreas(client, options) { options = options || { }; - // perform ACS check per conf & omit system_internal if desired - const areasWithTags = _.map(Config.fileBase.areas, (area, areaTag) => Object.assign(area, { areaTag : areaTag } ) ); + // perform ACS check per conf & omit internal if desired return _.omit(Config.fileBase.areas, (area, areaTag) => { - if(!options.includeSystemInternal && WellKnownAreaTags.MessageAreaAttach === areaTag) { + if(!options.includeSystemInternal && isInternalArea(areaTag)) { return true; } - if(options.writeAcs && !client.acs.FileAreaWrite(area)) { + if(options.writeAcs && !client.acs.hasFileAreaWrite(area)) { return true; // omit } @@ -122,16 +127,10 @@ function getAreaStorageDirectoryByTag(storageTag) { const storageLocation = (storageTag && Config.fileBase.storageTags[storageTag]); return paths.resolve(Config.fileBase.areaStoragePrefix, storageLocation || ''); - - /* - // absolute paths as-is - if(storageLocation && '/' === storageLocation.charAt(0)) { - return storageLocation; - } +} - // relative to |areaStoragePrefix| - return paths.join(Config.fileBase.areaStoragePrefix, storageLocation || ''); - */ +function getAreaDefaultStorageDirectory(areaInfo) { + return getAreaStorageDirectoryByTag(areaInfo.storageTags[0]); } function getAreaStorageLocations(areaInfo) { diff --git a/core/menu_module.js b/core/menu_module.js index d740c478..5f5d0318 100644 --- a/core/menu_module.js +++ b/core/menu_module.js @@ -340,7 +340,7 @@ MenuModule.prototype.displayAsset = function(name, options, cb) { return theme.displayThemedAsset( name, this.client, - Object.merge( { font : this.menuConfig.config }, options ), + Object.assign( { font : this.menuConfig.config.font }, options ), (err, artData) => { if(cb) { return cb(err, artData); @@ -376,7 +376,7 @@ MenuModule.prototype.prepViewController = function(name, formId, artData, cb) { MenuModule.prototype.prepViewControllerWithArt = function(name, formId, options, cb) { this.displayAsset( - name, + this.menuConfig.config.art[name], options, (err, artData) => { if(err) { diff --git a/core/menu_view.js b/core/menu_view.js index 0c11c51c..ec225907 100644 --- a/core/menu_view.js +++ b/core/menu_view.js @@ -92,12 +92,10 @@ MenuView.prototype.getItem = function(index) { }; MenuView.prototype.focusNext = function() { - // nothing @ base currently this.emit('index update', this.focusedItemIndex); }; MenuView.prototype.focusPrevious = function() { - // nothign @ base currently this.emit('index update', this.focusedItemIndex); }; diff --git a/core/toggle_menu_view.js b/core/toggle_menu_view.js index a740782c..35676193 100644 --- a/core/toggle_menu_view.js +++ b/core/toggle_menu_view.js @@ -25,9 +25,7 @@ function ToggleMenuView (options) { */ this.updateSelection = function() { - //assert(!self.positionCacheExpired); assert(this.focusedItemIndex >= 0 && this.focusedItemIndex <= self.items.length); - self.redraw(); }; } @@ -74,28 +72,38 @@ ToggleMenuView.prototype.setFocus = function(focused) { this.redraw(); }; -ToggleMenuView.prototype.onKeyPress = function(ch, key) { - if(key) { - var needsUpdate; - if(this.isKeyMapped('right', key.name) || this.isKeyMapped('down', key.name)) { - if(this.items.length - 1 === this.focusedItemIndex) { - this.focusedItemIndex = 0; - } else { - this.focusedItemIndex++; - } - needsUpdate = true; - } else if(this.isKeyMapped('left', key.name) || this.isKeyMapped('up', key.name)) { - if(0 === this.focusedItemIndex) { - this.focusedItemIndex = this.items.length - 1; - } else { - this.focusedItemIndex--; - } - needsUpdate = true; - } +ToggleMenuView.prototype.focusNext = function() { + if(this.items.length - 1 === this.focusedItemIndex) { + this.focusedItemIndex = 0; + } else { + this.focusedItemIndex++; + } - if(needsUpdate) { - this.updateSelection(); - return; + this.updateSelection(); + + ToggleMenuView.super_.prototype.focusNext.call(this); +}; + +ToggleMenuView.prototype.focusPrevious = function() { + + if(0 === this.focusedItemIndex) { + this.focusedItemIndex = this.items.length - 1; + } else { + this.focusedItemIndex--; + } + + this.updateSelection(); + + ToggleMenuView.super_.prototype.focusPrevious.call(this); +}; + +ToggleMenuView.prototype.onKeyPress = function(ch, key) { + + if(key) { + if(this.isKeyMapped('right', key.name) || this.isKeyMapped('down', key.name)) { + this.focusNext(); + } else if(this.isKeyMapped('left', key.name) || this.isKeyMapped('up', key.nam4e)) { + this.focusPrevious(); } } diff --git a/mods/file_transfer_protocol_select.js b/mods/file_transfer_protocol_select.js index b6f2a8ce..42e78bb4 100644 --- a/mods/file_transfer_protocol_select.js +++ b/mods/file_transfer_protocol_select.js @@ -27,11 +27,18 @@ exports.getModule = class FileTransferProtocolSelectModule extends MenuModule { super(options); this.config = this.menuConfig.config || {}; + + if(options.extraArgs) { + if(options.extraArgs.direction) { + this.config.direction = options.extraArgs.direction; + } + } + this.config.direction = this.config.direction || 'send'; this.loadAvailProtocols(); - this.extraArgs = options.extraArgs; + this.extraArgs = options.extraArgs; if(_.has(options, 'lastMenuResult.sentFileIds')) { this.sentFileIds = options.lastMenuResult.sentFileIds; @@ -50,9 +57,9 @@ exports.getModule = class FileTransferProtocolSelectModule extends MenuModule { }; if('send' === this.config.direction) { - return this.gotoMenu(this.config.downloadFilesMenu || 'downloadFiles', modOpts, cb); + return this.gotoMenu(this.config.downloadFilesMenu || 'sendFilesToUser', modOpts, cb); } else { - return this.gotoMenu(this.config.uploadFilesMenu || 'uploadFiles', modOpts, cb); + return this.gotoMenu(this.config.uploadFilesMenu || 'recvFilesFromUser', modOpts, cb); } }, }; diff --git a/mods/upload.js b/mods/upload.js new file mode 100644 index 00000000..47fbd9b4 --- /dev/null +++ b/mods/upload.js @@ -0,0 +1,148 @@ +/* jslint node: true */ +'use strict'; + +// enigma-bbs +const MenuModule = require('../core/menu_module.js').MenuModule; +const ViewController = require('../core/view_controller.js').ViewController; +const theme = require('../core/theme.js'); +const ansi = require('../core/ansi_term.js'); +const Errors = require('../core/enig_error.js').Errors; +const stringFormat = require('../core/string_format.js'); +const getSortedAvailableFileAreas = require('../core/file_area.js').getSortedAvailableFileAreas; +const getAreaDefaultStorageDirectory = require('../core/file_area.js').getAreaDefaultStorageDirectory; + +// deps +const async = require('async'); +const _ = require('lodash'); + +exports.moduleInfo = { + name : 'Upload', + desc : 'Module for classic file uploads', + author : 'NuSkooler', +}; + +const FormIds = { + options : 0, + fileDetails : 1, + +}; + +const MciViewIds = { + options : { + area : 1, // area selection + uploadType : 2, // blind vs specify filename + fileName : 3, // for non-blind; not editable for blind + navMenu : 4, // next/cancel/etc. + }, + + fileDetails : { + tags : 1, // tag(s) for item + desc : 2, // defaults to 'desc' (e.g. from FILE_ID.DIZ) + accept : 3, // accept fields & continue + } +}; + +exports.getModule = class UploadModule extends MenuModule { + + constructor(options) { + super(options); + + this.availAreas = getSortedAvailableFileAreas(this.client, { writeAcs : true } ); + + this.menuMethods = { + navContinue : (formData, extraArgs, cb) => { + if(this.isBlindUpload()) { + // jump to fileDetails form + // :TODO: support blind + } else { + // jump to protocol selection + const areaUploadDir = this.getSelectedAreaUploadDirectory(); + + const modOpts = { + extraArgs : { + recvDirectory : areaUploadDir, + direction : 'recv', + } + }; + + return this.gotoMenu(this.menuConfig.config.fileTransferProtocolSelection || 'fileTransferProtocolSelection', modOpts, cb); + } + } + }; + } + + getSelectedAreaUploadDirectory() { + const areaSelectView = this.viewControllers.options.getView(MciViewIds.options.area); + const selectedArea = this.availAreas[areaSelectView.getData()]; + + return getAreaDefaultStorageDirectory(selectedArea); + } + + isBlindUpload() { return 'blind' === this.uploadType; } + + initSequence() { + const self = this; + + async.series( + [ + function before(callback) { + return self.beforeArt(callback); + }, + function display(callback) { + return self.displayOptionsPage(false, callback); + } + ], + () => { + return self.finishedLoading(); + } + ); + } + + displayOptionsPage(cb) { + const self = this; + + async.series( + [ + function prepArtAndViewController(callback) { + return self.prepViewControllerWithArt( + 'options', + FormIds.options, + { clearScreen : true, trailingLF : false }, + callback + ); + }, + function populateViews(callback) { + const areaSelectView = self.viewControllers.options.getView(MciViewIds.options.area); + areaSelectView.setItems( self.availAreas.map(areaInfo => areaInfo.name ) ); + + const uploadTypeView = self.viewControllers.options.getView(MciViewIds.options.uploadType); + const fileNameView = self.viewControllers.options.getView(MciViewIds.options.fileName); + + const blindFileNameText = self.menuConfig.config.blindFileNameText || '(blind - filename ignored)'; + + uploadTypeView.on('index update', idx => { + self.uploadType = (0 === idx) ? 'blind' : 'non-blind'; + + if(self.isBlindUpload()) { + fileNameView.setText(blindFileNameText); + + // :TODO: when blind, fileNameView should not be focus/editable + } + }); + + uploadTypeView.setFocusItemIndex(0); // default to blind + fileNameView.setText(blindFileNameText); + areaSelectView.redraw(); + + return callback(null); + } + ], + err => { + if(cb) { + return cb(err); + } + } + ); + } + +};