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

135
controllers/adminGames.js Normal file
View File

@ -0,0 +1,135 @@
import Game from '../models/Game.js'
import steamScraper from '../scripts/scraper.js'
import asyncHandler from '../middleware/async.js'
import ErrorResponse from '../utils/errorResponse.js'
const checkForHexRegExp = new RegExp('^[0-9a-fA-F]{24}$')
const checkForTwelveRegExp = new RegExp('^[0-9a-fA-F]{12}$')
import {decode, isValid} from 'js-base64'
/**
* games.js
*
* @description :: Server-side logic for managing games.
*/
/**
* gameController.list()
*/
export const list = asyncHandler(async (req, res, next) => {
return res.status(200).json(res.advancedResults)
})
/**
* gameController.show()
*/
export const show = asyncHandler(async (req, res, next) => {
const { id } = req.params
const gameId =
id === id.match(checkForTwelveRegExp) || id.match(checkForHexRegExp)
? '_id'
: 'steamId'
const game = await Game.findOne({ [gameId]: id }).select('-__v')
return res.status(200).json({
success: true,
data: game,
})
})
/**
* gameController.create()
*/
export const create = asyncHandler(async (req, res, next) => {
let oldGame
req.body.steamId.length > 0
? (oldGame = await Game.findOne({ steamId: req.body.steamId }))
: (oldGame = await Game.findOne({ title: req.body.title }))
if (oldGame)
return next(
new ErrorResponse(`The game ${oldGame.title} already exists`, 400)
)
req.body.createdBy = req.user.id
req.body.lastModifiedBy = req.user.id
req.body.accessedBy[0].user = req.user.id
const data =
req.body.scrape === true ? await steamScraper(req.body) : req.body
if (req.body.scrape === false) {
if (req.body.shortDesc && isValid(req.body.shortDesc)) req.body.shortDesc = decode(req.body.shortDesc)
if (req.body.reviews && isValid(req.body.reviews)) req.body.reviews = decode(req.body.reviews)
if (req.body.summary && isValid(req.body.summary)) req.body.summary = decode(req.body.summary)
isValid(req.body.systemRequirements?.windows?.minimum) ? req.body.systemRequirements.windows.minimum = decode(req.body.systemRequirements.windows.minimum) : ''
isValid(req.body.systemRequirements?.windows?.recommended) ? req.body.systemRequirements.windows.recommended = decode(req.body.systemRequirements.windows.recommended) : ''
isValid(req.body.systemRequirements?.mac?.minimum) ? req.body.systemRequirements.mac.minimum = decode(req.body.systemRequirements.mac.minimum) : ''
isValid(req.body.systemRequirements?.mac?.recommended) ? req.body.systemRequirements.mac.recommended = decode(req.body.systemRequirements.mac.recommended) : ''
isValid(req.body.systemRequirements?.linux?.minimum) ? req.body.systemRequirements.linux.minimum = decode(req.body.systemRequirements.linux.minimum) : ''
isValid(req.body.systemRequirements?.linux?.recommended) ? req.body.systemRequirements.linux.recommended = decode(req.body.systemRequirements.linux.recommended) : ''
}
const game = await Game.create(data)
res.status(200).json({
success: true,
data: game,
})
})
/**
* gameController.update()
*/
export const update = asyncHandler(async (req, res, next) => {
const { id } = req.params
const gameId =
id === id.match(checkForTwelveRegExp) || id.match(checkForHexRegExp)
? '_id'
: 'steamId'
let game = await Game.findOne({ [gameId]: id })
if (!game)
return next(
ErrorResponse(`A game with the id of ${id} does not exist`, 401),
)
req.body.lastModifiedBy = req.user.id
if (req.body.shortDesc && isValid(req.body.shortDesc)) req.body.shortDesc = decode(req.body.shortDesc)
if (req.body.reviews && isValid(req.body.reviews)) req.body.reviews = decode(req.body.reviews)
if (req.body.summary && isValid(req.body.summary)) req.body.summary = decode(req.body.summary)
isValid(req.body.systemRequirements?.windows?.minimum) ? req.body.systemRequirements.windows.minimum = decode(req.body.systemRequirements.windows.minimum) : ''
isValid(req.body.systemRequirements?.windows?.recommended) ? req.body.systemRequirements.windows.recommended = decode(req.body.systemRequirements.windows.recommended) : ''
isValid(req.body.systemRequirements?.mac?.minimum) ? req.body.systemRequirements.mac.minimum = decode(req.body.systemRequirements.mac.minimum) : ''
isValid(req.body.systemRequirements?.mac?.recommended) ? req.body.systemRequirements.mac.recommended = decode(req.body.systemRequirements.mac.recommended) : ''
isValid(req.body.systemRequirements?.linux?.minimum) ? req.body.systemRequirements.linux.minimum = decode(req.body.systemRequirements.linux.minimum) : ''
isValid(req.body.systemRequirements?.linux?.recommended) ? req.body.systemRequirements.linux.recommended = decode(req.body.systemRequirements.linux.recommended) : ''
const data =
req.body.scrape === true ? await steamScraper(req.body) : req.body
game = await Game.findOneAndUpdate({ [gameId]: id }, data, {
new: true,
runValidators: true,
})
res.status(200).json({
success: true,
data: game,
})
})
/**
* gameController.remove()
*/
export const remove = asyncHandler(async (req, res, next) => {
const { id } = req.params
const gameId =
id === id.match(checkForTwelveRegExp) || id.match(checkForHexRegExp)
? '_id'
: 'steamId'
await Game.findOneAndDelete({ [gameId]: id })
res.status(200).json({ success: true, data: {} })
})

