Minor code cleanup, docs and other bits & pieces

This commit is contained in:
Hannah Wolfe 2013-08-06 20:27:56 +01:00
parent eac3047d45
commit 2f11f053ab
10 changed files with 218 additions and 225 deletions

View File

@ -168,7 +168,7 @@ var path = require('path'),
"core/client/**/*.js"
],
"except": [
"!core/client/assets/**/*.js",
"!core/**/vendor/**/*.js",
"!core/client/tpl/**/*.js"
]
}

View File

@ -1,58 +1,43 @@
// # Ghost Configuration
/**
* global module
**/
var path = require('path'),
config;
/**
* @module config
* @type {Object}
*/
config = {};
config = {};
// ## Admin settings
/**
* @property {string} defaultLang
*/
// Default language
config.defaultLang = 'en';
/**
* @property {boolean} forceI18n
*/
// Force i18n to be on
config.forceI18n = true;
// ## Themes
// ## Themes & Plugins
/**
* @property {string} themeDir
*/
// Themes
// Themes directory, relative to `content/`
config.themeDir = 'themes';
// Current active theme
/**
* @property {string} activeTheme
*/
config.activeTheme = 'casper';
// Current active plugins
config.activePlugins = [
'FancyFirstChar'
];
// Default Navigation Items
/**
* @property {Array} nav
*/
config.nav = [{
title: 'Home',
url: '/'
}];
// ## Default Navigation Items
// Add new objects here to extend the menu output by {{nav}}
config.nav = [
{
// Title is the text shown for this nav item
title: 'Home',
// Url can be a relative path, or external URL
url: '/'
}
// new items go here
];
// ## Environment
// **Warning:** Only change the settings below here if you are sure of what you are doing!
config.env = {
testing: {
database: {
@ -80,6 +65,7 @@ config.env = {
}
},
// Default configuration
development: {
database: {
client: 'sqlite3',
@ -123,7 +109,5 @@ config.env = {
}
};
/**
* @property {Object} exports
*/
// Export config
module.exports = config;

@ -1 +1 @@
Subproject commit 16d9029acc723fc075cfcfc7fe30b75a5061e7d5
Subproject commit 0c94300d4a8d68f8e740b42f884d8fc0903394fd

View File

@ -14,10 +14,6 @@
pane: options.pane,
model: this.model
}));
this.$('input').iCheck({
checkboxClass: 'icheckbox_ghost'
});
}
});
@ -93,6 +89,10 @@
afterRender: function () {
this.$el.attr('id', this.id);
this.$el.addClass('active');
this.$('input').iCheck({
checkboxClass: 'icheckbox_ghost'
});
},
saveSuccess: function () {
Ghost.notifications.addItem({
@ -143,9 +143,8 @@
},
afterRender: function () {
this.$el.attr('id', this.id);
this.$el.addClass('active');
this.$('.js-drop-zone').upload();
Settings.Pane.prototype.afterRender.call(this);
}
});
@ -224,27 +223,22 @@
ne2password: ne2Password
},
success: function (msg) {
self.addSubview(new Ghost.Views.NotificationCollection({
model: [{
type: 'success',
message: msg.msg,
status: 'passive',
id: 'success-98'
}]
}));
Ghost.notifications.addItem({
type: 'success',
message: msg.msg,
status: 'passive',
id: 'success-98'
});
self.$('#user-password-old').val('');
self.$('#user-password-new').val('');
self.$('#user-new-password-verification').val('');
},
error: function (obj, string, status) {
self.addSubview(new Ghost.Views.NotificationCollection({
model: [{
type: 'error',
message: 'Invalid username or password',
status: 'passive'
}]
}));
Ghost.notifications.addItem({
type: 'error',
message: 'Invalid username or password',
status: 'passive'
});
}
});
},

View File

