moved api from monorepo
This commit is contained in:
240
middleware/advancedResults.js
Normal file
240
middleware/advancedResults.js
Normal file
@@ -0,0 +1,240 @@
|
||||
const advancedResults = (model, populate) => async (req, res, next) => {
|
||||
if (req.originalUrl.indexOf('admin') === -1)
|
||||
req.query = {
|
||||
...req.query,
|
||||
$and: [{accessedBy: {$elemMatch: {user: req.user.id}}}],
|
||||
}
|
||||
|
||||
|
||||
if (req.query.search === undefined) req.query.search = ''
|
||||
if (req.query.search)
|
||||
req.query = {...req.query, $text: {$search: req.query.search}}
|
||||
|
||||
const filterAndInGame = ['genre', 'os', 'developer', 'publisher', 'series', 'intel', 'wine', 'controller', 'store', 'soundtrack', 'playStatus', 'rating', 'ratinggte', 'ratinglte', 'steamRating', 'steamRatinggte', 'steamRatinglte']
|
||||
|
||||
filterAndInGame.map((filter) => {
|
||||
if (req.query[filter] === undefined) req.query[filter] = ''
|
||||
if (req.query[filter]) {
|
||||
let newFilter
|
||||
if (filter === 'os') {
|
||||
newFilter = req.query[filter].split(',').reduce((prev, curr, index, arr) => {
|
||||
const key = `${[filter]}.${arr[index]}`.toLowerCase()
|
||||
prev.push({[key]: true})
|
||||
return prev
|
||||
}, [])
|
||||
} else if (filter === 'store' || filter === 'soundtrack' || filter === 'playStatus') {
|
||||
newFilter = req.query[filter].split(',').reduce((prev, curr) => {
|
||||
prev.push({accessedBy: {$elemMatch: {[filter]: curr}}})
|
||||
return prev
|
||||
}, [])
|
||||
} else if (filter === 'rating') {
|
||||
if (Object.hasOwn(req.query[filter], 'gte')) {
|
||||
newFilter = req.query[filter]['gte'].split(',').reduce((prev, curr) => {
|
||||
prev.push({accessedBy: {$elemMatch: {rating: {$gte: Number(curr)}}}})
|
||||
return prev
|
||||
}, [])
|
||||
req.query.rating = `gte${req.query[filter]['gte']}`
|
||||
} else if (Object.hasOwn(req.query[filter], 'lte')) {
|
||||
newFilter = req.query[filter]['lte'].split(',').reduce((prev, curr) => {
|
||||
prev.push({accessedBy: {$elemMatch: {rating: {$lte: Number(curr)}}}})
|
||||
return prev
|
||||
}, [])
|
||||
req.query.rating = `lte${req.query[filter]['lte']}`
|
||||
} else {
|
||||
newFilter = req.query[filter].split(',').reduce((prev, curr) => {
|
||||
prev.push({accessedBy: {$elemMatch: {rating: Number(curr)}}})
|
||||
return prev
|
||||
}, [])
|
||||
}
|
||||
} else if (filter === 'ratinggte') {
|
||||
newFilter = req.query[filter].split(',').reduce((prev, curr) => {
|
||||
prev.push({accessedBy: {$elemMatch: {rating: {$gte: Number(curr)}}}})
|
||||
return prev
|
||||
}, [])
|
||||
req.query.rating = req.query.ratinggte
|
||||
} else if (filter === 'ratinglte') {
|
||||
newFilter = req.query[filter].split(',').reduce((prev, curr) => {
|
||||
prev.push({accessedBy: {$elemMatch: {rating: {$lte: Number(curr)}}}})
|
||||
return prev
|
||||
}, [])
|
||||
req.query.rating = req.query.ratinglte
|
||||
} else if (filter === 'steamRating') {
|
||||
if (Object.hasOwn(req.query[filter], 'gte')) {
|
||||
newFilter = req.query[filter]['gte'].split(',').reduce((prev, curr) => {
|
||||
prev.push({steamRating: {$gte: Number(curr)}})
|
||||
return prev
|
||||
}, [])
|
||||
req.query.steamRating = `gte${req.query[filter]['gte']}`
|
||||
} else if (Object.hasOwn(req.query[filter], 'lte')) {
|
||||
newFilter = req.query[filter]['lte'].split(',').reduce((prev, curr) => {
|
||||
prev.push({steamRating: {$lte: Number(curr)}})
|
||||
return prev
|
||||
}, [])
|
||||
req.query.steamRating = `lte${req.query[filter]['lte']}`
|
||||
} else {
|
||||
newFilter = req.query[filter].split(',').reduce((prev, curr) => {
|
||||
prev.push({steamRating: Number(curr)})
|
||||
return prev
|
||||
}, [])
|
||||
}
|
||||
} else if (filter === 'steamRatinggte') {
|
||||
newFilter = req.query[filter].split(',').reduce((prev, curr) => {
|
||||
prev.push({steamRating: {$gte: Number(curr)}})
|
||||
return prev
|
||||
}, [])
|
||||
req.query.steamRating = req.query.steamRatinggte
|
||||
} else if (filter === 'steamRatinglte') {
|
||||
newFilter = req.query[filter].split(',').reduce((prev, curr) => {
|
||||
prev.push({steamRating: {$lte: Number(curr)}})
|
||||
return prev
|
||||
}, [])
|
||||
req.query.steamRating = req.query.steamRatinglte
|
||||
} else {
|
||||
newFilter = req.query[filter].split(',').reduce((prev, curr) => {
|
||||
prev.push({[filter]: curr})
|
||||
return prev
|
||||
}, [])
|
||||
}
|
||||
newFilter.forEach(element => req.query.$and.push(element))
|
||||
}
|
||||
})
|
||||
|
||||
let query
|
||||
|
||||
// Copy req.query
|
||||
const reqQuery = {...req.query}
|
||||
|
||||
// Fields to exclude
|
||||
const removeFields = [
|
||||
'select',
|
||||
'series',
|
||||
'developer',
|
||||
'publisher',
|
||||
'sort',
|
||||
'limit',
|
||||
'page',
|
||||
'search',
|
||||
'os',
|
||||
'playStatus',
|
||||
'store',
|
||||
'soundtrack',
|
||||
'genre',
|
||||
'controller',
|
||||
'rating',
|
||||
'ratinggte',
|
||||
'ratinglte',
|
||||
'steamRating',
|
||||
'steamRatinggte',
|
||||
'steamRatinglte',
|
||||
]
|
||||
|
||||
// Loop over removeFields and delete them from reqQuery
|
||||
removeFields.forEach((param) => delete reqQuery[param])
|
||||
|
||||
filterAndInGame.forEach((param) => {
|
||||
if (req.query[param] === '') delete reqQuery[param]
|
||||
})
|
||||
|
||||
// Create query String
|
||||
let queryStr = JSON.stringify(reqQuery)
|
||||
|
||||
// Create operators like gt, gte, etc...
|
||||
queryStr = queryStr.replace(
|
||||
/\b(gt|gte|lt|lte|in|all)\b/g,
|
||||
(match) => `$${match}`,
|
||||
)
|
||||
|
||||
queryStr = queryStr.replace(/\$\$/g, '$')
|
||||
|
||||
const total = await model.countDocuments(reqQuery)
|
||||
|
||||
// Finding resource
|
||||
query = model.find(JSON.parse(queryStr))
|
||||
|
||||
// Select Fields
|
||||
if (req.query.select) {
|
||||
const fields = req.query.select.split(',').join(' ')
|
||||
query = query.select(fields)
|
||||
}
|
||||
|
||||
// Sort
|
||||
if (req.query.sort) {
|
||||
const sortBy = req.query.sort.split(',').join(' ')
|
||||
query = query.sort(sortBy)
|
||||
} else {
|
||||
query = query.sort('series title')
|
||||
}
|
||||
|
||||
// Pagination
|
||||
let page = parseInt(req.query.page, 10) || 1
|
||||
const limit = parseInt(req.query.limit, 10) || 10
|
||||
|
||||
// This block figures out how many total pages there will be and if
|
||||
// the client is calling a page larger than the total pages
|
||||
let pages
|
||||
if (limit === 1) pages = total
|
||||
else if (total === 0) pages = 1
|
||||
else if (total % limit === 0) pages = (total - (total % limit)) / limit
|
||||
else pages = (total - (total % limit)) / limit + 1
|
||||
if (page > pages) page = pages
|
||||
|
||||
const startIndex = (page - 1) * limit
|
||||
const endIndex = page * limit
|
||||
|
||||
query = query.skip(startIndex).limit(limit)
|
||||
|
||||
if (populate) {
|
||||
query = query.populate(populate)
|
||||
}
|
||||
|
||||
// Executing query
|
||||
const results = await query
|
||||
|
||||
// Pagination result
|
||||
const pagination = {}
|
||||
|
||||
if (endIndex < total) {
|
||||
pagination.next = {
|
||||
page: page + 1,
|
||||
}
|
||||
}
|
||||
|
||||
if (startIndex > 0) {
|
||||
pagination.prev = {
|
||||
page: page - 1,
|
||||
}
|
||||
}
|
||||
|
||||
res.advancedResults = {
|
||||
success: true,
|
||||
searchParams: req.query.search,
|
||||
count: {
|
||||
gamesPerPage: results.length,
|
||||
totalGames: total,
|
||||
currentPage: page,
|
||||
pages,
|
||||
limit,
|
||||
},
|
||||
filters: {
|
||||
series: req.query.series,
|
||||
playStatus: req.query.playStatus,
|
||||
genre: req.query.genre,
|
||||
os: req.query.os,
|
||||
store: req.query.store,
|
||||
developer: req.query.developer,
|
||||
controller: req.query.controller,
|
||||
publisher: req.query.publisher,
|
||||
soundtrack: req.query.soundtrack,
|
||||
intel: req.query.intel,
|
||||
wine: req.query.wine,
|
||||
rating: req.query.rating,
|
||||
steamRating: req.query.steamRating,
|
||||
},
|
||||
pagination,
|
||||
data: results,
|
||||
}
|
||||
|
||||
next()
|
||||
}
|
||||
|
||||
export default advancedResults
|
4
middleware/async.js
Normal file
4
middleware/async.js
Normal file
@@ -0,0 +1,4 @@
|
||||
const asyncHandler = fn => (req, res, next) =>
|
||||
Promise.resolve(fn(req, res, next)).catch(next)
|
||||
|
||||
export default asyncHandler
|
48
middleware/auth.js
Normal file
48
middleware/auth.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import jwt from 'jsonwebtoken'
|
||||
import asyncHandler from './async.js'
|
||||
import ErrorResponse from '../utils/errorResponse.js'
|
||||
import User from '../models/User.js'
|
||||
|
||||
// Protect route
|
||||
export const protect = asyncHandler(async (req, res, next) => {
|
||||
let token
|
||||
|
||||
// Set token from header
|
||||
if (
|
||||
req.headers.authorization &&
|
||||
req.headers.authorization.startsWith('Bearer')
|
||||
)
|
||||
token = req.headers.authorization.split(' ')[1]
|
||||
// Set token from cookie
|
||||
// else if (req.cookies.token) token = req.cookies.token
|
||||
|
||||
// Make sure token exists
|
||||
if (!token)
|
||||
return next(new ErrorResponse('Not authorized to access this route', 401))
|
||||
|
||||
try {
|
||||
// Verify token
|
||||
const decoded = jwt.verify(token, Bun.env.ACCESS_TOKEN_SECRET)
|
||||
|
||||
req.user = await User.findById(decoded.id)
|
||||
|
||||
next()
|
||||
} catch (err) {
|
||||
return next(new ErrorResponse('Not authorized to access this route', 401))
|
||||
}
|
||||
})
|
||||
|
||||
// Grants access to specific roles
|
||||
export const authorize = (...roles) => {
|
||||
return (req, res, next) => {
|
||||
if (!roles.includes(req.user.role)) {
|
||||
return next(
|
||||
new ErrorResponse(
|
||||
`User role ${req.user.role} is not authorized to access this route.`,
|
||||
403
|
||||
)
|
||||
)
|
||||
}
|
||||
next()
|
||||
}
|
||||
}
|
31
middleware/error.js
Normal file
31
middleware/error.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import ErrorResponse from '../utils/errorResponse.js'
|
||||
|
||||
const errorHandler = (err, req, res, next) => {
|
||||
let error = { ...err }
|
||||
error.message = err.message
|
||||
console.log(err.stack.red)
|
||||
|
||||
//Mongoose bad ObjectId
|
||||
if (err.name === 'CastError') {
|
||||
const message = `Resource not found${typeof(err.value) === 'string' ? ` with id of ${err.value}` : ''}`
|
||||
error = new ErrorResponse(message, 404)
|
||||
}
|
||||
|
||||
//Mongoose duplicate key
|
||||
if (err.code === 11000) {
|
||||
const message = `Duplicate field value entered`
|
||||
error = new ErrorResponse(message, 400)
|
||||
}
|
||||
|
||||
//Mongoose validation error
|
||||
if(err.name === 'ValidationError') {
|
||||
const message = Object.values(err.errors).map(val => val.message)
|
||||
error = new ErrorResponse(message, 400)
|
||||
}
|
||||
res.status(error.statusCode || 500).json({
|
||||
success: false,
|
||||
error: error.message || 'Server Error',
|
||||
})
|
||||
}
|
||||
|
||||
export default errorHandler
|
Reference in New Issue
Block a user