Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async express refactor #17

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import express from 'express'
import mongoose from 'mongoose'
import asyncExpress from 'async-express'
const app = express()

// Load models into memory
Expand Down Expand Up @@ -28,18 +27,18 @@ if (process.env.NODE_ENV === 'test') {
process.env.WEB_TOKEN_SECRET = 'secret'
process.env.DB_URI = 'mongodb://127.0.0.1:27017/test'
}
const mongoConnect = asyncExpress(async (_1, _2, next: any) => {
const mongoConnect: express.RequestHandler = async (_1, _2, next: any) => {
await mongoose.connect(process.env.DB_URI, {
connectTimeoutMS: 5000,
useNewUrlParser: true,
})
next()
})
}

const mongoDisconnect = asyncExpress(async (_1, _2, next) => {
const mongoDisconnect: express.RequestHandler = async (_1, _2, next) => {
await mongoose.disconnect()
next()
})
}

/**
* Establish a connection to the mongo database, then continue the request
Expand Down
66 changes: 41 additions & 25 deletions middleware/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,61 @@ import jwt from 'jsonwebtoken'
import mongoose from 'mongoose'
import express from 'express'

export type AuthReq = express.Request & {
promoter: {
_id: mongoose.Types.ObjectId
}
}

export type OptionalAuthReq = express.Request & {
promoter?: {
_id: mongoose.Types.ObjectId
}
}

// Auth required
export default (
req: express.Request,
req: AuthReq,
res: express.Response,
next: express.NextFunction
) => {
const promoter = loadPromoter(req, res)
if (!promoter) {
res.status(401)
res.send('No authentication token supplied in body or query.')
return
try {
loadPromoter(req)
if (!req.promoter) {
res.status(401)
res.send('No authentication token supplied in body or query.')
res.end()
return
}
if (!req.promoter._id) {
throw new Error('No _id present on decoded promoter')
}
next()
} catch (err) {
res.status(500)
res.send(err.toString())
}
// Deprecated
req.promoter = promoter
next()
}

export const authNotRequired = (
req: express.Request,
req: OptionalAuthReq,
res: express.Response,
next: express.NextFunction
) => {
const promoter = loadPromoter(req, res)
// Deprecated
req.promoter = promoter || {}
next()
try {
loadPromoter(req)
next()
} catch (err) {
next()
}
}

const loadPromoter = (req: express.Request, res: express.Response) => {
const loadPromoter = (req: AuthReq | OptionalAuthReq) => {
const token = req.body.token || req.query.token
if (!token) return
try {
const promoter = jwt.verify(token, process.env.WEB_TOKEN_SECRET)
if (promoter._id) {
promoter._id = mongoose.Types.ObjectId(promoter._id)
}
return promoter
} catch (err) {
// console.log('Error decoding token', err)
res.status(500)
res.send(err.toString())
const promoter: any = jwt.verify(token, process.env.WEB_TOKEN_SECRET)
if (promoter._id) {
promoter._id = mongoose.Types.ObjectId(promoter._id)
}
req.promoter = promoter
}
5 changes: 0 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
},
"homepage": "https://github.com/critrace/backend#readme",
"dependencies": {
"async-express": "^0.1.6",
"axios": "^0.19.0",
"bcrypt": "^3.0.5",
"csv-parse": "^4.4.3",
Expand Down
49 changes: 25 additions & 24 deletions routes/bib.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import asyncExpress from 'async-express'
import auth from '../middleware/auth'
import auth, { AuthReq } from '../middleware/auth'
import { isSeriesPromoter } from './series'
import express from 'express'
import mongoose from 'mongoose'
const { ObjectId } = mongoose.Types
const Bib = mongoose.model('Bib')
const Entry = mongoose.model('Entry')
const SeriesPromoter = mongoose.model('SeriesPromoter')
const Race = mongoose.model('Race')

export default (app: any) => {
export default (app: express.Application) => {
app.get('/bibs', getBibs)
app.post('/bibs', auth, create)
app.delete('/bibs', auth, deleteBib)
app.put('/bibs', auth, update)
}

const create = asyncExpress(async (req, res) => {
const create = async (req: AuthReq, res: express.Response) => {
const existingBib = await Bib.findOne({
seriesId: mongoose.Types.ObjectId(req.body.seriesId),
riderId: mongoose.Types.ObjectId(req.body.riderId),
seriesId: ObjectId(req.body.seriesId),
riderId: ObjectId(req.body.riderId),
})
.lean()
.exec()
Expand All @@ -35,7 +36,7 @@ const create = asyncExpress(async (req, res) => {
}

const existingNumber = await Bib.findOne({
seriesId: mongoose.Types.ObjectId(req.body.seriesId),
seriesId: ObjectId(req.body.seriesId),
bibNumber: req.body.bibNumber,
})
.lean()
Expand All @@ -48,12 +49,12 @@ const create = asyncExpress(async (req, res) => {
}
const created = await Bib.create(req.body)
res.json(created)
})
}

const getBibs = asyncExpress(async (req, res) => {
const getBibs = async (req: AuthReq, res: express.Response) => {
if (req.query.seriesId) {
const bibs = await Bib.find({
seriesId: mongoose.Types.ObjectId(req.query.seriesId),
seriesId: ObjectId(req.query.seriesId),
})
.populate('rider')
.populate('series')
Expand All @@ -63,7 +64,7 @@ const getBibs = asyncExpress(async (req, res) => {
return
} else if (req.query.raceId) {
const race = await Race.findOne({
_id: mongoose.Types.ObjectId(req.query.raceId),
_id: ObjectId(req.query.raceId),
}).exec()
if (!race) {
res.status(400).json({
Expand All @@ -72,15 +73,15 @@ const getBibs = asyncExpress(async (req, res) => {
return
}
const bibs = await Bib.find({
seriesId: mongoose.Types.ObjectId(race.seriesId),
seriesId: ObjectId(race.seriesId),
})
.lean()
.exec()
res.json(bibs)
return
} else if (req.query._id) {
const bib = await Bib.findOne({
_id: mongoose.Types.ObjectId(req.query._id),
_id: ObjectId(req.query._id),
})
.populate('rider')
.populate('series')
Expand All @@ -90,11 +91,11 @@ const getBibs = asyncExpress(async (req, res) => {
return
}
res.status(204).end()
})
}

const deleteBib = asyncExpress(async (req, res) => {
const deleteBib = async (req: AuthReq, res: express.Response) => {
const bib = await Bib.findOne({
_id: mongoose.Types.ObjectId(req.body._id),
_id: ObjectId(req.body._id),
})
.lean()
.exec()
Expand All @@ -111,15 +112,15 @@ const deleteBib = asyncExpress(async (req, res) => {
return
}
await Bib.deleteOne({
_id: mongoose.Types.ObjectId(req.body._id),
_id: ObjectId(req.body._id),
}).exec()
await Entry.deleteMany({
bibId: mongoose.Types.ObjectId(req.body._id),
bibId: ObjectId(req.body._id),
}).exec()
res.status(204).end()
})
}

const update = asyncExpress(async (req, res) => {
const update = async (req: AuthReq, res: express.Response) => {
if (!req.body.where) {
res.status(400).json({
message: 'No where clause supplied',
Expand All @@ -141,7 +142,7 @@ const update = asyncExpress(async (req, res) => {
) {
const existingBib = await Bib.findOne({
bibNumber: req.body.changes.bibNumber,
seriesId: mongoose.Types.ObjectId(bib.seriesId),
seriesId: ObjectId(bib.seriesId),
}).exec()
if (existingBib) {
res.status(400).json({
Expand All @@ -151,8 +152,8 @@ const update = asyncExpress(async (req, res) => {
}
}
const seriesPromoter = await SeriesPromoter.findOne({
seriesId: mongoose.Types.ObjectId(bib.seriesId),
promoterId: mongoose.Types.ObjectId(req.promoter._id),
seriesId: ObjectId(bib.seriesId),
promoterId: req.promoter._id,
})
.lean()
.exec()
Expand All @@ -164,4 +165,4 @@ const update = asyncExpress(async (req, res) => {
}
await Bib.updateOne(req.body.where, req.body.changes).exec()
res.status(204).end()
})
}
36 changes: 20 additions & 16 deletions routes/event.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import mongoose from 'mongoose'
import asyncExpress from 'async-express'
import auth, { authNotRequired } from '../middleware/auth'
import express from 'express'
import auth, {
authNotRequired,
AuthReq,
OptionalAuthReq,
} from '../middleware/auth'
import { isSeriesPromoter } from './series'
import _ from 'lodash'
import csvStringify from 'csv-stringify'
Expand All @@ -13,7 +17,7 @@ const SeriesPromoter = mongoose.model('SeriesPromoter')
const Bib = mongoose.model('Bib')
const Rider = mongoose.model('Rider')

export default (app: any) => {
export default (app: express.Application) => {
app.get('/events', authNotRequired, getEvent)
app.get('/events/home', homeEvents)
app.post('/events', auth, create)
Expand All @@ -25,7 +29,7 @@ export default (app: any) => {
/**
* Result csv download route
**/
const generateCSV = asyncExpress(async (req, res) => {
const generateCSV = async (req: AuthReq, res: express.Response) => {
const _event = await Event.findOne({
_id: mongoose.Types.ObjectId(req.query.eventId),
})
Expand Down Expand Up @@ -159,12 +163,12 @@ const generateCSV = asyncExpress(async (req, res) => {
`attachment; filename="${req.query.eventId}.csv"`
)
res.send(csvData)
})
}

/**
* Create event route
**/
const create = asyncExpress(async (req, res) => {
const create = async (req: AuthReq, res: express.Response) => {
if (!(await isSeriesPromoter(req.body.seriesId, req.promoter._id))) {
res.status(401).json({
message: 'You must be a series promoter to create an event',
Expand All @@ -176,9 +180,9 @@ const create = asyncExpress(async (req, res) => {
...req.body,
})
res.json(created)
})
}

const getEvent = asyncExpress(async (req, res) => {
const getEvent = async (req: OptionalAuthReq, res: express.Response) => {
if (req.query._id) {
const event = await Event.findOne({
_id: mongoose.Types.ObjectId(req.query._id),
Expand All @@ -199,7 +203,7 @@ const getEvent = asyncExpress(async (req, res) => {
res.json(events)
return
}
if (!req.promoter._id) {
if (!req.promoter) {
res.status(401).json({
message: 'Authenticate to retrieve owned events',
})
Expand All @@ -218,9 +222,9 @@ const getEvent = asyncExpress(async (req, res) => {
.lean()
.exec()
res.json(events)
})
}

const homeEvents = asyncExpress(async (req, res) => {
const homeEvents = async (req: express.Request, res: express.Response) => {
const events = await Event.find({
seriesId: {
$ne: mongoose.Types.ObjectId('5c9f78c12d17216b9edfbb9f'),
Expand All @@ -234,9 +238,9 @@ const homeEvents = asyncExpress(async (req, res) => {
.lean()
.exec()
res.json(events)
})
}

const deleteEvent = asyncExpress(async (req, res) => {
const deleteEvent = async (req: AuthReq, res: express.Response) => {
const event = await Event.findOne({
_id: mongoose.Types.ObjectId(req.body._id),
})
Expand All @@ -263,9 +267,9 @@ const deleteEvent = asyncExpress(async (req, res) => {
...races.map(({ _id }) => Entry.deleteMany({ raceId: _id }).exec()),
])
res.status(204).end()
})
}

const getEntries = asyncExpress(async (req, res) => {
const getEntries = async (req: express.Request, res: express.Response) => {
const entries = await Entry.find({
eventId: mongoose.Types.ObjectId(req.query._id),
})
Expand All @@ -275,4 +279,4 @@ const getEntries = asyncExpress(async (req, res) => {
.lean()
.exec()
res.json(entries)
})
}
Loading