UNPKG

verdandi

Version:

Verðandi; API backend for Sjekk UT mobile application

281 lines (231 loc) 7.73 kB
'use strict'; /* istanbul ignore if */ if (process.env.NODE_ENV === 'production') { const secrets = require('./lib/secrets'); // eslint-disable-line global-require process.env.NEW_RELIC_LICENSE_KEY = secrets.NEW_RELIC_LICENSE_KEY; /* eslint-disable no-console */ console.log('Starting newrelic application monitoring'); /* eslint-enable */ require('newrelic'); // eslint-disable-line global-require } const raven = require('raven'); const sentry = require('./lib/sentry'); const User = require('./models/User'); const Checkin = require('./models/Checkin'); const express = require('express'); const compression = require('compression'); const responseTime = require('response-time'); const bodyParser = require('body-parser'); const HttpError = require('@starefossen/http-error'); const { middleware: requireAuth } = require('./lib/auth'); const { middleware: getNtbObject } = require('./lib/ntb'); const app = module.exports = express(); const router = new express.Router(); app.set('json spaces', 2); app.set('x-powered-by', false); app.set('etag', 'strong'); router.use(compression()); router.use(responseTime()); router.use(bodyParser.json()); // Full URL router.use(require('./lib/express-full-url')); // Cors Headers router.use(require('@starefossen/express-cors').middleware); // Health Check const healthCheck = require('@starefossen/express-health'); router.get('/CloudHealthCheck', healthCheck({ name: 'RethinkDB', check: cb => { cb(null, { status: 'Ok' }); }, })); router.get('/', (req, res) => { res.json({ checkin_new: { url: `${req.fullUrl}/steder/{sted}/besok`, rules: { max_distance: parseInt(process.env.CHECKIN_MAX_DISTANCE, 10), quarantine: parseInt(process.env.CHECKIN_TIMEOUT, 10), }, }, checkin_get: { url: `${req.fullUrl}/steder/{sted}/besok/{oid}` }, checkin_log: { url: `${req.fullUrl}/steder/{sted}/logg` }, checkin_stats: { url: `${req.fullUrl}/steder/{sted}/stats` }, profile_view: { url: `${req.fullUrl}/brukere/{bruker}` }, list_join: { url: `${req.fullUrl}/lister/{liste}/blimed` }, list_leave: { url: `${req.fullUrl}/lister/{liste}/meldav` }, list_log: { url: `${req.fullUrl}/lister/{liste}/logg` }, }); }); const notImplementedYet = (req, res) => { res.status(418); res.json({ message: 'Not implemented yet, come back later' }); }; router.get('/steder/:sted/stats', (req, res, next) => { Checkin.find() .where('ntb_steder_id').equals(req.params.sted) .count() .then(count => res.json({ data: { count } })) .catch(error => next(new HttpError('Database failure', 500, error))); }); router.get('/steder/:sted/logg', (req, res, next) => { Checkin.find() .where('ntb_steder_id').equals(req.params.sted) .limit(50) .sort({ timestamp: -1 }) .then(checkins => checkins.map(c => c.anonymize(req.headers['x-user-id']))) .then(data => res.json({ data })) .catch(error => next(new HttpError('Database failure', 500, error))); }); router.post('/steder/:sted/besok', requireAuth, getNtbObject, (req, res, next) => { const promise = Checkin.create({ location: { type: 'Point', coordinates: [req.body.lon, req.body.lat], }, public: !!req.body.public, ntb_steder_id: req.params.sted, dnt_user_id: req.user.id, timestamp: req.body.timestamp, }); // Save new checkin to user profile promise.then(checkin => { req.user.innsjekkinger.push(checkin); req.user.save(); }); // Return new checkin object promise.then(checkin => { res.set('Location', `${req.fullUrl}${req.url}/${checkin._id}`); res.json({ message: 'Ok', data: checkin.toJSON({ getters: false, versionKey: false, }), }); }); promise.catch(error => { if (error.name === 'ValidationError') { res.status(400).json({ message: 'Checkin validation failed', code: 400, errors: error.errors, }); } else { next(new HttpError('Database connection failed', 500, error)); } }); }); router.param('checkin', (req, res, next) => { if (/^[a-f0-9]{24}$/.test(req.params.checkin) === false) { res.status(400).json({ message: 'Invalid ObjectId' }); } else { next(); } }); router.get('/steder/:sted/besok/:checkin', (req, res, next) => { // @TODO redirect to correct cononical URL for checkin ID // @TODO validate visibility const promise = Checkin.findOne({ _id: req.params.checkin }); promise.then(data => { if (!data) { next(new HttpError('Checkin not found', 404)); } else { res.json({ data }); } }); promise.catch(error => next(new HttpError('Database failure', 500, error))); }); router.get('/lister/:liste/stats', notImplementedYet); router.get('/lister/:liste/logg', (req, res) => { Checkin.getCheckinsForList(req.params.liste) .then(checkins => checkins.map(c => c.anonymize(req.headers['x-user-id']))) .then(checkins => res.json({ data: checkins })); }); router.post('/lister/:liste/blimed', requireAuth, (req, res) => { const user = req.user; if (user.lister.indexOf(req.params.liste) === -1) { user.lister.push(req.params.liste); } user.save(); res.json({ message: 'Ok', data: user, }); }); router.post('/lister/:liste/meldav', requireAuth, (req, res) => { const user = req.user; if (user.lister.indexOf(req.params.liste) > -1) { user.lister.splice(user.lister.indexOf(req.params.liste), 1); } user.save(); res.json({ message: 'Ok', data: user, }); }); router.param('bruker', (req, res, next, bruker) => { const brukerId = parseInt(bruker, 10); // Assert valid user ID if (isNaN(brukerId)) { return next(new HttpError(`Invalid user id "${bruker}"`, 400)); } // Get user profile from database return User .findOne({ _id: brukerId }) // Expand user checkins .populate('innsjekkinger') // Check if user exists .then(user => { if (!user) { throw new HttpError(`User "${req.params.bruker}" Not Found`, 404); } return user; }) // Conditionally hide private user checkins // @TODO authenticate X-User-ID header before use .then(user => user.filterCheckins(parseInt(req.headers['x-user-id'], 10))) // Attach user instance to request object .then(user => { req.user = user; }) .then(() => next()) .catch(error => { if (error instanceof HttpError) { next(error); } else { next(new HttpError('Database failure', 500, error)); } }); }); router.get('/brukere/:bruker', (req, res) => { res.json({ data: req.user }); }); router.get('/brukere/:bruker/stats', notImplementedYet); router.get('/brukere/:bruker/logg', notImplementedYet); // Not Found router.use((req, res, next) => next(new HttpError('Not Found', 404))); // Sentry Error Handling router.use(raven.middleware.express.requestHandler(sentry)); router.use(raven.middleware.express.errorHandler(sentry)); // Final Error Handling router.use((err, req, res, next) => { // eslint-disable-line no-unused-vars /* eslint-disable no-console */ if (err.code >= 500) { if (err.error) { console.error(err.error.message); console.error(err.error.stack); } else { console.error(err.message); console.error(err.stack); } } /* eslint-enable */ res.status(err.code).json(err.toJSON()); }); app.use(`/api${process.env.VIRTUAL_PATH}`, router); app.use(process.env.VIRTUAL_PATH, router); /* istanbul ignore if */ if (!module.parent) { const port = process.env.VIRTUAL_PORT || 8080; app.listen(port); console.log(`Server listening on port ${port}`); // eslint-disable-line no-console }