@ -1,7 +1,7 @@
// # Ghost Module
// Defines core methods required to build the frontend
// Defines core methods required to build the application
// ## Setup Prerequisites
// Module dependencies
var config = require('./../config'),
when = require('when'),
express = require('express'),
@ -12,12 +12,11 @@ var config = require('./../config'),
nodefn = require('when/node/function'),
_ = require('underscore'),
Polyglot = require('node-polyglot'),
models = require('./server/models'),
plugins = require('./server/plugins'),
requireTree = require('./server/require-tree'),
// Variables
themePath = path.resolve(__dirname + '../../content/themes'),
pluginPath = path.resolve(__dirname + '../../content/plugins'),
themeDirectories = requireTree(themePath),
@ -79,16 +78,12 @@ Ghost = function () {
// Holds the persistent notifications
instance.notifications = [];
// Holds the available plugins
instance.availablePlugins = {};
app = express();
polyglot = new Polyglot();
// functionality
// load Plugins...
// var f = new FancyFirstChar(ghost).init();
_.extend(instance, {
app: function () { return app; },
config: function () { return config; },
@ -120,6 +115,7 @@ Ghost = function () {
return instance;
};
// Initialise the application
Ghost.prototype.init = function () {
var self = this;
@ -130,6 +126,7 @@ Ghost.prototype.init = function () {
}, errors.logAndThrowError);
};
// Maintain the internal cache of the settings object
Ghost.prototype.updateSettingsCache = function (settings) {
var self = this;
@ -154,12 +151,14 @@ Ghost.prototype.updateSettingsCache = function (settings) {
// ## Template utils
// Compile a template for a handlebars helper
Ghost.prototype.compileTemplate = function (templatePath) {
return nodefn.call(fs.readFile, templatePath).then(function (templateContents) {
return hbs.handlebars.compile(templateContents.toString());
}, errors.logAndThrowError);
};
// Load a template for a handlebars helper
Ghost.prototype.loadTemplate = function (name) {
var self = this,
templateFileName = name + '.hbs',
@ -181,38 +180,12 @@ Ghost.prototype.loadTemplate = function (name) {
return deferred.promise;
};
/**
* @param {string} name
* @param {Function} fn
* @return {method} hbs.registerHelper
*/
// Register a handlebars helper for themes
Ghost.prototype.registerThemeHelper = function (name, fn) {
hbs.registerHelper(name, fn);
};
/**
* @param {string} name
* @param {Function} fn
* @return {*}
*/
Ghost.prototype.registerTheme = function (name, fn) {
return this;
};
/**
* @param {string} name
* @param {Function} fn
* @return {*}
*/
Ghost.prototype.registerPlugin = function (name, fn) {
return this;
};
/**
* @param {string} name
* @param {integer} priority
* @param {Function} fn
*/
// Register a new filter callback function
Ghost.prototype.registerFilter = function (name, priority, fn) {
// Curry the priority optional parameter to a default of 5
if (_.isFunction(priority)) {
@ -226,11 +199,7 @@ Ghost.prototype.registerFilter = function (name, priority, fn) {
this.filterCallbacks[name][priority].push(fn);
};
/**
* @param {string} name
* @param {integer} priority
* @param {Function} fn
*/
// Unregister a filter callback function
Ghost.prototype.unregisterFilter = function (name, priority, fn) {
// Curry the priority optional parameter to a default of 5
if (_.isFunction(priority)) {
@ -245,12 +214,7 @@ Ghost.prototype.unregisterFilter = function (name, priority, fn) {
}
};
/**
* @param {string} name [description]
* @param {*} args
* @param {Function} callback
* @return {method} callback
*/
// Execute filter functions in priority order
Ghost.prototype.doFilter = function (name, args, callback) {
var callbacks = this.filterCallbacks[name];
@ -279,11 +243,7 @@ Ghost.prototype.doFilter = function (name, args, callback) {
callback(args);
};
/**
* Initialise plugins. Will load from config.activePlugins by default
*
* @param {Array} pluginsToLoad
*/
// Initialise plugins. Will load from config.activePlugins by default
Ghost.prototype.initPlugins = function (pluginsToLoad) {
pluginsToLoad = pluginsToLoad || config.activePlugins;
@ -295,11 +255,7 @@ Ghost.prototype.initPlugins = function (pluginsToLoad) {
}, errors.logAndThrowError);
};
/**
* Initialise Theme
*
* @param {Object} app
*/
// Initialise Theme or admin
Ghost.prototype.initTheme = function (app) {
var self = this;
return function initTheme(req, res, next) {
@ -329,4 +285,4 @@ Ghost.prototype.initTheme = function (app) {
// TODO: Expose the defaults for other people to see/manipulate as a static value?
// Ghost.defaults = defaults;
module.exports = Ghost;
module.exports = Ghost;

View File

@ -1,9 +1,6 @@
// # Ghost Data API
// Provides access to the data model
/**
* This is intended to replace the old dataProvider files and should access & manipulate the models directly
*/
var Ghost = require('../ghost'),
_ = require('underscore'),
when = require('when'),
@ -20,73 +17,135 @@ var Ghost = require('../ghost'),
settingsObject,
settingsCollection;
// # Posts
// ## Posts
posts = {
// takes filter / pagination parameters
// returns a page of posts in a json response
// #### Browse
// **takes:** filter / pagination parameters
browse: function browse(options) {
// **returns:** a promise for a page of posts in a json object
return dataProvider.Post.findPage(options);
},
// takes an identifier (id or slug?)
// returns a single post in a json response
// #### Read
// **takes:** an identifier (id or slug?)
read: function read(args) {
// **returns:** a promise for a single post in a json object
return dataProvider.Post.findOne(args);
},
// takes a json object with all the properties which should be updated
// returns the resulting post in a json response
// #### Edit
// **takes:** a json object with all the properties which should be updated
edit: function edit(postData) {
// **returns:** a promise for the resulting post in a json object
return dataProvider.Post.edit(postData);
},
// takes a json object representing a post,
// returns the resulting post in a json response
// #### Add
// **takes:** a json object representing a post,
add: function add(postData) {
// **returns:** a promise for the resulting post in a json object
return dataProvider.Post.add(postData);
},
// takes an identifier (id or slug?)
// returns a json response with the id of the deleted post
// #### Destroy
// **takes:** an identifier (id or slug?)
destroy: function destroy(args) {
// **returns:** a promise for a json response with the id of the deleted post
return dataProvider.Post.destroy(args.id);
}
};
// # Users
// ## Users
users = {
// #### Browse
// **takes:** options object
browse: function browse(options) {
// **returns:** a promise for a collection of users in a json object
return dataProvider.User.browse(options);
},
// #### Read
// **takes:** an identifier (id or slug?)
read: function read(args) {
// **returns:** a promise for a single user in a json object
return dataProvider.User.read(args);
},
edit: function edit(postData) {
return dataProvider.User.edit(postData);
// #### Edit
// **takes:** a json object representing a user
edit: function edit(userData) {
// **returns:** a promise for the resulting user in a json object
return dataProvider.User.edit(userData);
},
add: function add(postData) {
return dataProvider.User.add(postData);
// #### Add
// **takes:** a json object representing a user
add: function add(userData) {
// **returns:** a promise for the resulting user in a json object
return dataProvider.User.add(userData);
},
check: function check(postData) {
return dataProvider.User.check(postData);
// #### Check
// Checks a password matches the given email address
// **takes:** a json object representing a user
check: function check(userData) {
// **returns:** on success, returns a promise for the resulting user in a json object
return dataProvider.User.check(userData);
},
changePassword: function changePassword(postData) {
return dataProvider.User.changePassword(postData);
// #### Change Password
// **takes:** a json object representing a user
changePassword: function changePassword(userData) {
// **returns:** on success, returns a promise for the resulting user in a json object
return dataProvider.User.changePassword(userData);
}
};
// # Notifications
// ## Notifications
notifications = {
// #### Destroy
// **takes:** an identifier (id)
destroy: function destroy(i) {
ghost.notifications = _.reject(ghost.notifications, function (element) {
return element.id === i.id;
});
// **returns:** a promise for remaining notifications as a json object
return when(ghost.notifications);
},
// #### Add
// **takes:** a notification object of the form
// ```
// msg = {
// type: 'error', // this can be 'error', 'success', 'warn' and 'info'
// message: 'This is an error', // A string. Should fit in one line.
// status: 'persistent', // or 'passive'
// id: 'auniqueid' // A unique ID
// };
// ```
add: function add(notification) {
// **returns:** a promise for all notifications as a json object
return when(ghost.notifications.push(notification));
}
};
// # Settings
// ## Settings
// ### Helpers
// Turn a settings collection into a single object/hashmap
settingsObject = function (settings) {
return (settings.toJSON ? settings.toJSON() : settings).reduce(function (res, item) {
@ -103,14 +162,23 @@ settingsCollection = function (settings) {
};
settings = {
// #### Browse
// **takes:** options object
browse: function browse(options) {
// **returns:** a promise for a settings json object
return dataProvider.Settings.browse(options).then(settingsObject, errors.logAndThrowError);
},
// #### Read
// **takes:** either a json object containing a key, or a single key string
read: function read(options) {
if (_.isString(options)) {
options = { key: options };
}
// **returns:** a promise for a single key-value pair
return dataProvider.Settings.read(options.key).then(function (setting) {
if (!setting) {
return when.reject("Unable to find setting: " + options.key);
@ -119,13 +187,19 @@ settings = {
return _.pick(setting.toJSON(), 'key', 'value');
}, errors.logAndThrowError);
},
// #### Edit
// **takes:** either a json object representing a collection of settings, or a key and value pair
edit: function edit(key, value) {
// Check for passing a collection of settings first
if (_.isObject(key)) {
key = settingsCollection(key);
return dataProvider.Settings.edit(key).then(settingsObject, errors.logAndThrowError);
}
// **returns:** a promise for a settings json object
return dataProvider.Settings.read(key).then(function (setting) {
if (!setting) {
return when.reject("Unable to find setting: " + key);
@ -142,11 +216,9 @@ settings = {
}
};
// categories: {};
// post_categories: {};
// ## Request Handlers
// requestHandler
// ### requestHandler
// decorator for api functions which are called via an HTTP request
// takes the API method and wraps it so that it gets data from the request and returns a sensible JSON response
requestHandler = function (apiMethod) {
@ -160,6 +232,8 @@ requestHandler = function (apiMethod) {
};
};
// ### cachedSettingsRequestHandler
// Special request handler for settings to access the internal cache version of the settings object
cachedSettingsRequestHandler = function (apiMethod) {
if (!ghost.settings()) {
return requestHandler(apiMethod);
@ -193,9 +267,10 @@ cachedSettingsRequestHandler = function (apiMethod) {
};
};
// Public API
module.exports.posts = posts;
module.exports.users = users;
module.exports.notifications = notifications;
module.exports.settings = settings;
module.exports.requestHandler = requestHandler;
module.exports.cachedSettingsRequestHandler = cachedSettingsRequestHandler;
module.exports.cachedSettingsRequestHandler = cachedSettingsRequestHandler;

View File

@ -8,6 +8,7 @@ var Ghost = require('../../ghost'),
nodefn = require('when/node/function'),
api = require('../api'),
moment = require('moment'),
errors = require('../errorHandling'),
ghost = new Ghost(),
dataProvider = ghost.dataProvider,
@ -20,28 +21,24 @@ adminNavbar = {
name: 'Dashboard',
navClass: 'dashboard',
key: 'admin.navbar.dashboard',
// defaultString: 'dashboard',
path: '/'
},
content: {
name: 'Content',
navClass: 'content',
key: 'admin.navbar.content',
// defaultString: 'content',
path: '/content/'
},
add: {
name: 'New Post',
navClass: 'editor',
key: 'admin.navbar.editor',
// defaultString: 'editor',
path: '/editor/'
},
settings: {
name: 'Settings',
navClass: 'settings',
key: 'admin.navbar.settings',
// defaultString: 'settings',
path: '/settings/'
}
};
@ -70,11 +67,11 @@ adminControllers = {
// adds directories recursively
fs.mkdirs(dir, function (err) {
if (err) {
console.error(err);
errors.logError(err);
} else {
fs.copy(tmp_path, target_path, function (err) {
if (err) {
console.error(err);
errors.logError(err);
} else {
res.send(src);
}
@ -153,7 +150,6 @@ adminControllers = {
});
},
'editor': function (req, res) {
console.log(res.locals);
if (req.params.id !== undefined) {
api.posts.read({id: parseInt(req.params.id, 10)})
.then(function (post) {
@ -335,4 +331,4 @@ adminControllers = {
}
};
module.exports = adminControllers;
module.exports = adminControllers;

View File

@ -105,12 +105,7 @@ User = GhostBookshelf.Model.extend({
*/
},
/**
* User check
* @param _userdata
*
* Finds the user by email, and check's the password
*/
// Finds the user by email, and checks the password
check: function (_userdata) {
return this.forge({
email_address: _userdata.email

View File

@ -11,7 +11,7 @@ function getInstalledPlugins() {
}
return ghostApi.settings.read("installedPlugins").then(function (installed) {
installed = installed || "[]";
installed.value = installed.value || "[]";
try {
installed = JSON.parse(installed.value);

109
index.js
View File

@ -1,7 +1,10 @@
// # Ghost main app file
// Contains the app configuration and all of the routing
// If no env is set, default to development
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
// Module dependencies.
// Module dependencies
var express = require('express'),
when = require('when'),
_ = require('underscore'),
@ -18,30 +21,17 @@ var express = require('express'),
helpers = require('./core/server/helpers'),
packageInfo = require('./package.json'),
// ## Custom Middleware
auth,
authAPI,
isGhostAdmin,
ghostLocals,
disableCachedResult,
// ## Variables
// Variables
loading = when.defer(),
/**
* Create new Ghost object
* @type {Ghost}
*/
ghost = new Ghost();
/**
* Authenticate a request by redirecting to login if not logged in
* We strip /ghost/ out of the redirect parameter for neatness
*
* @type {*}
*/
auth = function (req, res, next) {
// ##Custom Middleware
// ### Auth Middleware
// Authenticate a request by redirecting to login if not logged in.
// We strip /ghost/ out of the redirect parameter for neatness
function auth(req, res, next) {
if (!req.session.user) {
var path = req.path.replace(/^\/ghost\/?/gi, ''),
redirect = '';
@ -55,35 +45,34 @@ auth = function (req, res, next) {
}
next();
};
}
/**
* Authenticate a request by responding with a 401 and json error details
*
* @type {*}
*/
authAPI = function (req, res, next) {
// ## AuthApi Middleware
// Authenticate a request to the API by responding with a 401 and json error details
function authAPI(req, res, next) {
if (!req.session.user) {
// TODO: standardize error format/codes/messages
var err = { code: 42, message: 'Please login' };
res.json(401, { error: err });
return;
}
next();
};
// #### isGhostAdmin
// Middleware which uses the URL to detect whether this response should be an admin response
next();
}
// ### GhostAdmin Middleware
// Uses the URL to detect whether this response should be an admin response
// This is used to ensure the right content is served, and is not for security purposes
isGhostAdmin = function (req, res, next) {
function isGhostAdmin(req, res, next) {
res.isAdmin = /(^\/ghost$|^\/ghost\/)/.test(req.url);
next();
};
}
// ### GhostLocals Middleware
// Expose the standard locals that every external page should have available,
// separating between the frontend / theme and the admin
ghostLocals = function (req, res, next) {
function ghostLocals(req, res, next) {
// Make sure we have a locals value.
res.locals = res.locals || {};
res.locals.version = packageInfo.version;
@ -109,18 +98,20 @@ ghostLocals = function (req, res, next) {
next();
}
};
}
// ### DisableCachedResult Middleware
// Disable any caching until it can be done properly
disableCachedResult = function (req, res, next) {
function disableCachedResult(req, res, next) {
res.set({
"Cache-Control": "no-cache, must-revalidate",
"Expires": "Sat, 26 Jul 1997 05:00:00 GMT"
});
next();
};
}
// ##Configuration
ghost.app().configure(function () {
ghost.app().use(isGhostAdmin);
ghost.app().use(express.favicon(__dirname + '/content/images/favicon.ico'));
@ -138,6 +129,7 @@ ghost.app().configure(function () {
}
});
// Development only configuration
ghost.app().configure("development", function () {
ghost.app().use(express.errorHandler({ dumpExceptions: true, showStack: true }));
ghost.app().use(express.logger('dev'));
@ -152,27 +144,32 @@ when.all([ghost.init(), filters.loadCoreFilters(ghost), helpers.loadCoreHelpers(
// post init config
ghost.app().use(ghostLocals);
/**
* API routes..
* @todo auth should be public auth not user auth
*/
// ## Routing
// ### API routes
/* TODO: auth should be public auth not user auth */
// #### Posts
ghost.app().get('/api/v0.1/posts', authAPI, disableCachedResult, api.requestHandler(api.posts.browse));
ghost.app().post('/api/v0.1/posts', authAPI, disableCachedResult, api.requestHandler(api.posts.add));
ghost.app().get('/api/v0.1/posts/:id', authAPI, disableCachedResult, api.requestHandler(api.posts.read));
ghost.app().put('/api/v0.1/posts/:id', authAPI, disableCachedResult, api.requestHandler(api.posts.edit));
ghost.app().del('/api/v0.1/posts/:id', authAPI, disableCachedResult, api.requestHandler(api.posts.destroy));
// #### Settings
ghost.app().get('/api/v0.1/settings', authAPI, disableCachedResult, api.cachedSettingsRequestHandler(api.settings.browse));
ghost.app().get('/api/v0.1/settings/:key', authAPI, disableCachedResult, api.cachedSettingsRequestHandler(api.settings.read));
ghost.app().put('/api/v0.1/settings', authAPI, disableCachedResult, api.cachedSettingsRequestHandler(api.settings.edit));
// #### Users
ghost.app().get('/api/v0.1/users', authAPI, disableCachedResult, api.requestHandler(api.users.browse));
ghost.app().get('/api/v0.1/users/:id', authAPI, disableCachedResult, api.requestHandler(api.users.read));
ghost.app().put('/api/v0.1/users/:id', authAPI, disableCachedResult, api.requestHandler(api.users.edit));
// #### Notifications
ghost.app().del('/api/v0.1/notifications/:id', authAPI, disableCachedResult, api.requestHandler(api.notifications.destroy));
ghost.app().post('/api/v0.1/notifications/', authAPI, disableCachedResult, api.requestHandler(api.notifications.add));
/**
* Admin routes..
* @todo put these somewhere in admin
*/
// ### Admin routes
/* TODO: put these somewhere in admin */
ghost.app().get(/^\/logout\/?$/, admin.logout);
ghost.app().get('/ghost/login/', admin.login);
ghost.app().get('/ghost/signup/', admin.signup);
@ -187,26 +184,20 @@ when.all([ghost.init(), filters.loadCoreFilters(ghost), helpers.loadCoreHelpers(
ghost.app().get('/ghost/debug/db/export/', auth, admin.debug['export']);
ghost.app().post('/ghost/debug/db/import/', auth, admin.debug['import']);
ghost.app().get('/ghost/debug/db/reset/', auth, admin.debug.reset);
ghost.app().post('/ghost/upload', admin.uploader);
ghost.app().get(/^\/(ghost$|(ghost-admin|admin|wp-admin|dashboard|login)\/?)/, auth, function (req, res) {
res.redirect('/ghost/');
});
ghost.app().get('/ghost/', auth, admin.index);
// Notifications routes
ghost.app().del('/api/v0.1/notifications/:id', authAPI, disableCachedResult, api.requestHandler(api.notifications.destroy));
ghost.app().post('/api/v0.1/notifications/', authAPI, disableCachedResult, api.requestHandler(api.notifications.add));
ghost.app().post('/ghost/upload', admin.uploader);
/**
* Frontend routes..
* @todo dynamic routing, homepage generator, filters ETC ETC
*/
// ### Frontend routes
/* TODO: dynamic routing, homepage generator, filters ETC ETC */
ghost.app().get('/:slug', frontend.single);
ghost.app().get('/', frontend.homepage);
ghost.app().get('/page/:page/', frontend.homepage);
// ## Start Ghost App
ghost.app().listen(
ghost.config().env[process.env.NODE_ENV || 'development'].url.port,
ghost.config().env[process.env.NODE_ENV || 'development'].url.host,
@ -224,6 +215,7 @@ when.all([ghost.init(), filters.loadCoreFilters(ghost), helpers.loadCoreHelpers(
process.exit(-1);
}
// Alpha warning, reminds users this is not production-ready software (yet)
// Remove once software becomes suitably 'ready'
console.log(
"\n !!! ALPHA SOFTWARE WARNING !!!\n".red,
@ -231,6 +223,7 @@ when.all([ghost.init(), filters.loadCoreFilters(ghost), helpers.loadCoreHelpers(
"Expect to see bugs and other issues (but please report them.)\n".red
);
// Startup message
console.log("Express server listening on address:",
ghost.config().env[process.env.NODE_ENV || 'development'].url.host + ':'
+ ghost.config().env[process.env.NODE_ENV || 'development'].url.port);
@ -239,4 +232,4 @@ when.all([ghost.init(), filters.loadCoreFilters(ghost), helpers.loadCoreHelpers(
loading.resolve();
}
);
}, errors.logAndThrowError);
}, errors.logAndThrowError);