UNPKG

13.5 kBJavaScriptView Raw
1/**
2 * We.js main file, load we.js features
3 *
4 */
5
6// Module dependencies.
7var async = require('async');
8var express = require('express');
9var http = require('http');
10var _ = require('lodash');
11var path = require('path');
12var wePassport = require('./auth/passport');
13var localization = require('./localization');
14var exec = require('child_process').exec;
15var staticConfig = require('./staticConfig');
16var projectPath = process.cwd();
17
18/**
19 * We.js object
20 *
21 * @type {Object}
22 */
23var we = {
24 projectPath: projectPath,
25 // enviroment config prod | dev | test
26 env: require('./env.js'),
27 // winston logger
28 log: require('./log')(projectPath),
29 // we.utils.async, we.utils._ ... see the ./utils file
30 utils: require('./utils'),
31 // hooks and events
32 hooks: require('./hooks'),
33 events: require('./events'),
34 // database logic and models is avaible in we.db.models
35 db: require('./database'),
36 // Access Control List
37 acl: require('./acl'),
38 // we.js prototypes
39 class: require('./class'),
40 // start configs with static configs
41 config: staticConfig(projectPath),
42 // we.js sanitizer
43 sanitizer: require('./sanitizer'),
44 // helper functions to load we.js resources
45 loaders: require('./loaders'),
46 // view logic
47 view: require('./view'),
48 // The we.js router
49 router: require('./router'),
50 email: require('./email'),
51 bootstrapStarted: false,
52 childProcesses:[],
53 // plugin manager and plugins vars
54 pluginManager: require('./pluginManager'),
55 plugins: {},
56 pluginPaths: [],
57 pluginNames: [],
58 // controllers
59 controllers: {},
60 // load we.js responses
61 responses: require('./responses'),
62 // save we-core path to plugin.js for update e install process
63 weCorePluginfile: path.resolve(__dirname, '../') + '/plugin.js',
64 // flag to check if needs restart
65 needsRestart: false
66};
67//Overide default toString and inspect to custom infos in we.js object
68we.inspect = function inspect() {
69 return '\nWe.js ;)\n';
70};
71we.toString = we.inspect;
72// - init database
73we.db.defaultConnection = we.db.connect(we.env);
74//set for more compatbility with sequelize docs
75we.db.sequelize = we.db.defaultConnection;
76// url feature like url alias
77we.url = require('./url');
78// client side config generator
79we.getAppBootstrapConfig = require('./staticConfig/getAppBootstrapConfig.js');
80we.antiSpam = require('./antiSpam');
81// load we.js auth logic
82we.auth = require('./auth');
83
84we.view.initialize(we);
85// load express and base middlewares
86var weExpress = require('./express');
87// save a reference to we.js object in plugin prototype
88we.class.Plugin.prototype.we = we;
89// helper function to get express Router
90we.getRouter = function getRouter() { return express.Router(); }
91
92/**
93 * Bootstrap and initialize the app
94 *
95 * @param {Object} configOnRun optional
96 * @param {Function} cb callback to run after load we.js
97 */
98we.bootstrap = function bootstrap(configOnRun, cb) {
99 // only bootstrap we.js one time
100 if (we.bootstrapStarted) throw new Error('We.js already did bootstrap');
101 we.bootstrapStarted = true;
102 // configsOnRun object is optional
103 if (!cb) {
104 cb = configOnRun;
105 configOnRun = null;
106 }
107 // configs on run extends default and file configs
108 if (configOnRun) _.merge(we.config, configOnRun);
109 // run all bootstrap steps in series
110 async.series([
111 function loadCoreFeatures(next) {
112 we.log.verbose('loadCoreFeatures step');
113
114 we.db.loadCoreModels(function(err) {
115 if(err) return next(err);
116
117 we.pluginManager.loadPluginsSettingsFromDB(we, function (err){
118 if (err) return next(err);
119 // preload all plugins
120 we.pluginManager.loadPlugins(we, function (err, plugins) {
121 if (err) return next(err);
122 we.plugins = plugins;
123 next();
124 });
125 });
126 });
127 },
128
129 function loadPluginFeatures(next) {
130 we.log.verbose('loadPluginFeatures step');
131
132 we.pluginNames = we.pluginManager.pluginNames;
133 // load plugin static configs, merge with old we.config and
134 // override the defalt config
135 we.config = staticConfig.loadPluginConfigs();
136
137 async.eachSeries(we.pluginNames, function (pluginName, next) {
138 we.plugins[pluginName].loadFeatures(we, next);
139 }, function (err) {
140 if (err) return next(err);
141 // load plugin widgets
142 for (var widgetName in we.view.configuration.widgets) {
143 we.view.widgets[widgetName] =
144 require(we.view.configuration.widgets[widgetName])(we.projectPath, we.class.Widget);
145 }
146
147 we.events.emit('we:after:load:plugins', we);
148 next();
149 })
150 },
151
152 // TODO move checkRequirements to we.js CLI action
153 function checkRequirements(next) {
154 we.log.verbose('checkRequirements step');
155 we.hooks.trigger('we:check:requirements', we, function (err) {
156 if (err) return next(err);
157 exec('gm version', function (error) {
158 if (error) {
159 return next('Requirement GraphicsMagick not found or not instaled, see: https://github.com/aheckmann/gm');
160 }
161 return next();
162 });
163 });
164 },
165
166 function loadModels(next) {
167 we.log.verbose('loadModels step');
168 we.loaders.loadModels(we, function(err, models) {
169 if (err) return next(err);
170 _.merge(we.db.modelsConfigs, models);
171 next();
172 })
173 },
174
175 function instantiateModels(next) {
176 we.log.verbose('instantiateModels step');
177 we.hooks.trigger('we:models:before:instance', we, function(err) {
178 if (err) return next(err);
179
180 for ( var modelName in we.db.modelsConfigs) {
181 we.db.models[modelName] = we.db.define(
182 modelName,
183 we.db.modelsConfigs[modelName].definition,
184 we.db.modelsConfigs[modelName].options
185 );
186 }
187
188 we.db.setModelAllJoins();
189
190 we.hooks.trigger('we:models:set:joins', we, function afterSetJoins(err) {
191 if (err) return next(err);
192 next();
193 });
194 });
195 },
196
197 function loadControllers(next) {
198 we.log.verbose('loadControllers step');
199 we.loaders.loadControllers(we, function(err, controllers) {
200 if (err) return next(err);
201 _.merge(we.controllers, controllers);
202
203 we.events.emit('we:after:load:controllers', we);
204 next();
205 })
206 },
207
208 function installAndRegisterPluginsIfNeed(next) {
209 we.log.verbose('installAndRegisterPluginsIfNeed step');
210 // dont have plugins to install
211 if (!we.pluginManager.pluginsToInstall) return next();
212 // sync all model before start the install scripts
213 we.db.defaultConnection.sync().then(function() {
214 // get plugins to install names
215 var names = Object.keys(we.pluginManager.pluginsToInstall);
216 async.eachSeries(names, function (name, nextPlugin) {
217 // run install scripts
218 we.pluginManager.installPlugin(name, function (err){
219 if (err) return nextPlugin(err);
220 // register it
221 we.pluginManager.registerPlugin(name, nextPlugin);
222 });
223 }, function (err) {
224 if (err) return next(err);
225 next();
226 });
227 }).catch(next);
228 },
229
230 function initACL(next) {
231 we.log.verbose('initACL step');
232 we.acl.init(we, next);
233 },
234
235 function initExpressAndPassport(next) {
236 we.log.verbose('initExpressPassport step');
237 // load express
238 we.express = weExpress(we);
239 we.events.emit('we:after:load:express', we);
240 // - Passports configs
241 wePassport.configureAndSetStrategies(we);
242 we.events.emit('we:after:load:passport', we);
243 // admin env middleware
244 we.express.get('/admin*', function adminPage(req ,res, next) {
245 res.locals.isAdmin = true;
246 res.locals.theme = we.view.adminTheme;
247 res.locals.template = 'home/index';
248 return next();
249 });
250 next();
251 },
252
253 function initI18n(next) {
254 we.log.verbose('initI18n step');
255 localization(we);
256 we.events.emit('we:after:init:i18n', we);
257 next();
258 },
259
260 function createDefaultFolders(next) {
261 we.log.verbose('createDefaultFolders step');
262 we.hooks.trigger('we:create:default:folders', we, function() {
263 next();
264 });
265 },
266
267 function loadEmailTemplates(next) {
268 we.log.verbose('loadEmailTemplates step');
269 we.email.init(we);
270
271 we.email.loadEmailTemplates(we, function (err, templates) {
272 if (err) return next(err);
273 we.email.templates = templates;
274 next();
275 });
276 },
277
278 function registerAllViewTemplates(next) {
279 we.log.verbose('registerAllViewTemplates step');
280 we.view.registerAll();
281 next();
282 },
283
284 function mergeRoutes(next) {
285 we.log.verbose('mergeRoutes step');
286 we.routes = {};
287 // merge plugin routes
288 for ( var plugin in we.plugins) {
289 _.merge(we.routes, we.plugins[plugin].routes);
290 }
291 // merge project routes
292 _.merge(we.routes, we.config.routes);
293 next();
294 },
295 function bindRoutes(next) {
296 we.log.verbose('bindRoutes step');
297 we.hooks.trigger('we:before:routes:bind', we, function beforeRouteBind() {
298 // bind dinamic url
299 we.express.get('*', we.url.middleware);
300
301 for (var route in we.routes) {
302 we.router.bindRoute(we, route, we.routes[route] );
303 }
304
305 we.hooks.trigger('we:after:routes:bind', we, function afterRouteBind() {
306
307 // bind after router handler for run responseMethod
308 we.express.use(function(req, res, done) {
309 if (res.responseMethod) return res[res.responseMethod]();
310 done();
311 });
312
313 next();
314 });
315 });
316 },
317 function bindResources(next) {
318 for (var resource in we.router.resources) {
319 we.router.bindResource(we.router.resources[resource]);
320 }
321
322 next();
323 }
324 ], function bootstrapDone(err) {
325 if (err) {
326 console.trace();
327 console.error('Error on we.js bootstrap: ', err);
328 return cb(err);
329 }
330
331 we.events.emit('we:bootstrap:done', we);
332
333 we.log.debug('We.js bootstrap done');
334 return cb(null, we);
335 });
336}
337
338/**
339 * Start we.js server (express)
340 * use after we.bootstrap
341 *
342 * @param {Function} cb callback how returns with cb(err);
343 */
344we.startServer = function startExpressServer(cb) {
345 we.hooks.trigger('we:server:before:start',we, function (err) {
346 if (err) return cb(err);
347 /**
348 * Get port from environment and store in Express.
349 */
350 var port = normalizePort(we.config.port);
351 we.express.set('port', port);
352
353 /**
354 * Create HTTP server.
355 */
356 var server = http.createServer(we.express);
357
358 we.events.emit('we:server:after:create', { we: we, server: server});
359
360 /**
361 * Listen on provided port, on all network interfaces.
362 */
363
364 // catch 404 and forward to error handler
365 we.express.use(function routeNotFound(req, res) {
366 we.log.debug('Route not found:', req.path);
367 // var err = new Error('Not Found');
368 // err.status = 404;
369 return res.notFound();
370 });
371
372 server.listen(port);
373 server.on('error', onError);
374 server.on('listening', onListening);
375
376 /**
377 * Normalize a port into a number, string, or false.
378 */
379 function normalizePort(val) {
380 var port = parseInt(val, 10);
381
382 if (isNaN(port)) {
383 // named pipe
384 return val;
385 }
386
387 if (port >= 0) {
388 // port number
389 return port;
390 }
391
392 return false;
393 }
394
395 /**
396 * Event listener for HTTP server "error" event.
397 */
398 function onError(error) {
399 if (error.syscall !== 'listen') {
400 throw error;
401 }
402
403 var bind = typeof port === 'string'
404 ? 'Pipe ' + port
405 : 'Port ' + port;
406
407 // handle specific listen errors with friendly messages
408 switch (error.code) {
409 case 'EACCES':
410 console.error(bind + ' requires elevated privileges');
411 process.exit(1);
412 break;
413 case 'EADDRINUSE':
414 console.error(bind + ' is already in use');
415 process.exit(1);
416 break;
417 default:
418 throw error;
419 }
420 }
421 /**
422 * Event listener for HTTP server "listening" event.
423 */
424 function onListening() {
425 var addr = server.address();
426 var bind = typeof addr === 'string'
427 ? 'pipe ' + addr
428 : 'port ' + addr.port;
429 we.log.info('Listening on ' + bind);
430 }
431 // save the current http server
432 we.http = server;
433 // express error handlers
434 // will print stacktrace
435 we.express.use(function onExpressError(err, req, res, next) {
436 we.log.error('Error on:', req.path, err);
437 res.serverError();
438 });
439
440 we.hooks.trigger('we:server:after:start',we, function (err) {
441 cb(err, we);
442 });
443 });
444}
445
446/**
447 * Bootstrap and Start we.js server
448 *
449 * @param {Object} cfgs configs (optional)
450 * @param {Function} cb callback
451 */
452we.go = function go(cfgs, cb) {
453 if (!cb) {
454 cb = cfgs;
455 cfgs = {};
456 }
457
458 we.bootstrap(cfgs, function(err, we) {
459 we.startServer(cb);
460 });
461}
462
463/**
464 * Turn off process function
465 *
466 * @param {Function} cb callback
467 */
468we.exit = function exit(cb) {
469
470 we.db.defaultConnection.close();
471
472 cb();
473}
474
475/**
476 * Run all plugin and project cron tasks
477 *
478 * @param {Function} cb callback
479 */
480we.runCron = function runCron(cb) {
481 we.cron = require('./cron');
482 we.cron.loadAndRunAllTasks(we, cb);
483}
484
485module.exports = we;