cubash-archive/routes/user.js

385 lines
10 KiB
JavaScript

/*
@swagger
components:
schemas:
Book:
type: object
required:
- title
- author
- finished
properties:
id:
type: integer
description: The auto-generated id of the book.
title:
type: string
description: The title of your book.
author:
type: string
description: Who wrote the book?
finished:
type: boolean
description: Have you finished reading it?
createdAt:
type: string
format: date
description: The date of the record creation.
example:
title: The Pragmatic Programmer
author: Andy Hunt / Dave Thomas
finished: true
*/
let bcrypt = require('bcryptjs')
let multer = require('multer')
let express = require('express')
let router = express.Router()
const auth = require('../lib/auth')
var Recaptcha = require('express-recaptcha').RecaptchaV3;
var recaptcha = new Recaptcha('6LdlbrwZAAAAAKvtcVQhVl_QaNOqmQ4PgyW3SKHy', '6LdlbrwZAAAAAMAWPVDrL8eNPxrws6AMDtLf1bgd');
var reCAPTCHASecret = "6LdlbrwZAAAAAKvtcVQhVl_QaNOqmQ4PgyW3SKHy";
const Errors = require('../lib/errors.js')
var format = require('date-format');
let {
User, Post, ProfilePicture, Item, userWall, StaffApplications, Inventory, AdminToken, PassKey, Thread, Category, Sequelize, Ip, Ban, sequelize
} = require('../models')
let pagination = require('../lib/pagination.js')
const sgMail = require('@sendgrid/mail');
const MailGen = require('mailgen')
const crypto = require("crypto")
const cryptoRandomString = require("crypto-random-string")
const rateLimit = require("express-rate-limit");
const emailLimiter = rateLimit({
windowMs: 60000,
max: 1, // limit each IP to 100 requests per windowMs
message: "{\"errors\":[{\"name\":\"rateLimit\",\"message\":\"You may only make 1 request to this endpoint per minute.\",\"status\":429}]}"
});
function setUserSession(req, res, username, UserId, admin) {
req.userData.loggedIn = true
req.userData.username = username
req.userData.UserId = UserId
res.cookie('username', username)
if(admin) { req.userData.admin = true }
}
router.post('/oidfhuisadhi8243', emailLimiter, async(req, res) => {
try {
await Ban.isIpBanned(req.ip)
let userParams = {
username: req.body.username,
email: req.body.email,
hash: req.body.password,
passkey: req.body.passkey,
admin: false,
bodyColor: '#fffff',
headColor: '#fffff',
leftLegColor: '#fffff',
rightLegColor: '#fffff',
leftArmColor: '#fffff',
rightArmColor: '#fffff',
koins: '250',
currency2: '0',
picture: 'default',
booster: false,
theme: 'light',
emailToken: crypto(16)
}
let user = await User.create(userParams)
await Ip.createIfNotExists(req.ip, user)
setUserSession(req, res, user.username, user.id, userParams.admin)
res.json(user.toJSON())
} catch (e) { next(e) }
})
router.post('/', emailLimiter, async(req, res, next) => {
try {
await Ban.isIpBanned(req.ip)
let userParams = {
username: req.body.username,
email: req.body.email,
hash: req.body.password,
passkey: req.body.passkey,
admin: false,
bodyColor: '#ffffff',
headColor: '#ffffff',
leftLegColor: '#ffffff',
rightLegColor: '#ffffff',
leftArmColor: '#ffffff',
rightArmColor: '#ffffff',
koins: '250',
currency2: '0',
picture: 'default',
developerMode: false,
emailVerified: false,
theme: 'light',
emailToken: cryptoRandomString({length: 16})
}
let user = await User.create(userParams)
await Ip.createIfNotExists(req.ip, user)
setUserSession(req, res, user.username, user.id, userParams.admin)
res.json(user.toJSON())
} catch (e) { next(e) }
})
router.post('/job-application', auth, async(req, res, next) => {
try {
let userParams = {
username: req.body.username,
dob: req.body.dob,
email: req.body.email,
whyWork: req.body.whyWork,
otherForm: req.body.otherForm,
experience: req.body.experience,
selectedOption: req.body.selectedOption,
}
await StaffApplications.submitApplication(userParams)
} catch (e) { next(e) }
})
router.get('/:username', async(req, res, next) => {
try {
let queryObj = {
attributes: {exclude: ['hash', 'email', 'emailVerified', 'koins', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode', 'cookieOptOut', 'deleteCode', 'jwtOffset']},
where: {username: req.params.username}
}
if (req.query.posts) {
let {from, limit} = pagination.getPaginationProps(req.query, true)
let postInclude = {
model: Post,
include: Post.includeOptions(),
limit,
order: [['id', 'DESC']]
}
if (from !== null) {
postInclude.where = {id: {$lte: from}}
}
queryObj.include = [postInclude]
let user = await User.findOne(queryObj)
if (!user) throw Errors.accountDoesNotExist
let meta = await user.getMeta(limit)
res.json(Object.assign(user.toJSON(limit), {meta}))
} else if (req.query.wall) {
let {from, limit} = pagination.getPaginationProps(req.query, true)
let postInclude = {
model: userWall,
include: userWall.includeOptions(),
limit,
order: [['id', 'DESC']],
}
if (from !== null) {
postInclude.where = {id: {$lte: from}}
}
queryObj.include = [postInclude]
let user = await User.findOne(queryObj)
if (!user) throw Errors.accountDoesNotExist
if (user.userWallOptOut) {
res.status(200)
res.json({userWalls: []})
}
res.json(Object.assign(user.toJSON(limit)))
} else if (req.query.threads) {
let queryString = ''
Object.keys(req.query).forEach(query => {
queryString += `&${query}=${req.query[query]}`
})
res.redirect('/api/v1/forums/category/ALL?username=' + req.params.username + queryString)
} else if(req.query.marketplace) {
let {from, limit} = pagination.getPaginationProps(req.query, true)
let UserId = await User.findOne({
where: {
username: req.params.username
}
})
if(!UserId) throw Errors.accountDoesNotExist
let marketplace = await Item.findAll({
where: {
UserId: UserId.id
}
})
let postInclude = {
model: Item,
include: { model: User, attributes: ['username', 'createdAt', 'id', 'color', 'picture', 'locked', 'admin', 'booster', 'executive', 'bot'] },
limit,
order: [['id', 'DESC']],
}
queryObj.include = [postInclude]
let user = await User.findOne(queryObj)
res.status(200)
let meta = await user.getMeta(limit)
res.json(Object.assign(user.toJSON(limit), {meta}))
} else if(req.query.inventory) {
let {from, limit} = pagination.getPaginationProps(req.query, true)
let userLookup = await User.findOne({
where: {
username: req.params.username
}
})
let marketplace = await Inventory.findAll({
where: {
UserId: userLookup.id
}
})
let postInclude = {
model: Inventory,
include: { model: Item, include: { model: User, attributes: ['username', 'createdAt', 'id', 'color', 'picture', 'locked', 'admin', 'booster', 'executive', 'bot'] } },
limit,
order: [['id', 'DESC']],
}
queryObj.include = [postInclude]
let user = await User.findOne(queryObj)
res.status(200)
let meta = await user.getMeta(limit)
res.json(Object.assign(user.toJSON(limit), {meta}))
} else {
let user = await User.findOne(queryObj)
if(!user) throw Errors.accountDoesNotExist
res.json(user.toJSON())
}
} catch (err) { next(err) }
})
router.post('/login', async(req, res, next) => {
try {
await Ban.isIpBanned(req.ip, req.body.email)
let user = await User.findOne({ where: {
username: req.body.username
}})
if(user) {
if(await user.comparePassword(req.body.password)) {
await Ip.createIfNotExists(req.ip, user)
setUserSession(req, res, user.username, user.id, user.admin)
res.json({
username: user.username,
admin: user.admin,
success: true
})
} else {
res.status(401)
res.json({
errors: [Errors.invalidLoginCredentials]
})
}
} else {
res.status(401)
res.json({
errors: [Errors.invalidLoginCredentials]
})
}
} catch (err) { next(err) }
})
router.post('/:username/logout', auth, async(req, res) => {
req.userData.destroy(() => {
res.clearCookie('username')
res.clearCookie('admin')
res.json({
success: true
})
})
})
router.get('/:username/picture', async(req, res, next) => {
try {
let user = await User.findOne({
where: {
username: req.params.username
}
})
if(!user) throw Errors.accountDoesNotExist
let picture = await ProfilePicture.findOne({
where: {
UserId: user.id
}
})
if(!picture) {
res.status(404)
res.end('')
} else {
res.writeHead(200, {
'Content-Type': picture.mimetype,
'Content-disposition': 'attachment;filename=profile',
'Content-Length': picture.file.length
})
res.end(new Buffer(picture.file, 'binary'))
}
} catch (e) { next(e) }
})
router.get('/', async(req, res, next) => {
try {
let sortFields = {
createdAt: 'X.id',
username: 'X.username',
threadCount: 'threadCount',
postCount: 'postCount'
};
let offset = Number.isInteger(+req.query.offset) ? +req.query.offset : 0;
let havingClause = '';
if(req.query.role === 'admin') {
havingClause = 'HAVING Users.admin = true';
} else if(req.query.role === 'user') {
havingClause = 'HAVING Users.admin = false';
} else {
havingClause = 'Having Users.hidden = false';
}
if(req.query.search) {
//I.e. if there is not already a HAVING clause
if(!havingClause.length) {
havingClause = 'HAVING ';
} else {
havingClause += ' AND ';
}
havingClause += 'Users.username LIKE $search';
}
let sql = `
SELECT X.username, X.admin, X.picture, X.level, X.levelProgress, X.bot, X.booster, X.description, X.bodyColor, X.headColor, X.leftLegColor, X.rightLegColor, X.leftArmColor, X.rightArmColor, X.hidden, X.system, X.createdAt, X.contributor, X.postCount, COUNT(Threads.id) as threadCount
FROM (
SELECT Users.*, COUNT(Posts.id) as postCount
FROM Users
LEFT OUTER JOIN Posts
ON Users.id = Posts.UserId
GROUP BY Users.id
${havingClause}
) as X
LEFT OUTER JOIN threads
ON X.id = Threads.UserId
GROUP BY X.id
ORDER BY ${sortFields[req.query.sort] || 'X.id'} ${req.query.order === 'asc' ? 'DESC' : 'ASC'}
LIMIT 30
OFFSET ${offset}
`;
let users = await sequelize.query(sql, {
model: User,
bind: { search: req.query.search + '%' }
});
res.json(users)
} catch (e) { next(e) }
})
module.exports = router;