moved api from monorepo

This commit is contained in:
2024-09-12 15:48:27 -04:00
parent 734bb0a0d2
commit d575a4efc5
29 changed files with 2904 additions and 0 deletions

View 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
View 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
View 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
View 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