forked from contentful/the-example-app.nodejs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.js
163 lines (135 loc) · 5.24 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
const path = require('path')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const express = require('express')
const logger = require('morgan')
const querystring = require('querystring')
const helmet = require('helmet')
// Load environment variables using dotenv
require('dotenv').config({ path: 'variables.env' })
const helpers = require('./helpers')
const { translate, initializeTranslations, setFallbackLocale } = require('./i18n/i18n')
const breadcrumb = require('./lib/breadcrumb')
const { updateCookie } = require('./lib/cookies')
const settings = require('./lib/settings')
const routes = require('./routes/index')
const { getSpace, getLocales } = require('./services/contentful')
const { catchErrors } = require('./handlers/errorHandlers')
const SETTINGS_NAME = 'theExampleAppSettings'
const app = express()
// View engine setup
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'pug')
app.use(logger('dev'))
app.use(helmet())
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
app.use(cookieParser())
app.use(express.static(path.join(__dirname, 'public')))
// Force all requests on production to be served over https
app.use(function (req, res, next) {
if (req.headers['x-forwarded-proto'] !== 'https' && process.env.NODE_ENV === 'production') {
const secureUrl = 'https://' + req.hostname + req.originalUrl
res.redirect(302, secureUrl)
}
next()
})
// Set our application settings based on environment variables or query parameters
app.use(settings)
// Make data available for our views to consume
app.use(catchErrors(async function (request, response, next) {
response.locals.baseUrl = `${request.protocol}://${request.headers.host}`
// Get enabled locales from Contentful
response.locals.locales = [{code: 'en-US', name: 'U.S. English'}]
response.locals.currentLocale = response.locals.locales[0]
// Inject custom helpers
response.locals.helpers = helpers
// Make query string available in templates to render links properly
const cleanQuery = helpers.cleanupQueryParameters(request.query)
const qs = querystring.stringify(cleanQuery)
response.locals.queryString = qs ? `?${qs}` : ''
response.locals.queryStringSettings = response.locals.queryString
response.locals.query = request.query
response.locals.currentPath = request.path
// Initialize translations and include them on templates
initializeTranslations()
response.locals.translate = translate
// Set active api based on query parameter
const apis = [
{
id: 'cda',
label: translate('contentDeliveryApiLabel', response.locals.currentLocale.code)
},
{
id: 'cpa',
label: translate('contentPreviewApiLabel', response.locals.currentLocale.code)
}
]
// Set currently used api
response.locals.currentApi = apis
.find((api) => api.id === (request.query.api || 'cda'))
// Fall back to delivery api if an invalid API is passed
if (!response.locals.currentApi) {
response.locals.currentApi = apis.find((api) => api.id === 'cda')
}
next()
}))
// Test space connection and attach space related data for views if possible
app.use(catchErrors(async function (request, response, next) {
// Catch misconfigured space credentials and display settings page
try {
const space = await getSpace()
const locales = await getLocales()
// Update credentials in cookie when space connection is successful
updateCookie(response, SETTINGS_NAME, response.locals.settings)
// Get available locales from space
response.locals.locales = locales
const defaultLocale = response.locals.locales
.find((locale) => locale.default)
if (request.query.locale) {
response.locals.currentLocale = space.locales
.find((locale) => locale.code === request.query.locale)
}
if (!response.locals.currentLocale) {
response.locals.currentLocale = defaultLocale
}
if (response.locals.currentLocale.fallbackCode) {
setFallbackLocale(response.locals.currentLocale.fallbackCode)
}
// Creates a query string which adds the current credentials to links
// To other implementations of this app in the about modal
helpers.updateSettingsQuery(request, response, response.locals.settings)
} catch (error) {
if ([401, 404].includes(error.response.status)) {
// If we can't connect to the space, force the settings page to be shown.
response.locals.forceSettingsRoute = true
} else {
throw error
}
}
next()
}))
app.use(breadcrumb())
// Initialize the route handling
// Check ./routes/index.js to get a list of all implemented routes
app.use('/', routes)
// Catch 404 and forward to error handler
app.use(function (request, response, next) {
const err = new Error(translate('errorMessage404Route', response.locals.currentLocale.code))
err.status = 404
next(err)
})
// Error handler
app.use(function (err, request, response, next) {
// Set locals, only providing error in development
response.locals.error = err
response.locals.error.status = err.status || 500
if (request.app.get('env') !== 'development') {
delete err.stack
}
response.locals.title = 'Error'
// Render the error page
response.status(err.status || 500)
response.render('error')
})
module.exports = app