223
controllers/auth.js Normal file
View File

@ -0,0 +1,223 @@
// noinspection SpellCheckingInspection
import User from '../models/User.js'
import asyncHandler from '../middleware/async.js'
import ErrorResponse from '../utils/errorResponse.js'
import sendEmail from '../utils/sendEmail.js'
import crypto from 'crypto'
// @desc Register user
// @route POST /api/v1/auth/register
// @access Public
export const register = asyncHandler(async (req, res, next) => {
const { name, displayName, email, password, role } = req.body
//Create user
const user = await User.create({
name,
displayName,
email,
password,
role,
gamesCreated: [],
gamesToAccess: [],
})
sendTokenResponse(user, 200, res)
})
// @desc Login user
// @route POST /api/v1/auth/login
// @access Public
export const login = asyncHandler(async (req, res, next) => {
const { email, password } = req.body
// Validate email & password
if (!email || !password)
return next(new ErrorResponse('Please provide an email and password', 400))
// Check for user
const user = await User.findOne({ email }).select('+password')
if (!user) return next(new ErrorResponse('Invalid credentials', 401))
// Check is password matches
const isMatched = await user.matchPassword(password)
if (!isMatched) return next(new ErrorResponse('Invalid credentials', 401))
sendTokenResponse(user, 200, res)
})
// @desc Logout User / Clear Cookie
// @route GET /api/v1/auth/logout
// @access Private
export const logout = asyncHandler(async (req, res, next) => {
res.cookie('token', 'none', {
expires: new Date(Date.now() + 10 * 1000),
httpOnly: true,
})
res.status(200).json({
success: true,
data: {},
})
})
// @desc Get current logged-in user
// @route POST /api/v1/auth/me
// @access Private
export const getMe = asyncHandler(async (req, res, next) => {
const user = await User.findById(req.user.id)
res.status(200).json({
success: true,
data: user,
})
})
// @desc Update user details
// @route PUT /api/v1/auth/updatedetails
// @access Private
export const updateDetails = asyncHandler(async (req, res, next) => {
const fieldsToUpdate = {
name: req.body.name,
displayName: req.body.displayName,
email: req.body.email,
role: req.body.role,
updateDate: Date.now(),
}
const user = await User.findByIdAndUpdate(req.user.id, fieldsToUpdate, {
new: true,
runValidators: true,
})
res.status(200).json({
success: true,
data: user,
})
})
// @desc Update password
// @route PUT /api/v1/auth/updatepassword
// @access Private
export const updatePassword = asyncHandler(async (req, res, next) => {
const user = await User.findById(req.user.id).select('+password')
// Check current password
if (!(await user.matchPassword(req.body.currentPassword)))
return next(new ErrorResponse('Password is incorrect', 401))
user.password = req.body.newPassword
await user.save()
sendTokenResponse(user, 200, res)
})
// @desc Forgot password
// @route POST /api/v1/auth/forgotpassword
// @access Public
export const forgotPassword = asyncHandler(async (req, res, next) => {
const user = await User.findOne({ email: req.body.email })
if (!user) {
console.error('user does not exist')
return res.status(200).json({
success: true,
data: 'Email has been sent',
})
}
// Get reset token
const resetToken = await user.getResetPasswordToken()
await user.save({ validateBeforeSave: false })
// Create reset url
let resetUrl
let message
if (req.get('Referrer') === undefined) {
const protocol = req.secure ? 'https' : 'http'
const host = await req.get('host')
resetUrl = `${protocol}://${host}/api/auth/resetpassword/${resetToken}`
message = {
text: `You are receiving this email because you (or someone else) has requested the reset of a password. Please make a PUT request to: \n\n${resetUrl}`,
html: `<body><p>You are receiving this email because you (or someone else) has requested the reset of a password. <br />Please make a PUT request to:</p> <p>${resetUrl}</p></body>`
}
} else {
resetUrl = `${req.get('Referrer')}resetpassword/${resetToken}`
message = {
text: `You are receiving this email because you (or someone else) has requested the reset of a password. \nPlease visit the below URL to continue this request. \n\n${resetUrl}`,
html: `<body><p>You are receiving this email because you (or someone else) has requested the reset of a password. <br />Please visit the below URL to continue this request.</p> <p><a href=${resetUrl}>${resetUrl}</a></p></body>`,
}
}
try {
await sendEmail({
email: user.email,
subject: 'Games Database Password Reset Token',
message,
})
res.status(200).json({
success: true,
data: 'Email has been sent',
})
} catch (err) {
console.log(err)
user.resetPasswordToken = undefined
user.resetPasswordExpire = undefined
await user.save({ validateBeforeSave: false })
return next(new ErrorResponse('Email could not be sent', 500))
}
})
// @desc Reset password
// @route PUT /api/v1/auth/resetpassword/:resettoken
// @access Public
export const resetPassword = asyncHandler(async (req, res, next) => {
// Get hashed token
const resetPasswordToken = crypto
.createHash('sha256')
.update(req.params.resettoken)
.digest('hex')
const user = await User.findOne({
resetPasswordToken,
resetPasswordExpire: { $gt: Date.now() },
})
if (!user) return next(new ErrorResponse('Invalid token', 400))
// Set new password
user.password = req.body.password
user.resetPasswordToken = undefined
user.resetPasswordExpire = undefined
await user.save()
sendTokenResponse(user, 200, res)
})
// Get token from model, create cookie and send response
const sendTokenResponse = (user, statusCode, res) => {
// Create token
const token = user.getSignedJwtToken()
const options = {
expires: new Date(
Date.now() + 24 * 60 * 60 * 1000,
),
httpOnly: true,
}
if (Bun.env.NODE_ENV === 'production') options.secure = true
res.status(statusCode).cookie('token', token, options).json({
success: true,
token,
})
}

