1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | "use strict";
|
22 |
|
23 | const path = require('path');
|
24 |
|
25 | const debug = require('debug')('volebo:express:server');
|
26 | const express = require('express');
|
27 |
|
28 |
|
29 | const logger = require('morgan');
|
30 |
|
31 | const bodyParser = require('body-parser');
|
32 | const handlebars = require('express-handlebars');
|
33 |
|
34 | const session = require('express-session');
|
35 | const langGen = require('express-mw-lang');
|
36 | const _ = require('lodash');
|
37 |
|
38 | const moment = require('moment');
|
39 | const passport = require('passport');
|
40 |
|
41 | const helmet = require('helmet')
|
42 |
|
43 |
|
44 |
|
45 | if (global.Intl) {
|
46 | const IntlPolyfill = require('intl');
|
47 | Intl.NumberFormat = IntlPolyfill.NumberFormat;
|
48 | Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
|
49 | } else {
|
50 | global.Intl = require('intl');
|
51 | }
|
52 |
|
53 |
|
54 |
|
55 | const handlebarsIntl = require('handlebars-intl');
|
56 |
|
57 | const [nodeEnv, isProduction] = require('./getnodeenv')();
|
58 | debug('NODE_ENV', nodeEnv);
|
59 |
|
60 | const Config = require('./config');
|
61 |
|
62 | debug('initializing');
|
63 |
|
64 |
|
65 | let main = function main(serverConfig) {
|
66 | let app = express();
|
67 |
|
68 |
|
69 | app.use(helmet());
|
70 | app.set('env', nodeEnv);
|
71 |
|
72 | |
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 | app.config = new Config(serverConfig);
|
81 |
|
82 |
|
83 |
|
84 | app.use(logger('common'));
|
85 |
|
86 | app.use(bodyParser.json());
|
87 | app.use(bodyParser.urlencoded({ extended: false }));
|
88 |
|
89 | app.set('trust proxy', app.config.proxy.list);
|
90 |
|
91 | |
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | if (_.get(app.config, 'debug.staticPath') && !isProduction) {
|
98 |
|
99 | let staticPath = app.config.debug.staticPath;
|
100 |
|
101 | debug('Use static path', staticPath);
|
102 | app.use(express.static(staticPath));
|
103 | }
|
104 |
|
105 |
|
106 | |
107 |
|
108 |
|
109 |
|
110 |
|
111 | if (app.config.debug && !isProduction) {
|
112 | app.set('json spaces', 4);
|
113 | }
|
114 |
|
115 | |
116 |
|
117 |
|
118 |
|
119 |
|
120 | app.use((req, _unused_res, next) => {
|
121 | req.forwardedSecure = _.lowerCase(req.headers["x-forwarded-proto"]) === "https";
|
122 | next();
|
123 | });
|
124 |
|
125 | |
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 | if (app.config.session && app.config.session.enabled) {
|
132 | let session_config = {
|
133 | name: app.config.session.name || 'sessionId',
|
134 | secret: app.config.session.secret,
|
135 | resave: false,
|
136 | saveUninitialized: false,
|
137 |
|
138 |
|
139 | cookie: {
|
140 |
|
141 | maxAge: 1000*60*30,
|
142 | httpOnly: true,
|
143 |
|
144 | secure : app.config.session.secure,
|
145 | },
|
146 |
|
147 | };
|
148 |
|
149 | if (app.config.session.domain.length > 0) {
|
150 | session_config.cookie.domain = app.config.session.domain.join(',');
|
151 | }
|
152 |
|
153 | app.use(session(session_config));
|
154 | }
|
155 |
|
156 | |
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 | if (app.config.auth.enabled) {
|
163 | app.use(passport.initialize());
|
164 | if (app.config.auth.session){
|
165 | app.use(passport.session());
|
166 | }
|
167 |
|
168 | passport.serializeUser(function(user, done) {
|
169 | debug('serializing', user);
|
170 | done(null, user);
|
171 | });
|
172 |
|
173 | passport.deserializeUser(function(obj, done) {
|
174 | debug('deserializing', obj);
|
175 | done(null, obj);
|
176 | });
|
177 | }
|
178 |
|
179 | |
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 | let langmw = langGen({
|
186 | defaultLanguage: 'en',
|
187 | availableLanguages: ['en', 'ru', 'zh'],
|
188 | onLangCodeReady: function(lang_code, _unused_req, res) {
|
189 |
|
190 | moment.locale(lang_code);
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 | if (!res._renderOriginal) {
|
199 | res._renderOriginal = res.render;
|
200 | }
|
201 | res.render = function overloadedRender(){
|
202 |
|
203 | let nargs = Array.prototype.slice.call(arguments);
|
204 | let opt = nargs[1];
|
205 |
|
206 | if (_.isNil(opt)) {
|
207 | opt = {};
|
208 | }
|
209 |
|
210 | if (res.helpers) {
|
211 | debug('Going to append per-request HBS helpers');
|
212 |
|
213 |
|
214 | if(opt.helpers) {
|
215 | _.assign(opt.helpers, res.helpers);
|
216 | } else {
|
217 | _.set(opt, 'helpers', res.helpers);
|
218 | }
|
219 | }
|
220 |
|
221 |
|
222 | _.set(opt, 'data.intl.locales', lang_code);
|
223 |
|
224 | nargs[1] = opt;
|
225 | return res._renderOriginal.apply(this, nargs);
|
226 | }
|
227 | }
|
228 | });
|
229 | app.lang = langmw;
|
230 | langmw.esu(app);
|
231 |
|
232 | |
233 |
|
234 |
|
235 |
|
236 |
|
237 | let hbs = handlebars.create({
|
238 | layoutsDir: path.join(__dirname, '..', 'views', 'layouts'),
|
239 | partialsDir: path.join(__dirname, '..', 'views', 'partials'),
|
240 | defaultLayout: 'default',
|
241 | helpers: require('./helpers').helpers,
|
242 | extname: '.hbs'
|
243 | });
|
244 | app.hbs = hbs;
|
245 |
|
246 | handlebarsIntl.registerWith(hbs.handlebars);
|
247 |
|
248 | app.engine('hbs', hbs.engine);
|
249 | app.set('view engine', 'hbs');
|
250 |
|
251 | |
252 |
|
253 |
|
254 |
|
255 |
|
256 | if (app.config.model.enabled) {
|
257 |
|
258 |
|
259 | const Model = require('volebo-data');
|
260 | app.model = new Model(app.config.model);
|
261 | }
|
262 |
|
263 | app._onStarting = function() {
|
264 | |
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 | app.use(function(_unused_req, _unused_res, next) {
|
271 |
|
272 | let err = new Error('Not Found');
|
273 | err.status = 404;
|
274 |
|
275 | next(err);
|
276 | });
|
277 |
|
278 | |
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 | let error_view_path = path.join(__dirname, '..', 'views', 'error.hbs');
|
286 |
|
287 | if (app.config.debug && app.config.debug.renderStack && !isProduction) {
|
288 |
|
289 |
|
290 |
|
291 | app.use(function global_error_dev(err, _unused_req, res, next) {
|
292 | res.status(err.status || 500);
|
293 | return res.render(error_view_path, {
|
294 | message: err.message,
|
295 | error: err,
|
296 | status: err.status
|
297 | });
|
298 | });
|
299 | } else {
|
300 |
|
301 |
|
302 |
|
303 | app.use(function global_error(err, _unused_req, res, next) {
|
304 | res.status(err.status || 500);
|
305 | return res.render(error_view_path, {
|
306 | message: err.message,
|
307 | error: {},
|
308 | status: err.status
|
309 | });
|
310 | });
|
311 | }
|
312 | }
|
313 |
|
314 | return app;
|
315 | }
|
316 |
|
317 | exports = module.exports = main;
|