From ac35d3506dbcefb8542edcefe40cfcc78dfa1d2f Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Sat, 1 Oct 2016 13:25:32 -0600 Subject: [PATCH] File area updates WIP --- core/conf_area_util.js | 30 +++++++++++++++ core/config.js | 4 +- core/enig_error.js | 8 ++-- core/file_area.js | 84 +++++++++++++++++++++++++++++++++++++++--- core/file_entry.js | 8 ++-- core/message_area.js | 38 ++++--------------- mods/file_area_list.js | 11 +++++- 7 files changed, 135 insertions(+), 48 deletions(-) create mode 100644 core/conf_area_util.js diff --git a/core/conf_area_util.js b/core/conf_area_util.js new file mode 100644 index 00000000..6009bb34 --- /dev/null +++ b/core/conf_area_util.js @@ -0,0 +1,30 @@ +/* jslint node: true */ +'use strict'; + +// deps +const _ = require('lodash'); + +exports.sortAreasOrConfs = sortAreasOrConfs; + +// +// Method for sorting message, file, etc. areas and confs +// If the sort key is present and is a number, sort in numerical order; +// Otherwise, use a locale comparison on the sort key or name as a fallback +// +function sortAreasOrConfs(areasOrConfs, type) { + let entryA; + let entryB; + + areasOrConfs.sort((a, b) => { + entryA = a[type]; + entryB = b[type]; + + if(_.isNumber(entryA.sort) && _.isNumber(entryB.sort)) { + return entryA.sort - entryB.sort; + } else { + const keyA = entryA.sort ? entryA.sort.toString() : entryA.name; + const keyB = entryB.sort ? entryB.sort.toString() : entryB.name; + return keyA.localeCompare(keyB); + } + }); +} \ No newline at end of file diff --git a/core/config.js b/core/config.js index 31c77275..78e55c42 100644 --- a/core/config.js +++ b/core/config.js @@ -236,7 +236,7 @@ function getDefaultConfig() { }, zmodem8kSexyz : { - name : 'ZModem 8k', + name : 'ZModem (SEXYZ)', type : 'external', external : { // :TODO: Look into shipping sexyz binaries or at least hosting them somewhere for common systems @@ -244,7 +244,7 @@ function getDefaultConfig() { sendArgs : [ '-telnet', 'sz', '{filePath}' ], - escapeTelnet : true, // set to true to escape Telnet codes such as IAC + escapeTelnet : false, // -telnet option does this for us } } diff --git a/core/enig_error.js b/core/enig_error.js index 4695608b..69c6fb3c 100644 --- a/core/enig_error.js +++ b/core/enig_error.js @@ -19,14 +19,12 @@ class EnigError extends Error { } } -// :TODO: Just use EnigError for all -class EnigMenuError extends EnigError { } - exports.EnigError = EnigError; -exports.EnigMenuError = EnigMenuError; exports.Errors = { General : (reason, reasonCode) => new EnigError('An error occurred', -33000, reason, reasonCode), - MenuStack : (reason, reasonCode) => new EnigMenuError('Menu stack error', -33001, reason, reasonCode), + MenuStack : (reason, reasonCode) => new EnigError('Menu stack error', -33001, reason, reasonCode), DoesNotExist : (reason, reasonCode) => new EnigError('Object does not exist', -33002, reason, reasonCode), + AccessDenied : (reason, reasonCode) => new EnigError('Access denied', -32003, reason, reasonCode), + Invalid : (reason, reasonCode) => new EnigError('Invalid', -32004, reason, reasonCode), }; diff --git a/core/file_area.js b/core/file_area.js index 8026c2ff..08c600af 100644 --- a/core/file_area.js +++ b/core/file_area.js @@ -2,30 +2,102 @@ 'use strict'; // ENiGMA½ -const Config = require('./config.js').config; -const Log = require('./logger.js').log; +const Config = require('./config.js').config; +const Errors = require('./enig_error.js').Errors; +const sortAreasOrConfs = require('./conf_area_util.js').sortAreasOrConfs; // deps const _ = require('lodash'); +const async = require('async'); exports.getAvailableFileAreas = getAvailableFileAreas; - +exports.getSortedAvailableFileAreas = getSortedAvailableFileAreas; +exports.getDefaultFileArea = getDefaultFileArea; exports.getFileAreaByTag = getFileAreaByTag; +exports.changeFileAreaWithOptions = changeFileAreaWithOptions; + +const WellKnownAreaTags = exports.WellKnownAreaTags = { + Invalid : '', + MessageAreaAttach : 'message_area_attach', +}; function getAvailableFileAreas(client, options) { options = options || { includeSystemInternal : false }; // perform ACS check per conf & omit system_internal if desired return _.omit(Config.fileAreas.areas, (area, areaTag) => { - /* if(!options.includeSystemInternal && 'system_internal' === confTag) { + if(!options.includeSystemInternal && WellKnownAreaTags.MessageAreaAttach === areaTag) { return true; - }*/ + } return !client.acs.hasFileAreaRead(area); }); } +function getSortedAvailableFileAreas(client, options) { + const areas = _.map(getAvailableFileAreas(client, options), (v, k) => { + return { + areaTag : k, + area : v + }; + }); + + sortAreasOrConfs(areas, 'area'); + return areas; +} + +function getDefaultFileArea(client, disableAcsCheck) { + let defaultArea = _.findKey(Config.fileAreas, o => o.default); + if(defaultArea) { + const area = Config.fileAreas.areas[defaultArea]; + if(true === disableAcsCheck || client.acs.hasFileAreaRead(area)) { + return defaultArea; + } + } + + // just use anything we can + defaultArea = _.findKey(Config.fileAreas.areas, (area, areaTag) => { + return WellKnownAreaTags.MessageAreaAttach !== areaTag && (true === disableAcsCheck || client.acs.hasFileAreaRead(area)); + }); + + return defaultArea; +} function getFileAreaByTag(areaTag) { return Config.fileAreas.areas[areaTag]; -} \ No newline at end of file +} + +function changeFileAreaWithOptions(client, areaTag, options, cb) { + async.waterfall( + [ + function getArea(callback) { + const area = getFileAreaByTag(areaTag); + return callback(area ? null : Errors.Invalid('Invalid file areaTag'), area); + }, + function validateAccess(area, callback) { + if(!client.acs.hasFileAreaRead(area)) { + return callback(Errors.AccessDenied('No access to this area')); + } + }, + function changeArea(area, callback) { + if(true === options.persist) { + client.user.persistProperty('file_area_tag', areaTag, err => { + return callback(err, area); + }); + } else { + client.user.properties['file_area_tag'] = areaTag; + return callback(null, area); + } + } + ], + (err, area) => { + if(!err) { + client.log.info( { areaTag : areaTag, area : area }, 'Current file area changed'); + } else { + client.log.warn( { areaTag : areaTag, area : area, error : err.message }, 'Could not change file area'); + } + + return cb(err); + } + ); +} diff --git a/core/file_entry.js b/core/file_entry.js index dadafb1d..ffafbe85 100644 --- a/core/file_entry.js +++ b/core/file_entry.js @@ -20,10 +20,10 @@ const FILE_WELL_KNOWN_META = { file_md5 : null, file_sha256 : null, file_crc32 : null, - est_release_year : parseInt, - dl_count : parseInt, - byte_size : parseInt, - user_rating : parseInt, + est_release_year : (y) => parseInt(y) || new Date().getFullYear(), + dl_count : (d) => parseInt(d) || 0, + byte_size : (b) => parseInt(b) || 0, + user_rating : (r) => Math.min(parseInt(r) || 0, 5), }; module.exports = class FileEntry { diff --git a/core/message_area.js b/core/message_area.js index 2f74357b..95cadf1c 100644 --- a/core/message_area.js +++ b/core/message_area.js @@ -2,11 +2,12 @@ 'use strict'; // ENiGMA½ -const msgDb = require('./database.js').dbs.message; -const Config = require('./config.js').config; -const Message = require('./message.js'); -const Log = require('./logger.js').log; -const msgNetRecord = require('./msg_network.js').recordMessage; +const msgDb = require('./database.js').dbs.message; +const Config = require('./config.js').config; +const Message = require('./message.js'); +const Log = require('./logger.js').log; +const msgNetRecord = require('./msg_network.js').recordMessage; +const sortAreasOrConfs = require('./conf_area_util.js').sortAreasOrConfs; // deps const async = require('async'); @@ -32,29 +33,6 @@ exports.updateMessageAreaLastReadId = updateMessageAreaLastReadId; exports.persistMessage = persistMessage; exports.trimMessageAreasScheduledEvent = trimMessageAreasScheduledEvent; -// -// Method for sorting Message areas and conferences -// If the sort key is present and is a number, sort in numerical order; -// Otherwise, use a locale comparison on the sort key or name as a fallback -// -function sortAreasOrConfs(areasOrConfs, type) { - let entryA; - let entryB; - - areasOrConfs.sort((a, b) => { - entryA = a[type]; - entryB = b[type]; - - if(_.isNumber(entryA.sort) && _.isNumber(entryB.sort)) { - return entryA.sort - entryB.sort; - } else { - const keyA = entryA.sort ? entryA.sort.toString() : entryA.name; - const keyB = entryB.sort ? entryB.sort.toString() : entryB.name; - return keyA.localeCompare(keyB); - } - }); -} - function getAvailableMessageConferences(client, options) { options = options || { includeSystemInternal : false }; @@ -269,7 +247,7 @@ function changeMessageConference(client, confTag, cb) { } function changeMessageAreaWithOptions(client, areaTag, options, cb) { - options = options || {}; + options = options || {}; // :TODO: this is currently pointless... cb is required... async.waterfall( [ @@ -305,7 +283,7 @@ function changeMessageAreaWithOptions(client, areaTag, options, cb) { client.log.warn( { areaTag : areaTag, area : area, error : err.message }, 'Could not change message area'); } - cb(err); + return cb(err); } ); } diff --git a/mods/file_area_list.js b/mods/file_area_list.js index 010aa4b3..a56f0a0c 100644 --- a/mods/file_area_list.js +++ b/mods/file_area_list.js @@ -151,7 +151,6 @@ exports.getModule = class FileAreaList extends MenuModule { const descView = self.viewControllers.browse.getView(MciViewIds.browse.desc); if(descView) { descView.setText(self.currentFileEntry.desc); - //descView.redraw(); } } @@ -159,6 +158,7 @@ exports.getModule = class FileAreaList extends MenuModule { const uploadTimestampFormat = config.browseUploadTimestampFormat || config.uploadTimestampFormat || 'YYYY-MMM-DD'; const area = FileArea.getFileAreaByTag(currEntry.areaTag); const hashTagsSep = config.hashTagsSep || ', '; + const entryInfo = { fileId : currEntry.fileId, areaTag : currEntry.areaTag, @@ -183,6 +183,13 @@ exports.getModule = class FileAreaList extends MenuModule { entryInfo[_.camelCase(name)] = value; }); + const userRatingChar = config.userRatingChar ? config.userRatingChar[0] : '*'; + if(_.isNumber(entryInfo.userRating)) { + entryInfo.userRatingString = new Array(entryInfo.userRating).join(userRatingChar); + } else { + entryInfo.userRatingString = ''; + } + // 10+ are custom textviews let textView; let customMciId = 10; @@ -197,6 +204,8 @@ exports.getModule = class FileAreaList extends MenuModule { ++customMciId; } + + return callback(null); } ], err => {