enigma-bbs/core/message_base_search.js

165 lines
5.6 KiB
JavaScript

/* jslint node: true */
'use strict';
// ENiGMA½
const MenuModule = require('./menu_module.js').MenuModule;
const {
getSortedAvailMessageConferences,
getAvailableMessageAreasByConfTag,
getSortedAvailMessageAreasByConfTag,
hasMessageConfAndAreaRead,
filterMessageListByReadACS,
} = require('./message_area.js');
const Errors = require('./enig_error.js').Errors;
const Message = require('./message.js');
// deps
const _ = require('lodash');
exports.moduleInfo = {
name : 'Message Base Search',
desc : 'Module for quickly searching the message base',
author : 'NuSkooler',
};
const MciViewIds = {
search : {
searchTerms : 1,
search : 2,
conf : 3,
area : 4,
to : 5,
from : 6,
advSearch : 7,
}
};
exports.getModule = class MessageBaseSearch extends MenuModule {
constructor(options) {
super(options);
this.menuMethods = {
search : (formData, extraArgs, cb) => {
return this.searchNow(formData, cb);
}
};
}
mciReady(mciData, cb) {
super.mciReady(mciData, err => {
if(err) {
return cb(err);
}
this.prepViewController('search', 0, mciData.menu, (err, vc) => {
if(err) {
return cb(err);
}
const confView = vc.getView(MciViewIds.search.conf);
const areaView = vc.getView(MciViewIds.search.area);
if(!confView || !areaView) {
return cb(Errors.DoesNotExist('Missing one or more required views'));
}
const availConfs = [ { text : '-ALL-', data : '' } ].concat(
getSortedAvailMessageConferences(this.client).map(conf => Object.assign(conf, { text : conf.conf.name, data : conf.confTag } )) || []
);
let availAreas = [ { text : '-ALL-', data : '' } ]; // note: will populate if conf changes from ALL
confView.setItems(availConfs);
areaView.setItems(availAreas);
confView.setFocusItemIndex(0);
areaView.setFocusItemIndex(0);
confView.on('index update', idx => {
availAreas = [ { text : '-ALL-', data : '' } ].concat(
getSortedAvailMessageAreasByConfTag(availConfs[idx].confTag, { client : this.client }).map(
area => Object.assign(area, { text : area.area.name, data : area.areaTag } )
)
);
areaView.setItems(availAreas);
areaView.setFocusItemIndex(0);
});
vc.switchFocus(MciViewIds.search.searchTerms);
return cb(null);
});
});
}
searchNow(formData, cb) {
const isAdvanced = formData.submitId === MciViewIds.search.advSearch;
const value = formData.value;
const filter = {
resultType : 'messageList',
sort : 'modTimestamp',
terms : value.searchTerms,
//extraFields : [ 'area_tag', 'message_uuid', 'reply_to_message_id', 'to_user_name', 'from_user_name', 'subject', 'modified_timestamp' ],
limit : 2048, // :TODO: best way to handle this? we should probably let the user know if some results are returned
};
const returnNoResults = () => {
return this.gotoMenu(
this.menuConfig.config.noResultsMenu || 'messageSearchNoResults',
{ menuFlags : [ 'popParent' ] },
cb
);
};
if(isAdvanced) {
filter.toUserName = value.toUserName;
filter.fromUserName = value.fromUserName;
if(value.confTag && !value.areaTag) {
// areaTag may be a string or array of strings
// getAvailableMessageAreasByConfTag() returns a obj - we only need tags
filter.areaTag = _.map(
getAvailableMessageAreasByConfTag(value.confTag, { client : this.client } ),
(area, areaTag) => areaTag
);
} else if(value.areaTag) {
if(hasMessageConfAndAreaRead(this.client, value.areaTag)) {
filter.areaTag = value.areaTag; // specific conf + area
} else {
return returnNoResults();
}
}
}
Message.findMessages(filter, (err, messageList) => {
if(err) {
return cb(err);
}
// don't include results without ACS -- if the user searched by
// explicit conf/area tag, we should have already filtered (above)
if(!value.confTag && !value.areaTag) {
messageList = filterMessageListByReadACS(this.client, messageList);
}
if(0 === messageList.length) {
return returnNoResults();
}
const menuOpts = {
extraArgs : {
messageList,
noUpdateLastReadId : true
},
menuFlags : [ 'popParent' ],
};
return this.gotoMenu(
this.menuConfig.config.messageListMenu || 'messageAreaMessageList',
menuOpts,
cb
);
});
}
};