cubash-archive/routes/user.js

326 lines
8.4 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()
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, userWall, StaffApplications, 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.session.loggedIn = true
req.session.username = username
req.session.UserId = UserId
res.cookie('username', username)
if(admin) { req.session.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', 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']},
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 postInclude = {
model: userWall,
include: userWall.includeOptions(),
order: [['id', 'DESC']]
}
queryObj.include = [postInclude]
let user = await User.findOne(queryObj)
if(!user) throw Errors.accountDoesNotExist
let meta = await user.getMeta()
res.json(Object.assign( user.toJSON(x), { meta } ))
} 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 {
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', async (req, res) => {
req.session.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 = '';
}
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.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' ? 'ASC' : 'DESC'}
LIMIT 2000
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;