2015-10-12 05:26:27 +00:00
|
|
|
/* jslint node: true */
|
|
|
|
'use strict';
|
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
const MenuModule = require('./menu_module.js').MenuModule;
|
|
|
|
const ViewController = require('./view_controller.js').ViewController;
|
|
|
|
const theme = require('./theme.js');
|
|
|
|
const sysValidate = require('./system_view_validate.js');
|
2015-10-12 05:26:27 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
const async = require('async');
|
|
|
|
const assert = require('assert');
|
|
|
|
const _ = require('lodash');
|
|
|
|
const moment = require('moment');
|
2015-10-12 05:26:27 +00:00
|
|
|
|
|
|
|
exports.moduleInfo = {
|
|
|
|
name : 'User Configuration',
|
|
|
|
desc : 'Module for user configuration',
|
|
|
|
author : 'NuSkooler',
|
|
|
|
};
|
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
const MciCodeIds = {
|
2015-12-24 18:52:23 +00:00
|
|
|
RealName : 1,
|
|
|
|
BirthDate : 2,
|
|
|
|
Sex : 3,
|
|
|
|
Loc : 4,
|
|
|
|
Affils : 5,
|
|
|
|
Email : 6,
|
|
|
|
Web : 7,
|
|
|
|
TermHeight : 8,
|
|
|
|
Theme : 9,
|
|
|
|
Password : 10,
|
2018-01-15 19:22:11 +00:00
|
|
|
PassConfirm : 11,
|
2015-12-24 18:52:23 +00:00
|
|
|
ThemeInfo : 20,
|
|
|
|
ErrorMsg : 21,
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2015-12-24 18:52:23 +00:00
|
|
|
SaveCancel : 25,
|
2015-10-13 06:35:37 +00:00
|
|
|
};
|
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
exports.getModule = class UserConfigModule extends MenuModule {
|
|
|
|
constructor(options) {
|
|
|
|
super(options);
|
2015-10-12 05:26:27 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
const self = this;
|
2015-10-12 05:26:27 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
this.menuMethods = {
|
2015-12-24 18:52:23 +00:00
|
|
|
//
|
2017-01-26 05:18:05 +00:00
|
|
|
// Validation support
|
2015-12-24 18:52:23 +00:00
|
|
|
//
|
2017-01-26 05:18:05 +00:00
|
|
|
validateEmailAvail : function(data, cb) {
|
|
|
|
//
|
|
|
|
// If nothing changed, we know it's OK
|
|
|
|
//
|
|
|
|
if(self.client.user.properties.email_address.toLowerCase() === data.toLowerCase()) {
|
|
|
|
return cb(null);
|
2015-12-24 18:52:23 +00:00
|
|
|
}
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
// Otherwise we can use the standard system method
|
|
|
|
return sysValidate.validateEmailAvail(data, cb);
|
|
|
|
},
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
validatePassword : function(data, cb) {
|
2016-07-25 20:35:58 +00:00
|
|
|
//
|
2017-01-26 05:18:05 +00:00
|
|
|
// Blank is OK - this means we won't be changing it
|
2016-07-25 20:35:58 +00:00
|
|
|
//
|
2017-01-26 05:18:05 +00:00
|
|
|
if(!data || 0 === data.length) {
|
|
|
|
return cb(null);
|
|
|
|
}
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
// Otherwise we can use the standard system method
|
|
|
|
return sysValidate.validatePasswordSpec(data, cb);
|
|
|
|
},
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
validatePassConfirmMatch : function(data, cb) {
|
|
|
|
var passwordView = self.getView(MciCodeIds.Password);
|
|
|
|
cb(passwordView.getData() === data ? null : new Error('Passwords do not match'));
|
|
|
|
},
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
viewValidationListener : function(err, cb) {
|
|
|
|
var errMsgView = self.getView(MciCodeIds.ErrorMsg);
|
|
|
|
var newFocusId;
|
|
|
|
if(errMsgView) {
|
|
|
|
if(err) {
|
|
|
|
errMsgView.setText(err.message);
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
if(err.view.getId() === MciCodeIds.PassConfirm) {
|
|
|
|
newFocusId = MciCodeIds.Password;
|
|
|
|
var passwordView = self.getView(MciCodeIds.Password);
|
|
|
|
passwordView.clearText();
|
|
|
|
err.view.clearText();
|
2016-07-25 20:35:58 +00:00
|
|
|
}
|
2017-01-26 05:18:05 +00:00
|
|
|
} else {
|
|
|
|
errMsgView.clearText();
|
|
|
|
}
|
2015-12-24 18:52:23 +00:00
|
|
|
}
|
2017-01-26 05:18:05 +00:00
|
|
|
cb(newFocusId);
|
2015-10-13 06:35:37 +00:00
|
|
|
},
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
//
|
|
|
|
// Handlers
|
|
|
|
//
|
|
|
|
saveChanges : function(formData, extraArgs, cb) {
|
|
|
|
assert(formData.value.password === formData.value.passwordConfirm);
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
const newProperties = {
|
|
|
|
real_name : formData.value.realName,
|
|
|
|
birthdate : new Date(Date.parse(formData.value.birthdate)).toISOString(),
|
|
|
|
sex : formData.value.sex,
|
|
|
|
location : formData.value.location,
|
|
|
|
affiliation : formData.value.affils,
|
|
|
|
email_address : formData.value.email,
|
|
|
|
web_address : formData.value.web,
|
2018-01-15 19:22:11 +00:00
|
|
|
term_height : formData.value.termHeight.toString(),
|
2017-01-26 05:18:05 +00:00
|
|
|
theme_id : self.availThemeInfo[formData.value.theme].themeId,
|
|
|
|
};
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
// runtime set theme
|
|
|
|
theme.setClientTheme(self.client, newProperties.theme_id);
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
// persist all changes
|
2018-01-15 19:22:11 +00:00
|
|
|
self.client.user.persistProperties(newProperties, err => {
|
2017-01-26 05:18:05 +00:00
|
|
|
if(err) {
|
|
|
|
self.client.log.warn( { error : err.toString() }, 'Failed persisting updated properties');
|
|
|
|
// :TODO: warn end user!
|
|
|
|
return self.prevMenu(cb);
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// New password if it's not empty
|
|
|
|
//
|
|
|
|
self.client.log.info('User updated properties');
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
if(formData.value.password.length > 0) {
|
|
|
|
self.client.user.setNewAuthCredentials(formData.value.password, err => {
|
|
|
|
if(err) {
|
|
|
|
self.client.log.error( { err : err }, 'Failed storing new authentication credentials');
|
|
|
|
} else {
|
|
|
|
self.client.log.info('User changed authentication credentials');
|
|
|
|
}
|
|
|
|
return self.prevMenu(cb);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
return self.prevMenu(cb);
|
|
|
|
}
|
|
|
|
});
|
2015-12-24 18:52:23 +00:00
|
|
|
},
|
2017-01-26 05:18:05 +00:00
|
|
|
};
|
|
|
|
}
|
2015-10-13 06:35:37 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
getView(viewId) {
|
|
|
|
return this.viewControllers.menu.getView(viewId);
|
|
|
|
}
|
|
|
|
|
|
|
|
mciReady(mciData, cb) {
|
|
|
|
super.mciReady(mciData, err => {
|
2015-12-24 18:52:23 +00:00
|
|
|
if(err) {
|
2017-01-26 05:18:05 +00:00
|
|
|
return cb(err);
|
2015-12-24 18:52:23 +00:00
|
|
|
}
|
2017-01-26 05:18:05 +00:00
|
|
|
|
|
|
|
const self = this;
|
2018-01-15 19:22:11 +00:00
|
|
|
const vc = self.viewControllers.menu = new ViewController( { client : self.client} );
|
2017-01-26 05:18:05 +00:00
|
|
|
let currentThemeIdIndex = 0;
|
|
|
|
|
|
|
|
async.series(
|
|
|
|
[
|
|
|
|
function loadFromConfig(callback) {
|
|
|
|
vc.loadFromMenuConfig( { callingMenu : self, mciMap : mciData.menu }, callback);
|
|
|
|
},
|
|
|
|
function prepareAvailableThemes(callback) {
|
2018-06-14 03:02:00 +00:00
|
|
|
self.availThemeInfo = _.sortBy([...theme.getAvailableThemes()].map(entry => {
|
|
|
|
const theme = entry[1];
|
2017-01-26 05:18:05 +00:00
|
|
|
return {
|
2018-06-14 03:02:00 +00:00
|
|
|
themeId : theme.info.themeId,
|
|
|
|
name : theme.info.name,
|
|
|
|
author : theme.info.author,
|
|
|
|
desc : _.isString(theme.info.desc) ? theme.info.desc : '',
|
|
|
|
group : _.isString(theme.info.group) ? theme.info.group : '',
|
2017-01-26 05:18:05 +00:00
|
|
|
};
|
|
|
|
}), 'name');
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2018-03-14 01:22:26 +00:00
|
|
|
currentThemeIdIndex = Math.max(0, _.findIndex(self.availThemeInfo, function cmp(ti) {
|
2017-01-26 05:18:05 +00:00
|
|
|
return ti.themeId === self.client.user.properties.theme_id;
|
2018-03-14 01:22:26 +00:00
|
|
|
}));
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
callback(null);
|
|
|
|
},
|
|
|
|
function populateViews(callback) {
|
|
|
|
var user = self.client.user;
|
|
|
|
|
|
|
|
self.setViewText('menu', MciCodeIds.RealName, user.properties.real_name);
|
|
|
|
self.setViewText('menu', MciCodeIds.BirthDate, moment(user.properties.birthdate).format('YYYYMMDD'));
|
|
|
|
self.setViewText('menu', MciCodeIds.Sex, user.properties.sex);
|
|
|
|
self.setViewText('menu', MciCodeIds.Loc, user.properties.location);
|
|
|
|
self.setViewText('menu', MciCodeIds.Affils, user.properties.affiliation);
|
|
|
|
self.setViewText('menu', MciCodeIds.Email, user.properties.email_address);
|
|
|
|
self.setViewText('menu', MciCodeIds.Web, user.properties.web_address);
|
|
|
|
self.setViewText('menu', MciCodeIds.TermHeight, user.properties.term_height.toString());
|
2018-01-15 19:22:11 +00:00
|
|
|
|
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
var themeView = self.getView(MciCodeIds.Theme);
|
|
|
|
if(themeView) {
|
|
|
|
themeView.setItems(_.map(self.availThemeInfo, 'name'));
|
|
|
|
themeView.setFocusItemIndex(currentThemeIdIndex);
|
|
|
|
}
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
var realNameView = self.getView(MciCodeIds.RealName);
|
|
|
|
if(realNameView) {
|
|
|
|
realNameView.setFocus(true); // :TODO: HACK! menu.hjson sets focus, but manual population above breaks this. Needs a real fix!
|
|
|
|
}
|
2018-01-15 19:22:11 +00:00
|
|
|
|
2017-01-26 05:18:05 +00:00
|
|
|
callback(null);
|
|
|
|
}
|
|
|
|
],
|
|
|
|
function complete(err) {
|
|
|
|
if(err) {
|
|
|
|
self.client.log.warn( { error : err.toString() }, 'User configuration failed to init');
|
|
|
|
self.prevMenu();
|
|
|
|
} else {
|
|
|
|
cb(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2015-10-12 05:26:27 +00:00
|
|
|
};
|