* Fix updating of existing file filter
* Update findFiles() to properly apply filters, sort order / direction, etc. * Properly persist hash tags @ file entry persist * Lots of improvements / additions to MCI for upload/download, etc. stats * Persist processed entries @ upload (WIP, but close!)
This commit is contained in:
parent
e265e3cc97
commit
fb176d3ab3
|
@ -46,6 +46,17 @@ module.exports = class FileBaseFilters {
|
||||||
return filterUuid;
|
return filterUuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
replace(filterUuid, filterInfo) {
|
||||||
|
const filter = this.get(filterUuid);
|
||||||
|
if(!filter) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
filterInfo.tags = this.cleanTags(filterInfo.tags);
|
||||||
|
this.filters[filterUuid] = filterInfo;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
remove(filterUuid) {
|
remove(filterUuid) {
|
||||||
delete this.filters[filterUuid];
|
delete this.filters[filterUuid];
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,13 @@ module.exports = class FileEntry {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function storeHashTags(callback) {
|
function storeHashTags(callback) {
|
||||||
return callback(null);
|
const hashTagsArray = Array.from(self.hashTags);
|
||||||
|
async.each(hashTagsArray, (hashTag, next) => {
|
||||||
|
return FileEntry.persistHashTag(self.fileId, hashTag, next);
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
return callback(err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
err => {
|
err => {
|
||||||
|
@ -192,6 +198,30 @@ module.exports = class FileEntry {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static persistHashTag(fileId, hashTag, cb) {
|
||||||
|
fileDb.serialize( () => {
|
||||||
|
fileDb.run(
|
||||||
|
`INSERT OR IGNORE INTO hash_tag (hash_tag)
|
||||||
|
VALUES (?);`,
|
||||||
|
[ hashTag ]
|
||||||
|
);
|
||||||
|
|
||||||
|
fileDb.run(
|
||||||
|
`REPLACE INTO file_hash_tag (hash_tag_id, file_id)
|
||||||
|
VALUES (
|
||||||
|
(SELECT hash_tag_id
|
||||||
|
FROM hash_tag
|
||||||
|
WHERE hash_tag = ?),
|
||||||
|
?
|
||||||
|
);`,
|
||||||
|
[ hashTag, fileId ],
|
||||||
|
err => {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
loadHashTags(cb) {
|
loadHashTags(cb) {
|
||||||
fileDb.each(
|
fileDb.each(
|
||||||
`SELECT ht.hash_tag_id, ht.hash_tag
|
`SELECT ht.hash_tag_id, ht.hash_tag
|
||||||
|
@ -226,20 +256,20 @@ module.exports = class FileEntry {
|
||||||
static getWellKnownMetaValues() { return Object.keys(FILE_WELL_KNOWN_META); }
|
static getWellKnownMetaValues() { return Object.keys(FILE_WELL_KNOWN_META); }
|
||||||
|
|
||||||
static findFiles(filter, cb) {
|
static findFiles(filter, cb) {
|
||||||
// :TODO: build search here - return [ fileid1, fileid2, ... ]
|
|
||||||
// free form
|
|
||||||
// areaTag
|
|
||||||
// tags
|
|
||||||
// order by
|
|
||||||
// sort
|
|
||||||
|
|
||||||
filter = filter || {};
|
filter = filter || {};
|
||||||
|
|
||||||
let sql =
|
let sql;
|
||||||
`SELECT file_id
|
|
||||||
FROM file`;
|
|
||||||
|
|
||||||
let sqlWhere = '';
|
let sqlWhere = '';
|
||||||
|
let sqlOrderBy;
|
||||||
|
const sqlOrderDir = 'ascending' === filter.order ? 'ASC' : 'DESC';
|
||||||
|
|
||||||
|
function getOrderByWithCast(ob) {
|
||||||
|
if( [ 'dl_count', 'user_rating', 'est_release_year', 'byte_size' ].indexOf(filter.sort) > -1 ) {
|
||||||
|
return `ORDER BY CAST(${ob} AS INTEGER)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `ORDER BY ${ob}`;
|
||||||
|
}
|
||||||
|
|
||||||
function appendWhereClause(clause) {
|
function appendWhereClause(clause) {
|
||||||
if(sqlWhere) {
|
if(sqlWhere) {
|
||||||
|
@ -250,13 +280,38 @@ module.exports = class FileEntry {
|
||||||
sqlWhere += clause;
|
sqlWhere += clause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(filter.sort) {
|
||||||
|
if(Object.keys(FILE_WELL_KNOWN_META).indexOf(filter.sort) > -1) { // sorting via a meta value?
|
||||||
|
sql =
|
||||||
|
`SELECT f.file_id
|
||||||
|
FROM file f, file_meta m`;
|
||||||
|
|
||||||
|
appendWhereClause(`f.file_id = m.file_id AND m.meta_name="${filter.sort}"`);
|
||||||
|
|
||||||
|
sqlOrderBy = `${getOrderByWithCast('m.meta_value')} ${sqlOrderDir}`;
|
||||||
|
} else {
|
||||||
|
sql =
|
||||||
|
`SELECT f.file_id, f.${filter.sort}
|
||||||
|
FROM file f`;
|
||||||
|
|
||||||
|
sqlOrderBy = getOrderByWithCast(`f.${filter.sort}`) + sqlOrderDir;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sql =
|
||||||
|
`SELECT f.file_id
|
||||||
|
FROM file`;
|
||||||
|
|
||||||
|
sqlOrderBy = `${getOrderByWithCast('f.file_id')} ${sqlOrderDir}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(filter.areaTag) {
|
if(filter.areaTag) {
|
||||||
appendWhereClause(`area_tag="${filter.areaTag}"`);
|
appendWhereClause(`f.area_tag="${filter.areaTag}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(filter.terms) {
|
if(filter.terms) {
|
||||||
appendWhereClause(
|
appendWhereClause(
|
||||||
`file_id IN (
|
`f.file_id IN (
|
||||||
SELECT rowid
|
SELECT rowid
|
||||||
FROM file_fts
|
FROM file_fts
|
||||||
WHERE file_fts MATCH "${filter.terms.replace(/"/g,'""')}"
|
WHERE file_fts MATCH "${filter.terms.replace(/"/g,'""')}"
|
||||||
|
@ -265,25 +320,24 @@ module.exports = class FileEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(filter.tags) {
|
if(filter.tags) {
|
||||||
const tags = filter.tags.split(' '); // filter stores as sep separated values
|
// build list of quoted tags; filter.tags comes in as a space separated values
|
||||||
|
const tags = filter.tags.split(' ').map( tag => `"${tag}"` ).join(',');
|
||||||
|
|
||||||
appendWhereClause(
|
appendWhereClause(
|
||||||
`file_id IN (
|
`f.file_id IN (
|
||||||
SELECT file_id
|
SELECT file_id
|
||||||
FROM file_hash_tag
|
FROM file_hash_tag
|
||||||
WHERE hash_tag_id IN (
|
WHERE hash_tag_id IN (
|
||||||
SELECT hash_tag_id
|
SELECT hash_tag_id
|
||||||
FROM hash_tag
|
FROM hash_tag
|
||||||
WHERE hash_tag IN (${tags.join(',')})
|
WHERE hash_tag IN (${tags})
|
||||||
)
|
)
|
||||||
)`
|
)`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// :TODO: filter.orderBy
|
sql += `${sqlWhere} ${sqlOrderBy};`;
|
||||||
// :TODO: filter.sort
|
|
||||||
|
|
||||||
sql += sqlWhere + ';';
|
|
||||||
const matchingFileIds = [];
|
const matchingFileIds = [];
|
||||||
fileDb.each(sql, (err, fileId) => {
|
fileDb.each(sql, (err, fileId) => {
|
||||||
if(fileId) {
|
if(fileId) {
|
||||||
|
|
|
@ -37,6 +37,17 @@ function setNextRandomRumor(cb) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRatio(client, propA, propB) {
|
||||||
|
const a = StatLog.getUserStatNum(client.user, propA);
|
||||||
|
const b = StatLog.getUserStatNum(client.user, propB);
|
||||||
|
const ratio = ~~((a / b) * 100);
|
||||||
|
return `${ratio}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function userStatAsString(client, statName, defaultValue) {
|
||||||
|
return (StatLog.getUserStat(client.user, statName) || defaultValue).toString();
|
||||||
|
}
|
||||||
|
|
||||||
function getPredefinedMCIValue(client, code) {
|
function getPredefinedMCIValue(client, code) {
|
||||||
|
|
||||||
if(!client || !code) {
|
if(!client || !code) {
|
||||||
|
@ -69,16 +80,16 @@ function getPredefinedMCIValue(client, code) {
|
||||||
UN : function userName() { return client.user.username; },
|
UN : function userName() { return client.user.username; },
|
||||||
UI : function userId() { return client.user.userId.toString(); },
|
UI : function userId() { return client.user.userId.toString(); },
|
||||||
UG : function groups() { return _.values(client.user.groups).join(', '); },
|
UG : function groups() { return _.values(client.user.groups).join(', '); },
|
||||||
UR : function realName() { return client.user.properties.real_name; },
|
UR : function realName() { return userStatAsString(client, 'real_name', ''); },
|
||||||
LO : function location() { return client.user.properties.location; },
|
LO : function location() { return userStatAsString(client, 'location', ''); },
|
||||||
UA : function age() { return client.user.getAge().toString(); },
|
UA : function age() { return client.user.getAge().toString(); },
|
||||||
UB : function birthdate() { return moment(client.user.properties.birthdate).format(client.currentTheme.helpers.getDateFormat()); },
|
BD : function birthdate() { return moment(client.user.properties.birthdate).format(client.currentTheme.helpers.getDateFormat()); }, // iNiQUiTY
|
||||||
US : function sex() { return client.user.properties.sex; },
|
US : function sex() { return userStatAsString(client, 'sex', ''); },
|
||||||
UE : function emailAddres() { return client.user.properties.email_address; },
|
UE : function emailAddres() { return userStatAsString(client, 'email_address', ''); },
|
||||||
UW : function webAddress() { return client.user.properties.web_address; },
|
UW : function webAddress() { return userStatAsString(client, 'web_address', ''); },
|
||||||
UF : function affils() { return client.user.properties.affiliation; },
|
UF : function affils() { return userStatAsString(client, 'affiliation', ''); },
|
||||||
UT : function themeId() { return client.user.properties.theme_id; },
|
UT : function themeId() { return userStatAsString(client, 'theme_id', ''); },
|
||||||
UC : function loginCount() { return client.user.properties.login_count.toString(); },
|
UC : function loginCount() { return userStatAsString(client, 'login_count', 0); },
|
||||||
ND : function connectedNode() { return client.node.toString(); },
|
ND : function connectedNode() { return client.node.toString(); },
|
||||||
IP : function clientIpAddress() { return client.address().address; },
|
IP : function clientIpAddress() { return client.address().address; },
|
||||||
ST : function serverName() { return client.session.serverName; },
|
ST : function serverName() { return client.session.serverName; },
|
||||||
|
@ -86,26 +97,27 @@ function getPredefinedMCIValue(client, code) {
|
||||||
const activeFilter = FileBaseFilters.getActiveFilter(client);
|
const activeFilter = FileBaseFilters.getActiveFilter(client);
|
||||||
return activeFilter ? activeFilter.name : '';
|
return activeFilter ? activeFilter.name : '';
|
||||||
},
|
},
|
||||||
DN : function userNumDownloads() { return StatLog.getUserStat(client.user, 'dl_total_count'); }, // Obv/2
|
DN : function userNumDownloads() { return userStatAsString(client, 'dl_total_count', 0); }, // Obv/2
|
||||||
DK : function userByteDownload() { // Obv/2
|
DK : function userByteDownload() { // Obv/2 uses DK=downloaded Kbytes
|
||||||
const byteSize = parseInt(StatLog.getUserStat(client.user, 'dl_total_bytes')) || 0;
|
const byteSize = StatLog.getUserStatNum(client.user, 'dl_total_bytes');
|
||||||
return formatByteSize(byteSize, true);
|
return formatByteSize(byteSize, true); // true=withAbbr
|
||||||
|
},
|
||||||
|
UP : function userNumUploads() { return userStatAsString(client, 'ul_total_count', 0); }, // Obv/2
|
||||||
|
UK : function userByteUpload() { // Obv/2 uses UK=uploaded Kbytes
|
||||||
|
const byteSize = StatLog.getUserStatNum(client.user, 'ul_total_bytes');
|
||||||
|
return formatByteSize(byteSize, true); // true=withAbbr
|
||||||
|
},
|
||||||
|
NR : function userUpDownRatio() { // Obv/2
|
||||||
|
return getRatio(client, 'ul_total_count', 'dl_total_count');
|
||||||
|
},
|
||||||
|
KR : function userUpDownByteRatio() { // Obv/2 uses KR=upload/download Kbyte ratio
|
||||||
|
return getRatio(client, 'ul_total_bytes', 'dl_total_bytes');
|
||||||
},
|
},
|
||||||
// :TODO: Up/down ratio (count)
|
|
||||||
// :TODO: Up/down ratio (bytes)
|
|
||||||
|
|
||||||
MS : function accountCreated() { return moment(client.user.properties.account_created).format(client.currentTheme.helpers.getDateFormat()); },
|
MS : function accountCreated() { return moment(client.user.properties.account_created).format(client.currentTheme.helpers.getDateFormat()); },
|
||||||
CS : function currentStatus() { return client.currentStatus; },
|
CS : function currentStatus() { return client.currentStatus; },
|
||||||
PS : function userPostCount() {
|
PS : function userPostCount() { return userStatAsString(client, 'post_count', 0); },
|
||||||
const postCount = client.user.properties.post_count || 0;
|
PC : function userPostCallRatio() { return getRatio(client, 'post_count', 'login_count'); },
|
||||||
return postCount.toString();
|
|
||||||
},
|
|
||||||
PC : function userPostCallRatio() {
|
|
||||||
const postCount = client.user.properties.post_count || 0;
|
|
||||||
const callCount = client.user.properties.login_count;
|
|
||||||
const ratio = ~~((postCount / callCount) * 100);
|
|
||||||
return `${ratio}%`;
|
|
||||||
},
|
|
||||||
|
|
||||||
MD : function currentMenuDescription() {
|
MD : function currentMenuDescription() {
|
||||||
return _.has(client, 'currentMenuModule.menuConfig.desc') ? client.currentMenuModule.menuConfig.desc : '';
|
return _.has(client, 'currentMenuModule.menuConfig.desc') ? client.currentMenuModule.menuConfig.desc : '';
|
||||||
|
@ -181,6 +193,7 @@ function getPredefinedMCIValue(client, code) {
|
||||||
//
|
//
|
||||||
// :TODO: DD - Today's # of downloads (iNiQUiTY)
|
// :TODO: DD - Today's # of downloads (iNiQUiTY)
|
||||||
//
|
//
|
||||||
|
// :TODO: System stat log for total ul/dl, total ul/dl bytes
|
||||||
|
|
||||||
//
|
//
|
||||||
// Special handling for XY
|
// Special handling for XY
|
||||||
|
|
|
@ -122,6 +122,10 @@ class StatLog {
|
||||||
return user.properties[statName];
|
return user.properties[statName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getUserStatNum(user, statName) {
|
||||||
|
return parseInt(this.getUserStat(user, statName)) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
incrementUserStat(user, statName, incrementBy, cb) {
|
incrementUserStat(user, statName, incrementBy, cb) {
|
||||||
incrementBy = incrementBy || 1;
|
incrementBy = incrementBy || 1;
|
||||||
|
|
||||||
|
|
1
main.js
1
main.js
|
@ -1,7 +1,6 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/* jslint node: true */
|
/* jslint node: true */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -262,11 +262,13 @@ exports.getModule = class FileAreaFilterEdit extends MenuModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
saveCurrentFilter(formData, cb) {
|
saveCurrentFilter(formData, cb) {
|
||||||
const filters = new FileBaseFilters(this.client);
|
const filters = new FileBaseFilters(this.client);
|
||||||
const selectedFilter = this.filtersArray[this.currentFilterIndex];
|
const selectedFilter = this.filtersArray[this.currentFilterIndex];
|
||||||
|
|
||||||
if(selectedFilter) {
|
if(selectedFilter) {
|
||||||
// *update* currently selected filter
|
// *update* currently selected filter
|
||||||
this.setFilterValuesFromFormData(selectedFilter, formData);
|
this.setFilterValuesFromFormData(selectedFilter, formData);
|
||||||
|
filters.replace(selectedFilter.uuid, selectedFilter);
|
||||||
} else {
|
} else {
|
||||||
// add a new entry; note that UUID will be generated
|
// add a new entry; note that UUID will be generated
|
||||||
const newFilter = {};
|
const newFilter = {};
|
||||||
|
|
|
@ -333,22 +333,20 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||||
if(_.isString(self.currentFileEntry.desc)) {
|
if(_.isString(self.currentFileEntry.desc)) {
|
||||||
const descView = self.viewControllers.browse.getView(MciViewIds.browse.desc);
|
const descView = self.viewControllers.browse.getView(MciViewIds.browse.desc);
|
||||||
if(descView) {
|
if(descView) {
|
||||||
/* :TODO: finish createCleanAnsi() and use here!!!
|
|
||||||
createCleanAnsi(
|
createCleanAnsi(
|
||||||
self.currentFileEntry.desc,
|
self.currentFileEntry.desc,
|
||||||
{ height : self.client.termHeight, width : descView.dimens.width },
|
{ height : self.client.termHeight, width : descView.dimens.width },
|
||||||
cleanDesc => {
|
cleanDesc => {
|
||||||
descView.setText(cleanDesc);
|
// :TODO: use cleanDesc -- need to finish createCleanAnsi() !!
|
||||||
|
//descView.setText(cleanDesc);
|
||||||
|
descView.setText( self.currentFileEntry.desc );
|
||||||
|
|
||||||
self.updateQueueIndicator();
|
self.updateQueueIndicator();
|
||||||
self.populateCustomLabels('browse', 10);
|
self.populateCustomLabels('browse', 10);
|
||||||
|
|
||||||
return callback(null);
|
return callback(null);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
*/
|
|
||||||
|
|
||||||
descView.setText( self.currentFileEntry.desc );
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.updateQueueIndicator();
|
self.updateQueueIndicator();
|
||||||
|
|
|
@ -222,31 +222,43 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
function prepDetails(scanResults, callback) {
|
function prepDetails(scanResults, callback) {
|
||||||
async.eachSeries(scanResults.newEntries, (newEntry, nextEntry) => {
|
async.eachSeries(scanResults.newEntries, (newEntry, nextEntry) => {
|
||||||
self.displayFileDetailsPageForEntry(newEntry, (err, newValues) => {
|
self.displayFileDetailsPageForEntry(newEntry, (err, newValues) => {
|
||||||
if(!err) {
|
if(err) {
|
||||||
// if the file entry did *not* have a desc, take the user desc
|
return nextEntry(err);
|
||||||
if(!self.fileEntryHasDetectedDesc(newEntry)) {
|
}
|
||||||
newEntry.desc = newValues.shortDesc.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(newValues.estYear.length > 0) {
|
// if the file entry did *not* have a desc, take the user desc
|
||||||
newEntry.meta.est_release_year = newValues.estYear;
|
if(!self.fileEntryHasDetectedDesc(newEntry)) {
|
||||||
}
|
newEntry.desc = newValues.shortDesc.trim();
|
||||||
|
}
|
||||||
|
|
||||||
if(newValues.tags.length > 0) {
|
if(newValues.estYear.length > 0) {
|
||||||
newEntry.setHashTags(newValues.tags);
|
newEntry.meta.est_release_year = newValues.estYear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(newValues.tags.length > 0) {
|
||||||
|
newEntry.setHashTags(newValues.tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nextEntry(err);
|
return nextEntry(err);
|
||||||
});
|
});
|
||||||
}, err => {
|
}, err => {
|
||||||
delete self.fileDetailsCurrentEntrySubmitCallback;
|
delete self.fileDetailsCurrentEntrySubmitCallback;
|
||||||
|
return callback(err, scanResults);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function persistNewEntries(scanResults, callback) {
|
||||||
|
// loop over entries again & persist to DB
|
||||||
|
async.eachSeries(scanResults.newEntries, (newEntry, nextEntry) => {
|
||||||
|
newEntry.persist(err => {
|
||||||
|
return nextEntry(err);
|
||||||
|
});
|
||||||
|
}, err => {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
err => {
|
err => {
|
||||||
|
console.log('eh'); // :TODO: remove me :)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue