Ability to delete private (aka inbox) messages
This commit is contained in:
parent
2408d4c5c0
commit
0d55daabe4
162
core/msg_list.js
162
core/msg_list.js
|
@ -7,6 +7,8 @@ const ViewController = require('./view_controller.js').ViewContro
|
||||||
const messageArea = require('./message_area.js');
|
const messageArea = require('./message_area.js');
|
||||||
const stringFormat = require('./string_format.js');
|
const stringFormat = require('./string_format.js');
|
||||||
const MessageAreaConfTempSwitcher = require('./mod_mixins.js').MessageAreaConfTempSwitcher;
|
const MessageAreaConfTempSwitcher = require('./mod_mixins.js').MessageAreaConfTempSwitcher;
|
||||||
|
const Errors = require('./enig_error.js').Errors;
|
||||||
|
const Message = require('./message.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -14,7 +16,7 @@ const _ = require('lodash');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Available listFormat/focusListFormat members (VM1):
|
Available listFormat/focusListFormat members for |msgList|
|
||||||
|
|
||||||
msgNum : Message number
|
msgNum : Message number
|
||||||
to : To username/handle
|
to : To username/handle
|
||||||
|
@ -22,22 +24,28 @@ const moment = require('moment');
|
||||||
subj : Subject
|
subj : Subject
|
||||||
ts : Message mod timestamp (format with config.dateTimeFormat)
|
ts : Message mod timestamp (format with config.dateTimeFormat)
|
||||||
newIndicator : New mark/indicator (config.newIndicator)
|
newIndicator : New mark/indicator (config.newIndicator)
|
||||||
|
|
||||||
MCI codes:
|
|
||||||
|
|
||||||
VM1 : Message list
|
|
||||||
TL2 : Message info 1: { msgNumSelected, msgNumTotal }
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.moduleInfo = {
|
exports.moduleInfo = {
|
||||||
name : 'Message List',
|
name : 'Message List',
|
||||||
desc : 'Module for listing/browsing available messages',
|
desc : 'Module for listing/browsing available messages',
|
||||||
author : 'NuSkooler',
|
author : 'NuSkooler',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FormIds = {
|
||||||
|
allViews : 0,
|
||||||
|
delPrompt : 1,
|
||||||
|
};
|
||||||
|
|
||||||
const MciViewIds = {
|
const MciViewIds = {
|
||||||
msgList : 1, // VM1
|
allViews : {
|
||||||
msgInfo1 : 2, // TL2
|
msgList : 1, // VM1 - see above
|
||||||
|
delPromptXy : 2, // %XY2, e.g: delete confirmation
|
||||||
|
customRangeStart : 10, // Everything |msgList| has plus { msgNumSelected, msgNumTotal }
|
||||||
|
},
|
||||||
|
|
||||||
|
delPrompt: {
|
||||||
|
prompt : 1,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(MenuModule) {
|
exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(MenuModule) {
|
||||||
|
@ -51,7 +59,7 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
|
||||||
|
|
||||||
this.menuMethods = {
|
this.menuMethods = {
|
||||||
selectMessage : (formData, extraArgs, cb) => {
|
selectMessage : (formData, extraArgs, cb) => {
|
||||||
if(MciViewIds.msgList === formData.submitId) {
|
if(MciViewIds.allViews.msgList === formData.submitId) {
|
||||||
this.initialFocusIndex = formData.value.message;
|
this.initialFocusIndex = formData.value.message;
|
||||||
|
|
||||||
const modOpts = {
|
const modOpts = {
|
||||||
|
@ -91,10 +99,40 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
|
||||||
return cb(null);
|
return cb(null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
fullExit : (formData, extraArgs, cb) => {
|
fullExit : (formData, extraArgs, cb) => {
|
||||||
this.menuResult = { fullExit : true };
|
this.menuResult = { fullExit : true };
|
||||||
return this.prevMenu(cb);
|
return this.prevMenu(cb);
|
||||||
|
},
|
||||||
|
deleteSelected : (formData, extraArgs, cb) => {
|
||||||
|
if(MciViewIds.allViews.msgList != formData.submitId) {
|
||||||
|
return cb(null);
|
||||||
|
}
|
||||||
|
const messageIndex = _.get(formData, 'value.message');
|
||||||
|
return this.promptDeleteMessageConfirm(messageIndex, cb);
|
||||||
|
},
|
||||||
|
deleteMessageYes : (formData, extraArgs, cb) => {
|
||||||
|
const msgListView = this.viewControllers.allViews.getView(MciViewIds.allViews.msgList);
|
||||||
|
this.enableMessageListIndexUpdates(msgListView);
|
||||||
|
if(this.selectedMessageForDelete) {
|
||||||
|
this.selectedMessageForDelete.deleteMessage(this.client.user, err => {
|
||||||
|
if(err) {
|
||||||
|
this.client.log.error(`Failed to delete message: ${this.selectedMessageForDelete.messageUuid}`);
|
||||||
|
} else {
|
||||||
|
this.client.log.info(`User deleted message: ${this.selectedMessageForDelete.messageUuid}`);
|
||||||
|
this.config.messageList.splice(msgListView.focusedItemIndex, 1);
|
||||||
|
this.updateMessageNumbersAfterDelete(msgListView.focusedItemIndex);
|
||||||
|
msgListView.setItems(this.config.messageList);
|
||||||
|
}
|
||||||
|
this.selectedMessageForDelete = null;
|
||||||
|
msgListView.redraw();
|
||||||
|
return cb(null);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return cb(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deleteMessageNo : (formData, extraArgs, cb) => {
|
||||||
|
return cb(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -130,6 +168,17 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
|
||||||
super.leave();
|
super.leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
populateCustomLabelsForSelected(selectedIndex) {
|
||||||
|
const formatObj = Object.assign(
|
||||||
|
{
|
||||||
|
msgNumSelected : (selectedIndex + 1),
|
||||||
|
msgNumTotal : this.config.messageList.length,
|
||||||
|
},
|
||||||
|
this.config.messageList[selectedIndex] // plus, all the selected message props
|
||||||
|
);
|
||||||
|
return this.updateCustomViewTextsWithFilter('allViews', MciViewIds.allViews.customRangeStart, formatObj);
|
||||||
|
}
|
||||||
|
|
||||||
mciReady(mciData, cb) {
|
mciReady(mciData, cb) {
|
||||||
super.mciReady(mciData, err => {
|
super.mciReady(mciData, err => {
|
||||||
if(err) {
|
if(err) {
|
||||||
|
@ -183,7 +232,7 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
|
||||||
function updateMessageListObjects(callback) {
|
function updateMessageListObjects(callback) {
|
||||||
const dateTimeFormat = self.menuConfig.config.dateTimeFormat || self.client.currentTheme.helpers.getDateTimeFormat();
|
const dateTimeFormat = self.menuConfig.config.dateTimeFormat || self.client.currentTheme.helpers.getDateTimeFormat();
|
||||||
const newIndicator = self.menuConfig.config.newIndicator || '*';
|
const newIndicator = self.menuConfig.config.newIndicator || '*';
|
||||||
const regIndicator = new Array(newIndicator.length + 1).join(' '); // fill with space to avoid draw issues
|
const regIndicator = ' '.repeat(newIndicator.length); // fill with space to avoid draw issues
|
||||||
|
|
||||||
let msgNum = 1;
|
let msgNum = 1;
|
||||||
self.config.messageList.forEach( (listItem, index) => {
|
self.config.messageList.forEach( (listItem, index) => {
|
||||||
|
@ -200,19 +249,10 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
|
||||||
});
|
});
|
||||||
return callback(null);
|
return callback(null);
|
||||||
},
|
},
|
||||||
function populateList(callback) {
|
function populateAndDrawViews(callback) {
|
||||||
const msgListView = vc.getView(MciViewIds.msgList);
|
const msgListView = vc.getView(MciViewIds.allViews.msgList);
|
||||||
// :TODO: replace with standard custom info MCI - msgNumSelected, msgNumTotal, areaName, areaDesc, confName, confDesc, ...
|
|
||||||
const messageInfo1Format = self.menuConfig.config.messageInfo1Format || '{msgNumSelected} / {msgNumTotal}';
|
|
||||||
|
|
||||||
msgListView.setItems(self.config.messageList);
|
msgListView.setItems(self.config.messageList);
|
||||||
|
self.enableMessageListIndexUpdates(msgListView);
|
||||||
msgListView.on('index update', idx => {
|
|
||||||
self.setViewText(
|
|
||||||
'allViews',
|
|
||||||
MciViewIds.msgInfo1,
|
|
||||||
stringFormat(messageInfo1Format, { msgNumSelected : (idx + 1), msgNumTotal : self.config.messageList.length } ));
|
|
||||||
});
|
|
||||||
|
|
||||||
if(self.initialFocusIndex > 0) {
|
if(self.initialFocusIndex > 0) {
|
||||||
// note: causes redraw()
|
// note: causes redraw()
|
||||||
|
@ -221,14 +261,7 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
|
||||||
msgListView.redraw();
|
msgListView.redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
return callback(null);
|
self.populateCustomLabelsForSelected(self.initialFocusIndex || 0);
|
||||||
},
|
|
||||||
function drawOtherViews(callback) {
|
|
||||||
const messageInfo1Format = self.menuConfig.config.messageInfo1Format || '{msgNumSelected} / {msgNumTotal}';
|
|
||||||
self.setViewText(
|
|
||||||
'allViews',
|
|
||||||
MciViewIds.msgInfo1,
|
|
||||||
stringFormat(messageInfo1Format, { msgNumSelected : self.initialFocusIndex + 1, msgNumTotal : self.config.messageList.length } ));
|
|
||||||
return callback(null);
|
return callback(null);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -255,4 +288,69 @@ exports.getModule = class MessageListModule extends MessageAreaConfTempSwitcher(
|
||||||
getMenuResult() {
|
getMenuResult() {
|
||||||
return this.menuResult;
|
return this.menuResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableMessageListIndexUpdates(msgListView) {
|
||||||
|
msgListView.on('index update', idx => this.populateCustomLabelsForSelected(idx) );
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMessageNumbersAfterDelete(startIndex) {
|
||||||
|
// all index -= 1 from this point on.
|
||||||
|
for(let i = startIndex; i < this.config.messageList.length; ++i) {
|
||||||
|
const msgItem = this.config.messageList[i];
|
||||||
|
msgItem.msgNum -= 1;
|
||||||
|
msgItem.text = `${msgItem.msgNum} - ${msgItem.subject} from ${msgItem.fromUserName}`; // default text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
promptDeleteMessageConfirm(messageIndex, cb) {
|
||||||
|
const messageInfo = this.config.messageList[messageIndex];
|
||||||
|
if(!_.isObject(messageInfo)) {
|
||||||
|
return cb(Errors.Invalid(`Invalid message index: ${messageIndex}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
// :TODO: create static userHasDeleteRights() that takes id || uuid that doesn't require full msg load
|
||||||
|
this.selectedMessageForDelete = new Message();
|
||||||
|
this.selectedMessageForDelete.load( { uuid : messageInfo.messageUuid }, err => {
|
||||||
|
if(err) {
|
||||||
|
this.selectedMessageForDelete = null;
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this.selectedMessageForDelete.userHasDeleteRights(this.client.user)) {
|
||||||
|
this.selectedMessageForDelete = null;
|
||||||
|
return cb(Errors.AccessDenied('User does not have rights to delete this message'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// user has rights to delete -- prompt/confirm then proceed
|
||||||
|
return this.promptConfirmDelete(cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
promptConfirmDelete(cb) {
|
||||||
|
const promptXyView = this.viewControllers.allViews.getView(MciViewIds.allViews.delPromptXy);
|
||||||
|
if(!promptXyView) {
|
||||||
|
return cb(Errors.MissingMci(`Missing prompt XY${MciViewIds.allViews.delPromptXy} MCI`));
|
||||||
|
}
|
||||||
|
|
||||||
|
const promptOpts = {
|
||||||
|
clearAtSubmit : true,
|
||||||
|
};
|
||||||
|
if(promptXyView.dimens.width) {
|
||||||
|
promptOpts.clearWidth = promptXyView.dimens.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.promptForInput(
|
||||||
|
{
|
||||||
|
formName : 'delPrompt',
|
||||||
|
formId : FormIds.delPrompt,
|
||||||
|
promptName : this.config.deleteMessageFromListPrompt || 'deleteMessageFromListPrompt',
|
||||||
|
prevFormName : 'allViews',
|
||||||
|
position : promptXyView.position,
|
||||||
|
},
|
||||||
|
promptOpts,
|
||||||
|
err => {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue