-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
185 lines (167 loc) · 4.78 KB
/
index.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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
require('dotenv').config()
const config = require('config')
const jwtAuth = require('tc-core-library-js').middleware.jwtAuthenticator
const express = require('express')
const _ = require('lodash')
const cors = require('cors')
const bodyParser = require('body-parser')
const schedule = require('node-schedule')
const helper = require('./src/common/helper')
const logger = require('./src/common/logger')
const errors = require('./src/common/errors')
const models = require('./src/models')
const { initServer, retryEmail } = require('./src/init')
config.TEMPLATE_MAP = JSON.parse(config.TEMPLATE_MAP)
// key is topic name, e.g. 'notifications.connect.project.created';
// value is handler for the topic to find user ids that should receive notifications for a message,
// it is defined as: function(topic, message, callback),
// the topic is topic name,
// the message is JSON event message,
// the callback is function(error, userIds), where userIds is an array of user ids to receive notifications
const handlers = {}
/**
* Set configuration, the default config will be overridden by the given config,
* unspecified config parameters will not be changed, i.e. still using default values.
*
* Note that setConfig should be called before the initDatabase and start functions.
*
* @param {Object} cfg the configuration to set
*/
function setConfig (cfg) {
if (!cfg) {
throw new errors.ValidationError('Missing configuration.')
}
_.extend(config, cfg)
}
/**
* Remove topic handler for topic.
* @param {String} topic the topic name
*/
function removeTopicHandler (topic) {
if (!topic) {
throw new errors.ValidationError('Missing topic.')
}
delete handlers[topic]
}
/**
* Get all topic handlers.
* @returns {Object} all topic handlers, key is topic name, value is handler
*/
function getAllHandlers () {
return handlers
}
/**
* Add topic handler for topic, override existing one if any.
* @param {String} topic the topic name
* @param {Function} handler the handler
*/
function addTopicHandler (topic, handler) {
if (!topic) {
throw new errors.ValidationError('Missing topic.')
}
if (!handler) {
throw new errors.ValidationError('Missing handler.')
}
handlers[topic] = handler
}
const app = express()
app.set('port', config.PORT)
app.use(cors())
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
const apiRouter = express.Router()
// load all routes
_.each(require('./src/routes'), (verbs, url) => {
_.each(verbs, (def, verb) => {
const actions = []
const method = require('./src/controllers/' + def.controller)[def.method]
if (!method) {
throw new Error(def.method + ' is undefined')
}
actions.push((req, res, next) => {
req.signature = `${def.controller}#${def.method}`
next()
})
if (url !== '/health') {
actions.push(jwtAuth())
actions.push((req, res, next) => {
if (!req.authUser) {
return next(new errors.UnauthorizedError('Authorization failed.'))
}
req.user = req.authUser
return next()
})
}
actions.push(method)
apiRouter[verb](url, helper.autoWrapExpress(actions))
})
})
app.use(config.API_CONTEXT_PATH, apiRouter)
app.use((req, res) => {
res.status(404).json({ error: 'route not found' })
})
app.use((err, req, res) => { // eslint-disable-line
logger.logFullError(err, req.signature)
let status = err.httpStatus || 500
if (err.isJoi) {
status = 400
}
// from express-jwt
if (err.name === 'UnauthorizedError') {
status = 401
}
res.status(status)
if (err.isJoi) {
res.json({
error: 'Validation failed',
details: err.details
})
} else {
res.json({
error: err.message
})
}
})
function start () {
initServer(handlers).then(() => {
if (_.isEmpty(handlers)) {
throw new errors.ValidationError('Missing handler(s).')
}
schedule.scheduleJob(config.EMAIL_RETRY_SCHEDULE, async function () {
try {
logger.info("Retrying failed emails")
await retryEmail(handlers)
} catch (err) {
console.log('Error in retrying email', err)
logger.error(err)
}
})
app.listen(app.get('port'), () => {
logger.info(`Express server listening on port ${app.get('port')}`)
})
}).catch((err) => {
logger.error(err)
process.exit(1)
})
}
/**
* Initialize database. All tables are cleared and re-created.
* @returns {Promise} promise to init db
*/
async function initDatabase () {
// load models only after config is set
logger.info('Initializing database...')
const span = await logger.startSpan('initDatabase')
await models.init(true)
await logger.endSpan(span)
}
// Exports
module.exports = {
setConfig,
addTopicHandler,
removeTopicHandler,
getAllHandlers,
start,
initDatabase
}
logger.buildService(module.exports)