* Add FileBaseFilters
* Add HTTP(S) file web server with temp URLs * Get temp web d/l from file list * Add File area filter editor (all file area stuff will be rename to file "base" later) * Concept of "listening servers" vs "login servers" * Ability to get servers by their package name * New MCI: %FN: File Base active filter name * Some ES6 updates * VC resetInitialFocus() to set focus to explicit/detected initial focus field * Limit what is dumped out when logging form data
This commit is contained in:
283
mods/file_area_filter_edit.js
Normal file
283
mods/file_area_filter_edit.js
Normal file
@@ -0,0 +1,283 @@
|
||||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
// ENiGMA½
|
||||
const MenuModule = require('../core/menu_module.js').MenuModule;
|
||||
const ViewController = require('../core/view_controller.js').ViewController;
|
||||
const getSortedAvailableFileAreas = require('../core/file_area.js').getSortedAvailableFileAreas;
|
||||
const FileBaseFilters = require('../core/file_base_filter.js');
|
||||
const stringFormat = require('../core/string_format.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
|
||||
exports.moduleInfo = {
|
||||
name : 'File Area Filter Editor',
|
||||
desc : 'Module for adding, deleting, and modifying file base filters',
|
||||
author : 'NuSkooler',
|
||||
};
|
||||
|
||||
const MciViewIds = {
|
||||
editor : {
|
||||
searchTerms : 1,
|
||||
tags : 2,
|
||||
area : 3,
|
||||
sort : 4,
|
||||
order : 5,
|
||||
filterName : 6,
|
||||
navMenu : 7,
|
||||
|
||||
selectedFilterInfo : 10, // { ...filter object ... }
|
||||
activeFilterInfo : 11, // { ...filter object ... }
|
||||
}
|
||||
};
|
||||
|
||||
exports.getModule = class FileAreaFilterEdit extends MenuModule {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.filtersArray = new FileBaseFilters(this.client).toArray(); // ordered, such that we can index into them
|
||||
this.currentFilterIndex = 0; // into |filtersArray|
|
||||
|
||||
this.menuMethods = {
|
||||
saveFilter : (formData, extraArgs, cb) => {
|
||||
return this.saveCurrentFilter(formData, cb);
|
||||
|
||||
},
|
||||
prevFilter : (formData, extraArgs, cb) => {
|
||||
this.currentFilterIndex -= 1;
|
||||
if(this.currentFilterIndex < 0) {
|
||||
this.currentFilterIndex = this.filtersArray.length - 1;
|
||||
}
|
||||
this.loadDataForFilter(this.currentFilterIndex);
|
||||
return cb(null);
|
||||
},
|
||||
nextFilter : (formData, extraArgs, cb) => {
|
||||
this.currentFilterIndex += 1;
|
||||
if(this.currentFilterIndex >= this.filtersArray.length) {
|
||||
this.currentFilterIndex = 0;
|
||||
}
|
||||
this.loadDataForFilter(this.currentFilterIndex);
|
||||
return cb(null);
|
||||
},
|
||||
makeFilterActive : (formData, extraArgs, cb) => {
|
||||
const filters = new FileBaseFilters(this.client);
|
||||
filters.setActive(this.filtersArray[this.currentFilterIndex].uuid);
|
||||
|
||||
this.updateActiveLabel();
|
||||
|
||||
// :TODO: Need to update %FN somehow
|
||||
return cb(null);
|
||||
},
|
||||
newFilter : (formData, extraArgs, cb) => {
|
||||
this.currentFilterIndex = this.filtersArray.length; // next avail slot
|
||||
this.clearForm(true); // true=reset focus
|
||||
return cb(null);
|
||||
},
|
||||
deleteFilter : (formData, extraArgs, cb) => {
|
||||
const filterUuid = this.filtersArray[this.currentFilterIndex].uuid;
|
||||
this.filtersArray.splice(this.currentFilterIndex, 1); // remove selected entry
|
||||
|
||||
// remove from stored properties
|
||||
const filters = new FileBaseFilters(this.client);
|
||||
filters.remove(filterUuid);
|
||||
filters.persist( () => {
|
||||
|
||||
//
|
||||
// If the item was also the active filter, we need to make a new one active
|
||||
//
|
||||
if(filterUuid === this.client.user.properties.file_base_filter_active_uuid) {
|
||||
const newActive = this.filtersArray[this.currentFilterIndex];
|
||||
if(newActive) {
|
||||
filters.setActive(newActive.uuid);
|
||||
} else {
|
||||
// nothing to set active to
|
||||
// :TODO: is this what we want?
|
||||
this.client.user.properties.file_base_filter_active_uuid = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// update UI
|
||||
if(this.filtersArray.length > 0) {
|
||||
this.loadDataForFilter(this.currentFilterIndex);
|
||||
} else {
|
||||
this.clearForm(true); // true=reset focus
|
||||
}
|
||||
return cb(null);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mciReady(mciData, cb) {
|
||||
super.mciReady(mciData, err => {
|
||||
if(err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
const self = this;
|
||||
const vc = self.addViewController( 'editor', new ViewController( { client : this.client } ) );
|
||||
|
||||
async.series(
|
||||
[
|
||||
function loadFromConfig(callback) {
|
||||
return vc.loadFromMenuConfig( { callingMenu : self, mciMap : mciData.menu }, callback);
|
||||
},
|
||||
function populateAreas(callback) {
|
||||
self.availAreas = [ { name : '-ALL-' } ].concat(getSortedAvailableFileAreas(self.client) || []);
|
||||
|
||||
const areasView = vc.getView(MciViewIds.editor.area);
|
||||
if(areasView) {
|
||||
areasView.setItems( self.availAreas.map( a => a.name ) );
|
||||
}
|
||||
|
||||
self.updateActiveLabel();
|
||||
self.loadDataForFilter(self.currentFilterIndex);
|
||||
self.viewControllers.editor.resetInitialFocus();
|
||||
return callback(null);
|
||||
}
|
||||
],
|
||||
err => {
|
||||
return cb(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getCurrentFilter() {
|
||||
return this.filtersArray[this.currentFilterIndex];
|
||||
}
|
||||
|
||||
setText(mciId, text) {
|
||||
const view = this.viewControllers.editor.getView(mciId);
|
||||
if(view) {
|
||||
view.setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
updateActiveLabel() {
|
||||
const activeFilter = FileBaseFilters.getActiveFilter(this.client);
|
||||
if(activeFilter) {
|
||||
const activeFormat = this.menuConfig.config.activeFormat || '{name}';
|
||||
this.setText(MciViewIds.editor.activeFilterInfo, stringFormat(activeFormat, activeFilter));
|
||||
}
|
||||
}
|
||||
|
||||
setFocusItemIndex(mciId, index) {
|
||||
const view = this.viewControllers.editor.getView(mciId);
|
||||
if(view) {
|
||||
view.setFocusItemIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
clearForm(setFocus) {
|
||||
[ MciViewIds.editor.searchTerms, MciViewIds.editor.tags, MciViewIds.editor.filterName ].forEach(mciId => {
|
||||
this.setText(mciId, '');
|
||||
});
|
||||
|
||||
[ MciViewIds.editor.area, MciViewIds.editor.order, MciViewIds.editor.sort ].forEach(mciId => {
|
||||
this.setFocusItemIndex(mciId, 0);
|
||||
});
|
||||
|
||||
if(setFocus) {
|
||||
this.viewControllers.editor.resetInitialFocus();
|
||||
}
|
||||
}
|
||||
|
||||
getSelectedAreaTag(index) {
|
||||
if(0 === index) {
|
||||
return ''; // -ALL-
|
||||
}
|
||||
const area = this.availAreas[index];
|
||||
if(!area) {
|
||||
return '';
|
||||
}
|
||||
return area.areaTag;
|
||||
}
|
||||
|
||||
getOrderBy(index) {
|
||||
return FileBaseFilters.OrderByValues[index] || FileBaseFilters.OrderByValues[0];
|
||||
}
|
||||
|
||||
setAreaIndexFromCurrentFilter() {
|
||||
let index;
|
||||
const filter = this.getCurrentFilter();
|
||||
if(filter) {
|
||||
// special treatment: areaTag saved as blank ("") if -ALL-
|
||||
index = (filter.areaTag && this.availAreas.findIndex(area => filter.areaTag === area.areaTag)) || 0;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
this.setFocusItemIndex(MciViewIds.editor.area, index);
|
||||
}
|
||||
|
||||
setOrderByFromCurrentFilter() {
|
||||
let index;
|
||||
const filter = this.getCurrentFilter();
|
||||
if(filter) {
|
||||
index = FileBaseFilters.OrderByValues.findIndex( ob => filter.order === ob ) || 0;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
this.setFocusItemIndex(MciViewIds.editor.order, index);
|
||||
}
|
||||
|
||||
setSortByFromCurrentFilter() {
|
||||
let index;
|
||||
const filter = this.getCurrentFilter();
|
||||
if(filter) {
|
||||
index = FileBaseFilters.SortByValues.findIndex( sb => filter.sort === sb ) || 0;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
this.setFocusItemIndex(MciViewIds.editor.sort, index);
|
||||
}
|
||||
|
||||
getSortBy(index) {
|
||||
return FileBaseFilters.SortByValues[index] || FileBaseFilters.SortByValues[0];
|
||||
}
|
||||
|
||||
setFilterValuesFromFormData(filter, formData) {
|
||||
filter.name = formData.value.name;
|
||||
filter.areaTag = this.getSelectedAreaTag(formData.value.areaIndex);
|
||||
filter.terms = formData.value.searchTerms;
|
||||
filter.tags = formData.value.tags;
|
||||
filter.order = this.getOrderBy(formData.value.orderByIndex);
|
||||
filter.sort = this.getSortBy(formData.value.sortByIndex);
|
||||
}
|
||||
|
||||
saveCurrentFilter(formData, cb) {
|
||||
const filters = new FileBaseFilters(this.client);
|
||||
const selectedFilter = this.filtersArray[this.currentFilterIndex];
|
||||
if(selectedFilter) {
|
||||
// *update* currently selected filter
|
||||
this.setFilterValuesFromFormData(selectedFilter, formData);
|
||||
} else {
|
||||
// add a new entry; note that UUID will be generated
|
||||
const newFilter = {};
|
||||
this.setFilterValuesFromFormData(newFilter, formData);
|
||||
|
||||
// set current to what we just saved
|
||||
newFilter.uuid = filters.add(newFilter);
|
||||
|
||||
// add to our array (at current index position)
|
||||
this.filtersArray[this.currentFilterIndex] = newFilter;
|
||||
}
|
||||
|
||||
return filters.persist(cb);
|
||||
}
|
||||
|
||||
loadDataForFilter(filterIndex) {
|
||||
const filter = this.filtersArray[filterIndex];
|
||||
if(filter) {
|
||||
this.setText(MciViewIds.editor.searchTerms, filter.terms);
|
||||
this.setText(MciViewIds.editor.tags, filter.tags);
|
||||
this.setText(MciViewIds.editor.filterName, filter.name);
|
||||
|
||||
this.setAreaIndexFromCurrentFilter();
|
||||
this.setSortByFromCurrentFilter();
|
||||
this.setOrderByFromCurrentFilter();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -13,6 +13,7 @@ const Errors = require('../core/enig_error.js').Errors;
|
||||
const ArchiveUtil = require('../core/archive_util.js');
|
||||
const Config = require('../core/config.js').config;
|
||||
const DownloadQueue = require('../core/download_queue.js');
|
||||
const FileAreaWeb = require('../core/file_area_web.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
@@ -43,7 +44,6 @@ const MciViewIds = {
|
||||
browse : {
|
||||
desc : 1,
|
||||
navMenu : 2,
|
||||
queueToggle : 3, // active queue toggle indicator - others avail in customs as {isQueued}
|
||||
// 10+ = customs
|
||||
},
|
||||
details : {
|
||||
@@ -74,7 +74,7 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||
this.filterCriteria = options.extraArgs.filterCriteria;
|
||||
}
|
||||
|
||||
this.dlQueue = new DownloadQueue(this.client.user);
|
||||
this.dlQueue = new DownloadQueue(this.client);
|
||||
|
||||
this.filterCriteria = this.filterCriteria || {
|
||||
// :TODO: set area tag - all in current area by default
|
||||
@@ -112,6 +112,9 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||
this.updateQueueIndicator();
|
||||
return cb(null);
|
||||
},
|
||||
showWebDownloadLink : (formData, extraArgs, cb) => {
|
||||
return this.fetchAndDisplayWebDownloadLink(cb);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -141,7 +144,7 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||
);
|
||||
}
|
||||
|
||||
populateCurrentEntryInfo() {
|
||||
populateCurrentEntryInfo(cb) {
|
||||
const config = this.menuConfig.config;
|
||||
const currEntry = this.currentFileEntry;
|
||||
|
||||
@@ -163,6 +166,8 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||
uploadTimestamp : moment(currEntry.uploadTimestamp).format(uploadTimestampFormat),
|
||||
hashTags : Array.from(currEntry.hashTags).join(hashTagsSep),
|
||||
isQueued : this.dlQueue.isQueued(this.currentFileEntry) ? isQueuedIndicator : isNotQueuedIndicator,
|
||||
webDlLink : '', // :TODO: fetch web any existing web d/l link
|
||||
webDlExpire : '', // :TODO: fetch web d/l link expire time
|
||||
};
|
||||
|
||||
//
|
||||
@@ -194,9 +199,27 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||
if(entryInfo.userRating < 5) {
|
||||
entryInfo.userRatingString += new Array( (5 - entryInfo.userRating) + 1).join(userRatingUnticked);
|
||||
}
|
||||
|
||||
FileAreaWeb.getExistingTempDownloadServeItem(this.client, this.currentFileEntry, (err, serveItem) => {
|
||||
if(err) {
|
||||
entryInfo.webDlLink = config.webDlLinkNeedsGenerated || 'Not yet generated';
|
||||
entryInfo.webDlExpire = '';
|
||||
} else {
|
||||
const webDlExpireTimeFormat = config.webDlExpireTimeFormat || 'YYYY-MMM-DD @ h:mm';
|
||||
|
||||
entryInfo.webDlLink = serveItem.url;
|
||||
entryInfo.webDlExpire = moment(serveItem.expireTimestamp).format(webDlExpireTimeFormat);
|
||||
}
|
||||
|
||||
return cb(null);
|
||||
});
|
||||
}
|
||||
|
||||
populateCustomLabels(category, startId) {
|
||||
return this.updateCustomLabelsWithFilter(category, startId);
|
||||
}
|
||||
|
||||
updateCustomLabelsWithFilter(category, startId, filter) {
|
||||
let textView;
|
||||
let customMciId = startId;
|
||||
const config = this.menuConfig.config;
|
||||
@@ -205,7 +228,7 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||
const key = `${category}InfoFormat${customMciId}`;
|
||||
const format = config[key];
|
||||
|
||||
if(format) {
|
||||
if(format && (!filter || filter.find(f => format.indexOf(f) > - 1))) {
|
||||
textView.setText(stringFormat(format, this.currentFileEntry.entryInfo));
|
||||
}
|
||||
|
||||
@@ -295,8 +318,11 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||
self.currentFileEntry = new FileEntry();
|
||||
|
||||
self.currentFileEntry.load( self.fileList[ self.fileListPosition ], err => {
|
||||
self.populateCurrentEntryInfo();
|
||||
return callback(err);
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
return self.populateCurrentEntryInfo(callback);
|
||||
});
|
||||
},
|
||||
function populateViews(callback) {
|
||||
@@ -360,8 +386,63 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
fetchAndDisplayWebDownloadLink(cb) {
|
||||
const self = this;
|
||||
|
||||
async.series(
|
||||
[
|
||||
function generateLinkIfNeeded(callback) {
|
||||
|
||||
if(self.currentFileEntry.webDlExpireTime < moment()) {
|
||||
return callback(null);
|
||||
}
|
||||
|
||||
const expireTime = moment().add(Config.fileBase.web.expireMinutes, 'minutes');
|
||||
|
||||
FileAreaWeb.createAndServeTempDownload(
|
||||
self.client,
|
||||
self.currentFileEntry,
|
||||
{ expireTime : expireTime },
|
||||
(err, url) => {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
self.currentFileEntry.webDlExpireTime = expireTime;
|
||||
|
||||
const webDlExpireTimeFormat = self.menuConfig.config.webDlExpireTimeFormat || 'YYYY-MMM-DD @ h:mm';
|
||||
|
||||
self.currentFileEntry.entryInfo.webDlLink = url;
|
||||
self.currentFileEntry.entryInfo.webDlExpire = expireTime.format(webDlExpireTimeFormat);
|
||||
|
||||
return callback(null);
|
||||
}
|
||||
);
|
||||
},
|
||||
function updateActiveViews(callback) {
|
||||
self.updateCustomLabelsWithFilter( 'browse', 10, [ '{webDlLink}', '{webDlExpire}' ] );
|
||||
return callback(null);
|
||||
}
|
||||
],
|
||||
err => {
|
||||
return cb(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
updateQueueIndicator() {
|
||||
const isQueuedIndicator = this.menuConfig.config.isQueuedIndicator || 'Y';
|
||||
const isNotQueuedIndicator = this.menuConfig.config.isNotQueuedIndicator || 'N';
|
||||
|
||||
this.currentFileEntry.entryInfo.isQueued = stringFormat(
|
||||
this.dlQueue.isQueued(this.currentFileEntry) ?
|
||||
isQueuedIndicator :
|
||||
isNotQueuedIndicator
|
||||
);
|
||||
|
||||
this.updateCustomLabelsWithFilter( 'browse', 10, [ '{isQueued}' ] );
|
||||
/*
|
||||
const indicatorView = this.viewControllers.browse.getView(MciViewIds.browse.queueToggle);
|
||||
|
||||
if(indicatorView) {
|
||||
@@ -374,7 +455,7 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||
isNotQueuedIndicator
|
||||
)
|
||||
);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
cacheArchiveEntries(cb) {
|
||||
|
||||
Reference in New Issue
Block a user