238
controllers/games.js Normal file
View File

@ -0,0 +1,238 @@
// noinspection DuplicatedCode
import Game from '../models/Game.js'
import steamScraper from '../scripts/scraper.js'
import asyncHandler from '../middleware/async.js'
import ErrorResponse from '../utils/errorResponse.js'
import {decode, isValid} from "js-base64";
const checkForHexRegExp = new RegExp('^[0-9a-fA-F]{24}$')
const checkForTwelveRegExp = new RegExp('^[0-9a-fA-F]{12}$')
/**
* games.js
*
* @description :: Server-side logic for managing games.
*/
/**
* gameController.list()
*/
export const list = asyncHandler(async (req, res, next) => {
const data = res.advancedResults.data
if (data[0]?.accessedBy) {
for (let i = 0; i < data.length; i++) {
for (let x = 0; x < data[i].accessedBy.length; x++) {
if (data[i].accessedBy[x].user.toString() !== req.user.id)
data[i].accessedBy.splice(x, 1)
}
}
}
return res.status(200).json(res.advancedResults)
})
/**
* gameController.show()
*/
export const show = asyncHandler(async (req, res, next) => {
const {id} = req.params
const gameId =
id === id.match(checkForTwelveRegExp) || id.match(checkForHexRegExp)
? '_id'
: 'steamId'
const game = await Game.findOne({[gameId]: id})
if (!game)
return next(
new ErrorResponse(`Game not found with id of ${req.params.id}`, 404),
)
if (
!game.accessedBy
.map((x) => x.user.toString() === req.user.id)
.includes(true)
)
return next(
new ErrorResponse(
`You do not have permission to access Game ID ${req.params.id}`,
401,
),
)
const userGame = await Game.findOne({[gameId]: id}).select(
'-createdBy -__v',
)
for (let i = 0; i < userGame.accessedBy.length; i++) {
if (userGame.accessedBy[i].user.toString() !== req.user.id)
userGame.accessedBy.splice(i, 1)
}
res.status(200).json({success: true, data: userGame})
})
/**
* gameController.create()
*/
export const create = asyncHandler(async (req, res, next) => {
let oldGame
if (req.body.shortDesc && isValid(req.body.shortDesc)) req.body.shortDesc = decode(req.body.shortDesc)
if (req.body.reviews && isValid(req.body.reviews)) req.body.reviews = decode(req.body.reviews)
if (req.body.summary && isValid(req.body.summary)) req.body.summary = decode(req.body.summary)
isValid(req.body.systemRequirements?.windows?.minimum) ? req.body.systemRequirements.windows.minimum = decode(req.body.systemRequirements.windows.minimum) : ''
isValid(req.body.systemRequirements?.windows?.recommended) ? req.body.systemRequirements.windows.recommended = decode(req.body.systemRequirements.windows.recommended) : ''
isValid(req.body.systemRequirements?.mac?.minimum) ? req.body.systemRequirements.mac.minimum = decode(req.body.systemRequirements.mac.minimum) : ''
isValid(req.body.systemRequirements?.mac?.recommended) ? req.body.systemRequirements.mac.recommended = decode(req.body.systemRequirements.mac.recommended) : ''
isValid(req.body.systemRequirements?.linux?.minimum) ? req.body.systemRequirements.linux.minimum = decode(req.body.systemRequirements.linux.minimum) : ''
isValid(req.body.systemRequirements?.linux?.recommended) ? req.body.systemRequirements.linux.recommended = decode(req.body.systemRequirements.linux.recommended) : ''
req.body.steamId.length > 0
? (oldGame = await Game.findOne({
steamId: req.body.steamId,
'accessedBy.user': req.user.id,
}))
: (oldGame = await Game.findOne({
title: req.body.title,
'accessedBy.user': req.user.id,
}))
if (oldGame)
return next(
new ErrorResponse(`The game ${oldGame.title} already exists in users account.`, 400)
)
req.body.steamId.length > 0
? (oldGame = await Game.findOne({steamId: req.body.steamId}))
: (oldGame = await Game.findOne({title: req.body.title}))
if (oldGame) {
oldGame.accessedBy.push({
user: req.user.id,
store: req.body.accessedBy[0].store,
playStatus: req.body.accessedBy[0].playStatus,
soundtrack: req.body.accessedBy[0].soundtrack,
rating: req.body.accessedBy[0].rating,
})
oldGame.lastModifiedBy = req.user.id
await oldGame.save()
return res.status(200).json({
success: true,
data: oldGame,
})
}
req.body.createdBy = req.user.id
req.body.lastModifiedBy = req.user.id
req.body.accessedBy[0].user = req.user.id
const data =
req.body.scrape === true ? await steamScraper(req.body) : req.body
const game = await Game.create(data)
res.status(200).json({
success: true,
data: game,
})
})
/**
* gameController.update()
*/
export const update = asyncHandler(async (req, res, next) => {
const {id} = req.params
const gameId =
id === id.match(checkForTwelveRegExp) || id.match(checkForHexRegExp)
? '_id'
: 'steamId'
if (req.body.shortDesc && isValid(req.body.shortDesc)) req.body.shortDesc = decode(req.body.shortDesc)
if (req.body.reviews && isValid(req.body.reviews)) req.body.reviews = decode(req.body.reviews)
if (req.body.summary && isValid(req.body.summary)) req.body.summary = decode(req.body.summary)
isValid(req.body.systemRequirements?.windows?.minimum) ? req.body.systemRequirements.windows.minimum = decode(req.body.systemRequirements.windows.minimum) : ''
isValid(req.body.systemRequirements?.windows?.recommended) ? req.body.systemRequirements.windows.recommended = decode(req.body.systemRequirements.windows.recommended) : ''
isValid(req.body.systemRequirements?.mac?.minimum) ? req.body.systemRequirements.mac.minimum = decode(req.body.systemRequirements.mac.minimum) : ''
isValid(req.body.systemRequirements?.mac?.recommended) ? req.body.systemRequirements.mac.recommended = decode(req.body.systemRequirements.mac.recommended) : ''
isValid(req.body.systemRequirements?.linux?.minimum) ? req.body.systemRequirements.linux.minimum = decode(req.body.systemRequirements.linux.minimum) : ''
isValid(req.body.systemRequirements?.linux?.recommended) ? req.body.systemRequirements.linux.recommended = decode(req.body.systemRequirements.linux.recommended) : ''
let game = await Game.findOne({
[gameId]: id,
'accessedBy.user': req.user.id,
})
if (!game)
return next(
new ErrorResponse(`A game with the id of ${id} does not exist`, 401),
)
game = await Game.findOneAndUpdate(
{[gameId]: id, 'accessedBy.user': req.user.id},
{
$set: {
series: req.body.series,
intel: req.body.intel,
genre: req.body.genre,
wine: req.body.wine,
lastModifiedBy: req.user.id,
'accessedBy.$.store': req.body.accessedBy[0].store,
'accessedBy.$.playStatus': req.body.accessedBy[0].playStatus,
'accessedBy.$.soundtrack': req.body.accessedBy[0].soundtrack,
'accessedBy.$.rating': req.body.accessedBy[0].rating,
},
},
{new: true, runValidators: true},
)
res.status(200).json({
success: true,
data: game,
})
})
/**
* gameController.remove()
*/
export const remove = asyncHandler(async (req, res, next) => {
const {id} = req.params
const gameId =
id === id.match(checkForTwelveRegExp) || id.match(checkForHexRegExp)
? '_id'
: 'steamId'
let game = await Game.findOne({
[gameId]: id,
'accessedBy.user': req.user.id,
})
if (!game)
return next(
new ErrorResponse(`A game with the id of ${id} does not exist`, 401),
)
if (game.accessedBy.length > 1) {
await Game.findOneAndUpdate(
{[gameId]: id, 'accessedBy.user': req.user.id},
{
$pull: {
accessedBy: {user: req.user.id},
},
},
{new: true, runValidators: true},
)
} else {
await Game.findOneAndDelete({[gameId]: id})
}
res.status(200).json({
success: true,
data: {},
})
})

64
controllers/tags.js Normal file
View File

@ -0,0 +1,64 @@
import getTag from '../utils/getTag.js'
import asyncHandler from '../middleware/async.js'
/**
* gameController.tagList()
* Finds all genres used distinctly
*/
export const genreList = asyncHandler(async (req, res, next) => {
const genre = await getTag('genre')
return res.status(200).json({
success: true,
genre,
})
})
export const seriesList = asyncHandler(async (req, res, next) => {
const series = await getTag('series')
return res.status(200).json({
success: true,
series,
})
})
export const storeList = asyncHandler(async (req, res, next) => {
const store = await getTag('accessedBy.store')
return res.status(200).json({
success: true,
store,
})
})
export const developerList = asyncHandler(async (req, res, next) => {
const developer = await getTag('developer')
return res.status(200).json({
success: true,
developer,
})
})
export const publisherList = asyncHandler(async (req, res, next) => {
const publisher = await getTag('publisher')
return res.status(200).json({
success: true,
publisher,
})
})
export const tags = async (req, res, next) => {
const genre = await getTag('genre')
const series = await getTag('series')
const store = await getTag('accessedBy.store')
const developer = await getTag('developer')
const publisher = await getTag('publisher')
const tags = { genre, series, store, developer, publisher }
return res.status(200).json({
success: true,
data: tags,
})
}

79
controllers/users.js Normal file
View File

@ -0,0 +1,79 @@
import User from '../models/User.js'
import asyncHandler from '../middleware/async.js'
import ErrorResponse from '../utils/errorResponse.js'
// @desc Get all users
// @route GET /api/admin/users
// @access Private/Admin
export const getUsers = asyncHandler(async (req, res, next) => {
res.status(200).json({
success: true,
data: res.advancedResults,
})
})
// @desc Get single user
// @route GET /api/admin/users/:id
// @access Private/Admin
export const getUser = asyncHandler(async (req, res, next) => {
console.log('reached route.')
const user = await User.findById(req.params.id)
res.status(200).json({
success: true,
data: user,
})
})
// @desc Create user
// @route POST /api/admin/users
// @access Private/Admin
export const createUser = asyncHandler(async (req, res, next) => {
const user = await User.create(req.body)
res.status(201).json({
success: true,
data: user,
})
})
// @desc Update user
// @route PUT /api/admin/users/:id
// @access Private/Admin
export const updateUser = asyncHandler(async (req, res, next) => {
const { password, ...updateFields } = req.body
let user = await User.findById(req.params.id).select('+password')
if (!user)
return next(new ErrorResponse('User does not exist in database', 404))
await user.updateOne(updateFields, {
runValidators: true,
})
if (password) {
user.password = password
await user.save()
user = await User.findById(req.params.id).select('+password')
} else {
user = await User.findById(req.params.id)
}
res.status(200).json({
success: true,
data: user,
})
})
// @desc Delete user
// @route DELETE /api/admin/users/:id
// @access Private/Admin
export const deleteUser = asyncHandler(async (req, res, next) => {
await User.findByIdAndDelete(req.params.id)
res.status(200).json({
success: true,
data: {},
})
})