'use strict';
var path = require('path'),
// request = require('superagent'),
async = require('async'),
fs = require('fs-extra'),
str2json = require('string-to-json'),
merge = require('utils-merge'),
ejs = require('ejs'),
Utilities = require('periodicjs.core.utilities'),
ControllerHelper = require('periodicjs.core.controller'),
CoreUtilities,
CoreController,
appSettings,
dbSettings,
mongoose,
AppDBSetting,
logger,
restartfile = path.join(process.cwd(), '/content/extensions/restart.json'),
CoreMailer = require('periodicjs.core.mailer'),
Extensions = require('periodicjs.core.extensions'),
ExtensionCore = new Extensions({
extensionFilePath: path.resolve(process.cwd(), './content/extensions/extensions.json')
}),
changedemailtemplate,
emailtransport;
/**
* default email settings, sends mail with nodemailer and mail core extension
* @param {object} options - contains email options and nodemailer transport
* @param {Function} callbackk async callback
*/
var sendEmail = function (options, callback) {
var mailtransport = options.mailtransport,
user = options.user,
mailoptions = {};
mailoptions.to = (options.to) ? options.to : appSettings.adminnotificationemail;
mailoptions.cc = user.email; //options.cc;
mailoptions.bcc = options.bcc;
mailoptions.replyTo = options.replyTo;
mailoptions.subject = options.subject;
if (options.generatetextemail) {
mailoptions.generateTextFromHTML = true;
}
mailoptions.html = options.html;
mailoptions.text = options.text;
mailtransport.sendMail(mailoptions, callback);
};
/**
* send setting update email
* @param {object} options - contains email options and nodemailer transport
* @param {Function} callbackk async callback
*/
var sendSettingEmail = function (options, callback) {
var settingemailoptions = options;
settingemailoptions.subject = (options.subject) ? options.subject : appSettings.name + ' -Admin Email Notification';
settingemailoptions.generatetextemail = true;
settingemailoptions.html = ejs.render(options.emailtemplate, settingemailoptions);
// console.log('settingemailoptions',settingemailoptions);
sendEmail(settingemailoptions, callback);
};
/**
* restarts application response handler and send notification email
* @param {object} req
* @param {object} res
* @return {object} reponds with an error page or sends user to authenicated in resource
*/
var restart_app = function (req, res) {
CoreUtilities.restart_app({
restartfile: restartfile
});
CoreController.handleDocumentQueryRender({
req: req,
res: res,
redirecturl: '/p-admin/settings',
responseData: {
result: 'success',
data: 'restarted'
}
});
if (changedemailtemplate && emailtransport) {
var d = new Date();
fs.readFile(changedemailtemplate, 'utf8', function (err, templatestring) {
if (err) {
logger.err(err);
}
else if (templatestring) {
sendSettingEmail({
subject: appSettings.name + '[env:' + appSettings.application.environment + '] Application Restart Notification',
user: req.user,
hostname: req.headers.host,
appname: appSettings.name,
appenvironment: appSettings.application.environment,
appport: appSettings.application.port,
settingmessage: 'Your application was restarted from the admin interface - ' + d,
emailtemplate: templatestring,
mailtransport: emailtransport
}, function (err, status) {
if (err) {
logger.error(err);
}
else {
console.info('email status', status);
}
});
}
});
}
};
/**
* placeholder response for updating application
* @param {object} req
* @param {object} res
* @return {object} reponds with an error page or sends user to authenicated in resource
*/
var update_app = function (req, res) {
CoreController.handleDocumentQueryRender({
req: req,
res: res,
redirecturl: '/p-admin/settings',
responseData: {
result: 'success',
data: 'restarted'
}
});
};
/**
* load the extensions configuration files from the installed config folder in content/config/extensions/[extension]/[config files]
* @param {object} req
* @param {object} res
* @param {Function} next
*/
var load_extension_settings = function (req, res, next) {
var extname = req.params.id,
ext_default_config_file_path = path.resolve(process.cwd(), 'node_modules/', extname, 'config'),
ext_installed_config_file_path = path.resolve(process.cwd(), 'content/config/extensions/', extname);
/**
* load config files into array of filejson
* @param {Function} callback async callbackk
* @return {array} array of file data objects
*/
var loadconfigfiles = function (callback) {
var configfilesJSON = [];
fs.readdir(ext_installed_config_file_path, function (err, configfiles) {
if (configfiles && configfiles.length > 0) {
async.each(configfiles, function (configFile, cb) {
if (path.extname(configFile) === '.json') {
fs.readJson(path.resolve(ext_installed_config_file_path, configFile), function (err, data) {
if (err) {
cb(err);
}
else {
configfilesJSON.push({
name: configFile,
filedata: data
});
cb(null);
}
});
}
else {
fs.readFile(path.resolve(ext_installed_config_file_path, configFile), 'utf8', function (err, data) {
if (err) {
cb(err);
}
else {
configfilesJSON.push({
name: configFile,
filedata: data
});
cb(null);
}
});
}
}, function (err) {
if (err) {
callback(err);
}
else {
callback(null, configfilesJSON);
}
});
}
else {
callback(null, configfilesJSON);
}
});
};
req.controllerData = (req.controllerData) ? req.controllerData : {};
async.waterfall([
function (cb) {
cb(null, {
ext_default_config_file_path: ext_default_config_file_path,
ext_installed_config_file_path: ext_installed_config_file_path
});
},
ExtensionCore.getExtensionConfigFiles,
ExtensionCore.copyMissingConfigFiles,
loadconfigfiles
],
function (err, result) {
if (err) {
CoreController.handleDocumentQueryErrorResponse({
err: err,
res: res,
req: req
});
}
else {
// console.log('err', err, 'result', result);
req.controllerData.extconfigfiles = result;
next();
}
});
};
/**
* save data from config page post
* @param {object} req
* @param {object} res
*/
var update_ext_filedata = function (req, res) {
var updateConfigFileData = CoreUtilities.removeEmptyObjectValues(req.body),
extconffile = path.resolve(process.cwd(), 'content/config/extensions/', updateConfigFileData.extname, updateConfigFileData.filename),
jsonParseError;
delete updateConfigFileData._csrf;
try {
updateConfigFileData.filedata = (path.extname(updateConfigFileData.filename) === '.json') ? JSON.parse(updateConfigFileData.filedata) : updateConfigFileData.filedata;
}
catch (e) {
jsonParseError = e;
}
if (path.extname(updateConfigFileData.filename) === '.json') {
logger.warn('write json');
fs.writeJson(extconffile, updateConfigFileData.filedata, function (err) {
if (err) {
CoreController.handleDocumentQueryErrorResponse({
err: err,
res: res,
req: req
});
}
else if (jsonParseError) {
CoreController.handleDocumentQueryErrorResponse({
err: 'JSON Parse Error: ' + jsonParseError,
res: res,
req: req
});
}
else {
CoreController.handleDocumentQueryRender({
req: req,
res: res,
redirecturl: '/p-admin/extension/' + updateConfigFileData.extname,
responseData: {
result: 'success',
data: 'updated config file and restarted application'
},
callback: function () {
CoreUtilities.restart_app({
restartfile: restartfile
});
}
});
}
});
}
else {
logger.warn('write file');
fs.outputFile(extconffile, updateConfigFileData.filedata, function (err) {
if (err) {
CoreController.handleDocumentQueryErrorResponse({
err: err,
res: res,
req: req
});
}
else if (jsonParseError) {
CoreController.handleDocumentQueryErrorResponse({
err: 'JSON Parse Error: ' + jsonParseError,
res: res,
req: req
});
}
else {
CoreController.handleDocumentQueryRender({
req: req,
res: res,
redirecturl: '/p-admin/extension/' + updateConfigFileData.extname,
responseData: {
result: 'success',
data: 'updated config file and restarted application'
},
callback: function () {
CoreUtilities.restart_app({
restartfile: restartfile
});
}
});
}
});
}
};
/**
* load app configuration information
* @param {object} req
* @param {object} res
* @param {object} next async callback
* @return {object} reponds with an error page or sends user to authenicated in resource
*/
var load_app_settings = function (req, res, next) {
var appsettings = {
readonly: {
application: appSettings.application,
cookies: appSettings.cookies,
crsf: appSettings.crsf,
database: dbSettings.url,
expressCompression: appSettings.expressCompression,
theme: appSettings.theme,
templatefileextension: appSettings.templatefileextension,
templateengine: appSettings.templateengine,
sessions: appSettings.sessions,
version: appSettings.version,
},
configuration: {
adminnotificationemail: appSettings.adminnotificationemail,
serverfromemail: appSettings.serverfromemail,
debug: appSettings.debug,
homepage: appSettings.homepage,
name: appSettings.name,
}
};
req.controllerData = (req.controllerData) ? req.controllerData : {};
req.controllerData.appsettings = appsettings;
next();
};
/**
* load theme configuration information
* @param {object} req
* @param {object} res
* @param {object} next async callback
* @return {object} reponds with an error page or sends user to authenicated in resource
*/
var load_theme_settings = function (req, res, next) {
var themesettings = {
readonly: {
name: appSettings.themeSettings.name,
periodicCompatibility: appSettings.themeSettings.periodicCompatibility,
author: appSettings.themeSettings.author,
url: appSettings.themeSettings.url,
templatefileextension: appSettings.templatefileextension,
templateengine: appSettings.templateengine,
themepath: appSettings.themepath
},
configuration: {
settings: appSettings.themeSettings.settings,
}
};
req.controllerData = (req.controllerData) ? req.controllerData : {};
req.controllerData.themesettings = themesettings;
next();
};
/**
* form upload handler to update app settings, and sends notification email
* @param {object} req
* @param {object} res
* @param {object} next async callback
* @return {object} reponds with an error page or sends user to authenicated in resource
*/
var update_app_settings = function (req, res) {
var updatedAppSettings = CoreUtilities.removeEmptyObjectValues(req.body),
appsettingsfile = path.join(process.cwd(), 'content/config/config.json');
updatedAppSettings = CoreUtilities.replaceBooleanStringObjectValues(updatedAppSettings);
delete updatedAppSettings._csrf;
fs.readJson(appsettingsfile, function (err, appconfig) {
if (err) {
CoreController.handleDocumentQueryErrorResponse({
err: err,
res: res,
req: req
});
}
else {
updatedAppSettings = str2json.convert(updatedAppSettings);
var originalconfig = appconfig,
mergedconfig = merge(originalconfig, updatedAppSettings);
fs.writeJson(appsettingsfile, mergedconfig, function (err) {
if (err) {
CoreController.handleDocumentQueryErrorResponse({
err: err,
res: res,
req: req
});
}
else {
CoreController.handleDocumentQueryRender({
req: req,
res: res,
redirecturl: '/p-admin/settings',
responseData: {
result: 'success',
data: 'app config updated'
},
callback: function () {
CoreUtilities.restart_app({
restartfile: restartfile
});
}
});
if (changedemailtemplate && emailtransport) {
var d = new Date();
fs.readFile(changedemailtemplate, 'utf8', function (err, templatestring) {
if (err) {
logger.err(err);
}
else if (templatestring) {
sendSettingEmail({
subject: appSettings.name + '[env:' + appSettings.application.environment + '] Application Configuration Change Notification',
user: req.user,
hostname: req.headers.host,
appname: appSettings.name,
appenvironment: appSettings.application.environment,
appport: appSettings.application.port,
settingmessage: '<p>Your application was configuration was changed from the admin interface - ' + d + '</p><p><pre>' + JSON.stringify(mergedconfig, null, '\t') + '</pre></p>',
emailtemplate: templatestring,
mailtransport: emailtransport
}, function (err, status) {
if (err) {
logger.error(err);
}
else {
console.info('email status', status);
}
});
}
});
}
}
});
}
});
};
/**
* form upload handler to update theme settings, and sends notification email
* @param {object} req
* @param {object} res
* @param {object} next async callback
* @return {object} reponds with an error page or sends user to authenicated in resource
*/
var update_theme_settings = function (req, res) {
var updatedThemeSettings = CoreUtilities.removeEmptyObjectValues(req.body),
themesettingsfile = path.join(process.cwd(), 'content/themes', appSettings.theme, 'periodicjs.theme.json');
updatedThemeSettings = CoreUtilities.replaceBooleanStringObjectValues(updatedThemeSettings);
delete updatedThemeSettings._csrf;
fs.readJson(themesettingsfile, function (err, themeconfig) {
if (err) {
CoreController.handleDocumentQueryErrorResponse({
err: err,
res: res,
req: req
});
}
else {
updatedThemeSettings = str2json.convert(updatedThemeSettings);
var originalsettings = themeconfig.settings,
mergedsettings = merge(originalsettings, updatedThemeSettings.settings),
newthemeconfig = themeconfig;
newthemeconfig.settings = mergedsettings;
fs.writeJson(themesettingsfile, newthemeconfig, function (err) {
if (err) {
CoreController.handleDocumentQueryErrorResponse({
err: err,
res: res,
req: req
});
}
else {
CoreController.handleDocumentQueryRender({
req: req,
res: res,
redirecturl: '/p-admin/settings',
responseData: {
result: 'success',
data: 'theme config updated'
},
callback: function () {
CoreUtilities.restart_app({
restartfile: restartfile
});
}
});
if (changedemailtemplate && emailtransport) {
var d = new Date();
fs.readFile(changedemailtemplate, 'utf8', function (err, templatestring) {
if (err) {
logger.err(err);
}
else if (templatestring) {
sendSettingEmail({
subject: appSettings.name + '[env:' + appSettings.application.environment + '] Application Theme Setting Change Notification',
user: req.user,
hostname: req.headers.host,
appname: appSettings.name,
appenvironment: appSettings.application.environment,
appport: appSettings.application.port,
settingmessage: '<p>Your theme configuration was changed from the admin interface - ' + d + '</p><p><pre>' + JSON.stringify(newthemeconfig, null, '\t') + '</pre></p>',
emailtemplate: templatestring,
mailtransport: emailtransport
}, function (err, status) {
if (err) {
logger.error(err);
}
else {
console.info('email status', status);
}
});
}
});
}
}
});
}
});
};
/**
* settings controller
* @module settingsController
* @{@link https://github.com/typesettin/periodicjs.ext.admin}
* @author Yaw Joseph Etse
* @copyright Copyright (c) 2014 Typesettin. All rights reserved.
* @license MIT
* @requires module:async
* @requires module:path
* @requires module:string-to-json
* @requires module:utils-merge
* @requires module:ejs
* @requires module:periodicjs.core.utilities
* @requires module:periodicjs.core.controller
* @requires module:periodicjs.core.mailer
* @param {object} resources variable injection from current periodic instance with references to the active logger and mongo session
* @return {object} settings
*/
var controller = function (resources) {
logger = resources.logger;
mongoose = resources.mongoose;
appSettings = resources.settings;
dbSettings = resources.db;
CoreController = new ControllerHelper(resources);
CoreUtilities = new Utilities(resources);
AppDBSetting = mongoose.model('Setting');
CoreController.getPluginViewDefaultTemplate({
viewname: 'p-admin/email/settings/notification',
themefileext: appSettings.templatefileextension
},
function (err, templatepath) {
if (templatepath === 'p-admin/email/settings/notification') {
templatepath = path.resolve(process.cwd(), 'node_modules/periodicjs.ext.admin/views', templatepath + '.' + appSettings.templatefileextension);
}
changedemailtemplate = templatepath;
}
);
CoreMailer.getTransport({
appenvironment: appSettings.application.environment
}, function (err, transport) {
if (err) {
console.error(err);
}
else {
emailtransport = transport;
}
});
return {
load_extension_settings: load_extension_settings,
update_ext_filedata: update_ext_filedata,
load_app_settings: load_app_settings,
load_theme_settings: load_theme_settings,
restart_app: restart_app,
update_app: update_app,
update_theme_settings: update_theme_settings,
update_app_settings: update_app_settings
};
};
module.exports = controller;