mirror of
https://github.com/NuSkooler/enigma-bbs.git
synced 2025-06-08 13:44:39 +02:00
* WIP on upload scan/processing
* WIP on user add/edit data to uploads * Add write access (upload) to area ACS * Add upload collision handling * Add upload stats
This commit is contained in:
parent
4c1c05e4da
commit
e265e3cc97
11 changed files with 479 additions and 133 deletions
241
mods/upload.js
241
mods/upload.js
|
@ -10,10 +10,13 @@ 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;
|
||||
const scanFile = require('../core/file_area.js').scanFile;
|
||||
const getAreaStorageDirectoryByTag = require('../core/file_area.js').getAreaStorageDirectoryByTag;
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
const paths = require('path');
|
||||
|
||||
exports.moduleInfo = {
|
||||
name : 'Upload',
|
||||
|
@ -23,7 +26,8 @@ exports.moduleInfo = {
|
|||
|
||||
const FormIds = {
|
||||
options : 0,
|
||||
fileDetails : 1,
|
||||
processing : 1,
|
||||
fileDetails : 2,
|
||||
|
||||
};
|
||||
|
||||
|
@ -35,10 +39,16 @@ const MciViewIds = {
|
|||
navMenu : 4, // next/cancel/etc.
|
||||
},
|
||||
|
||||
processing : {
|
||||
// 10+ = customs
|
||||
},
|
||||
|
||||
fileDetails : {
|
||||
tags : 1, // tag(s) for item
|
||||
desc : 2, // defaults to 'desc' (e.g. from FILE_ID.DIZ)
|
||||
accept : 3, // accept fields & continue
|
||||
desc : 1, // defaults to 'desc' (e.g. from FILE_ID.DIZ)
|
||||
tags : 2, // tag(s) for item
|
||||
estYear : 3,
|
||||
accept : 4, // accept fields & continue
|
||||
// 10+ = customs
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -47,14 +57,15 @@ exports.getModule = class UploadModule extends MenuModule {
|
|||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
if(_.has(options, 'lastMenuResult.recvFilePaths')) {
|
||||
this.recvFilePaths = options.lastMenuResult.recvFilePaths;
|
||||
}
|
||||
|
||||
this.availAreas = getSortedAvailableFileAreas(this.client, { writeAcs : true } );
|
||||
|
||||
this.menuMethods = {
|
||||
navContinue : (formData, extraArgs, cb) => {
|
||||
optionsNavContinue : (formData, extraArgs, cb) => {
|
||||
if(this.isBlindUpload()) {
|
||||
// jump to fileDetails form
|
||||
// :TODO: support blind
|
||||
} else {
|
||||
// jump to protocol selection
|
||||
const areaUploadDir = this.getSelectedAreaUploadDirectory();
|
||||
|
||||
|
@ -66,20 +77,54 @@ exports.getModule = class UploadModule extends MenuModule {
|
|||
};
|
||||
|
||||
return this.gotoMenu(this.menuConfig.config.fileTransferProtocolSelection || 'fileTransferProtocolSelection', modOpts, cb);
|
||||
} else {
|
||||
// jump to fileDetails form
|
||||
// :TODO: support non-blind: collect info/filename -> upload -> complete
|
||||
}
|
||||
},
|
||||
|
||||
fileDetailsContinue : (formData, extraArgs, cb) => {
|
||||
|
||||
|
||||
// see notes in displayFileDetailsPageForEntry() about this hackery:
|
||||
cb(null);
|
||||
return this.fileDetailsCurrentEntrySubmitCallback(null, formData.value); // move on to the next entry, if any
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
getSaveState() {
|
||||
const saveState = {
|
||||
uploadType : this.uploadType,
|
||||
|
||||
};
|
||||
|
||||
if(this.isBlindUpload()) {
|
||||
saveState.areaInfo = this.getSelectedAreaInfo();
|
||||
}
|
||||
|
||||
return saveState;
|
||||
}
|
||||
|
||||
restoreSavedState(savedState) {
|
||||
if(savedState.areaInfo) {
|
||||
this.areaInfo = savedState.areaInfo;
|
||||
}
|
||||
}
|
||||
|
||||
getSelectedAreaInfo() {
|
||||
const areaSelectView = this.viewControllers.options.getView(MciViewIds.options.area);
|
||||
return this.availAreas[areaSelectView.getData()];
|
||||
}
|
||||
|
||||
getSelectedAreaUploadDirectory() {
|
||||
const areaSelectView = this.viewControllers.options.getView(MciViewIds.options.area);
|
||||
const selectedArea = this.availAreas[areaSelectView.getData()];
|
||||
|
||||
return getAreaDefaultStorageDirectory(selectedArea);
|
||||
const areaInfo = this.getSelectedAreaInfo();
|
||||
return getAreaDefaultStorageDirectory(areaInfo);
|
||||
}
|
||||
|
||||
isBlindUpload() { return 'blind' === this.uploadType; }
|
||||
|
||||
isFileTransferComplete() { return !_.isUndefined(this.recvFilePaths); }
|
||||
|
||||
initSequence() {
|
||||
const self = this;
|
||||
|
||||
|
@ -89,7 +134,11 @@ exports.getModule = class UploadModule extends MenuModule {
|
|||
return self.beforeArt(callback);
|
||||
},
|
||||
function display(callback) {
|
||||
return self.displayOptionsPage(false, callback);
|
||||
if(self.isFileTransferComplete()) {
|
||||
return self.displayProcessingPage(callback);
|
||||
} else {
|
||||
return self.displayOptionsPage(callback);
|
||||
}
|
||||
}
|
||||
],
|
||||
() => {
|
||||
|
@ -98,6 +147,110 @@ exports.getModule = class UploadModule extends MenuModule {
|
|||
);
|
||||
}
|
||||
|
||||
finishedLoading() {
|
||||
if(this.isFileTransferComplete()) {
|
||||
return this.processUploadedFiles();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
scanFiles(cb) {
|
||||
const self = this;
|
||||
|
||||
const results = {
|
||||
newEntries : [],
|
||||
dupes : [],
|
||||
};
|
||||
|
||||
async.eachSeries(this.recvFilePaths, (filePath, nextFilePath) => {
|
||||
// :TODO: virus scanning/etc. should occur around here
|
||||
|
||||
// :TODO: update scanning status art or display line "scanning {fileName}..." type of thing
|
||||
|
||||
self.client.term.pipeWrite(`|00|07\nScanning ${paths.basename(filePath)}...`);
|
||||
|
||||
scanFile(
|
||||
filePath,
|
||||
{
|
||||
areaTag : self.areaInfo.areaTag,
|
||||
storageTag : self.areaInfo.storageTags[0],
|
||||
},
|
||||
(err, fileEntry, existingEntries) => {
|
||||
if(err) {
|
||||
return nextFilePath(err);
|
||||
}
|
||||
|
||||
self.client.term.pipeWrite(' done\n');
|
||||
|
||||
// new or dupe?
|
||||
if(existingEntries.length > 0) {
|
||||
// 1:n dupes found
|
||||
results.dupes = results.dupes.concat(existingEntries);
|
||||
} else {
|
||||
// new one
|
||||
results.newEntries.push(fileEntry);
|
||||
}
|
||||
|
||||
return nextFilePath(null);
|
||||
}
|
||||
);
|
||||
}, err => {
|
||||
return cb(err, results);
|
||||
});
|
||||
}
|
||||
|
||||
processUploadedFiles() {
|
||||
//
|
||||
// For each file uploaded, we need to process & gather information
|
||||
//
|
||||
const self = this;
|
||||
|
||||
async.waterfall(
|
||||
[
|
||||
function scan(callback) {
|
||||
return self.scanFiles(callback);
|
||||
},
|
||||
function displayDupes(scanResults, callback) {
|
||||
if(0 === scanResults.dupes.length) {
|
||||
return callback(null, scanResults);
|
||||
}
|
||||
|
||||
// :TODO: display dupe info
|
||||
return callback(null, scanResults);
|
||||
},
|
||||
function prepDetails(scanResults, callback) {
|
||||
async.eachSeries(scanResults.newEntries, (newEntry, nextEntry) => {
|
||||
self.displayFileDetailsPageForEntry(newEntry, (err, newValues) => {
|
||||
if(!err) {
|
||||
// if the file entry did *not* have a desc, take the user desc
|
||||
if(!self.fileEntryHasDetectedDesc(newEntry)) {
|
||||
newEntry.desc = newValues.shortDesc.trim();
|
||||
}
|
||||
|
||||
if(newValues.estYear.length > 0) {
|
||||
newEntry.meta.est_release_year = newValues.estYear;
|
||||
}
|
||||
|
||||
if(newValues.tags.length > 0) {
|
||||
newEntry.setHashTags(newValues.tags);
|
||||
}
|
||||
}
|
||||
|
||||
return nextEntry(err);
|
||||
});
|
||||
}, err => {
|
||||
delete self.fileDetailsCurrentEntrySubmitCallback;
|
||||
return callback(err);
|
||||
});
|
||||
}
|
||||
],
|
||||
err => {
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
displayOptionsPage(cb) {
|
||||
const self = this;
|
||||
|
||||
|
@ -130,6 +283,7 @@ exports.getModule = class UploadModule extends MenuModule {
|
|||
}
|
||||
});
|
||||
|
||||
self.uploadType = 'blind';
|
||||
uploadTypeView.setFocusItemIndex(0); // default to blind
|
||||
fileNameView.setText(blindFileNameText);
|
||||
areaSelectView.redraw();
|
||||
|
@ -145,4 +299,59 @@ exports.getModule = class UploadModule extends MenuModule {
|
|||
);
|
||||
}
|
||||
|
||||
displayProcessingPage(cb) {
|
||||
// :TODO: If art is supplied, display & start processing + update status/etc.; if no art, we'll just write each status update on a new line
|
||||
return cb(null);
|
||||
}
|
||||
|
||||
fileEntryHasDetectedDesc(fileEntry) {
|
||||
return (fileEntry.desc && fileEntry.desc.length > 0);
|
||||
}
|
||||
|
||||
displayFileDetailsPageForEntry(fileEntry, cb) {
|
||||
const self = this;
|
||||
|
||||
async.series(
|
||||
[
|
||||
function prepArtAndViewController(callback) {
|
||||
return self.prepViewControllerWithArt(
|
||||
'fileDetails',
|
||||
FormIds.fileDetails,
|
||||
{ clearScreen : true, trailingLF : false },
|
||||
callback
|
||||
);
|
||||
},
|
||||
function populateViews(callback) {
|
||||
const descView = self.viewControllers.fileDetails.getView(MciViewIds.fileDetails.desc);
|
||||
|
||||
if(self.fileEntryHasDetectedDesc(fileEntry)) {
|
||||
descView.setText(fileEntry.desc);
|
||||
descView.setPropertyValue('mode', 'preview');
|
||||
|
||||
// :TODO: it would be nice to take this out of the focus order
|
||||
}
|
||||
|
||||
const tagsView = self.viewControllers.fileDetails.getView(MciViewIds.fileDetails.tags);
|
||||
tagsView.setText( Array.from(fileEntry.hashTags).join(',') ); // :TODO: optional 'hashTagsSep' like file list/browse
|
||||
|
||||
const yearView = self.viewControllers.fileDetails.getView(MciViewIds.fileDetails.estYear);
|
||||
yearView.setText(fileEntry.meta.est_release_year || '');
|
||||
|
||||
return callback(null);
|
||||
}
|
||||
],
|
||||
err => {
|
||||
//
|
||||
// we only call |cb| here if there is an error
|
||||
// else, wait for the current from to be submit - then call -
|
||||
// this way we'll move on to the next file entry when ready
|
||||
//
|
||||
if(err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
self.fileDetailsCurrentEntrySubmitCallback = cb; // stash for moduleMethods.fileDetailsContinue
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue