* 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:
Bryan Ashby 2017-01-18 22:23:53 -07:00
parent e265e3cc97
commit fb176d3ab3
8 changed files with 159 additions and 66 deletions

View File

@ -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];
} }

View File

@ -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) {

View File

@ -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

View File

@ -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;

View File

@ -1,7 +1,6 @@
#!/usr/bin/env node #!/usr/bin/env node
/* jslint node: true */ /* jslint node: true */
'use strict'; 'use strict';
/* /*

View File

@ -264,9 +264,11 @@ 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 = {};

View File

@ -333,12 +333,13 @@ 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);
@ -346,9 +347,6 @@ exports.getModule = class FileAreaList extends MenuModule {
return callback(null); return callback(null);
} }
); );
*/
descView.setText( self.currentFileEntry.desc );
} }
} else { } else {
self.updateQueueIndicator(); self.updateQueueIndicator();

View File

@ -222,7 +222,10 @@ 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) {
return nextEntry(err);
}
// if the file entry did *not* have a desc, take the user desc // if the file entry did *not* have a desc, take the user desc
if(!self.fileEntryHasDetectedDesc(newEntry)) { if(!self.fileEntryHasDetectedDesc(newEntry)) {
newEntry.desc = newValues.shortDesc.trim(); newEntry.desc = newValues.shortDesc.trim();
@ -235,18 +238,27 @@ exports.getModule = class UploadModule extends MenuModule {
if(newValues.tags.length > 0) { if(newValues.tags.length > 0) {
newEntry.setHashTags(newValues.tags); 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 :)
} }
); );
} }