forked from kaverti/website
633 lines
21 KiB
JavaScript
633 lines
21 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, teamWall, TeamInvite, TeamMemberRole, Transaction, teamPicture, userWall, StaffApplications, AdminToken, PassKey, Thread, Category, Sequelize, Ip, Ban, sequelize, Team, TeamMembers, TeamRoles
|
|
} = 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('/create', emailLimiter, auth, async(req, res, next) => {
|
|
try {
|
|
await Ban.isIpBanned(req.ip)
|
|
let user = await User.findOne({where: {
|
|
username: req.userData.username
|
|
}})
|
|
if(user.koins >= 300) {
|
|
let userParams = {
|
|
username: req.body.username,
|
|
name: req.body.name,
|
|
description: "This is the " + req.body.username + " team!",
|
|
banned: false,
|
|
banReason: "No reason provided",
|
|
itemsOptOut: false,
|
|
forumEnabled: false,
|
|
teamWallOptOut: false,
|
|
approved: false,
|
|
picture: "default",
|
|
OwnerId: req.userData.UserId
|
|
}
|
|
let team = await Team.create(userParams)
|
|
let teamInfo = team.toJSON()
|
|
console.log(teamInfo)
|
|
let teamRoleMembers = {
|
|
name: "Members",
|
|
teamId: teamInfo.id,
|
|
priority: 2
|
|
}
|
|
let teamRoleAdmins = {
|
|
name: "Administrators",
|
|
teamId: teamInfo.id,
|
|
administrator: true,
|
|
priority: 1
|
|
}
|
|
let memberRole = await TeamRoles.create(teamRoleMembers)
|
|
let memberRoleInfo = memberRole.toJSON()
|
|
let adminRole = await TeamRoles.create(teamRoleAdmins)
|
|
let adminRoleInfo = adminRole.toJSON()
|
|
let teamAddOwner = {
|
|
userId: req.userData.UserId,
|
|
teamId: teamInfo.id,
|
|
roles: {"deprecated": "deprecated"}
|
|
}
|
|
let teamRoleOwner = {
|
|
UserId: req.userData.UserId,
|
|
TeamId: teamInfo.id,
|
|
RoleId: adminRoleInfo.id,
|
|
Role2Id: memberRoleInfo.id
|
|
}
|
|
await TeamMembers.create(teamAddOwner)
|
|
await TeamMemberRole.create(teamRoleOwner)
|
|
await Transaction.create({UserId: user.id, priceOfPurchase: 300, text: user.username + ' purchased a Kaverti Team for 300 koins', limited: false, ipId: Ip.createIfNotExists(req.ip, user)})
|
|
res.json(team.toJSON())
|
|
} else {
|
|
throw Errors.insufficientKoins
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/view/:username', async(req, res, next) => {
|
|
try {
|
|
let queryObj = {
|
|
attributes: {exclude: ['banReason', 'TeamRoleId']},
|
|
where: {username: req.params.username}
|
|
}
|
|
let queryObjBanned = {
|
|
attributes: {exclude: ['banReason', 'description', 'picture', 'forumEnabled', 'TeamRoleId', 'OwnerId']},
|
|
where: {username: req.params.username}
|
|
}
|
|
if(req.query.wall) {
|
|
let {from, limit} = pagination.getPaginationProps(req.query, true)
|
|
let postInclude = {
|
|
model: teamWall,
|
|
include: teamWall.includeOptions(),
|
|
limit,
|
|
order: [['id', 'DESC']],
|
|
}
|
|
if (from !== null) {
|
|
postInclude.where = {id: {$lte: from}}
|
|
}
|
|
queryObj.include = [postInclude]
|
|
|
|
let user = await Team.findOne(queryObj)
|
|
if (!user) throw Errors.accountDoesNotExist
|
|
if(user.banned) {
|
|
throw Errors.teamBanned
|
|
}
|
|
if (user.userWallOptOut) {
|
|
throw Errors.userWallOptOut
|
|
}
|
|
res.json(Object.assign(user.toJSON(limit)))
|
|
} else {
|
|
let team = await Team.findOne(queryObj)
|
|
if (!team) throw Errors.accountDoesNotExist
|
|
if(!team.banned) {
|
|
res.json(team.toJSON())
|
|
} else {
|
|
let team = await Team.findOne(queryObjBanned)
|
|
res.json(team.toJSON())
|
|
}
|
|
}
|
|
|
|
|
|
} catch (err) { next(err) }
|
|
})
|
|
|
|
router.get('/view/:username/picture', async (req, res, next) => {
|
|
try {
|
|
let user = await Team.findOne({
|
|
where: {
|
|
username: req.params.username
|
|
}
|
|
})
|
|
if(!user) throw Errors.accountDoesNotExist
|
|
|
|
let picture = await teamPicture.findOne({
|
|
where: {
|
|
TeamId: user.id
|
|
}
|
|
})
|
|
|
|
if(!picture) {
|
|
res.status(404)
|
|
res.json({picture: "https://cdn.kaverti.com/teams/unknown-light.png"})
|
|
} else if(!user.banned) {
|
|
res.writeHead(200, {
|
|
'Content-Type': picture.mimetype,
|
|
'Content-disposition': 'attachment;filename=kaverti-team-profile-picture',
|
|
'Content-Length': picture.file.length
|
|
})
|
|
res.end(new Buffer.from(picture.file, 'binary'))
|
|
} else {
|
|
res.status(404)
|
|
res.json({picture: "https://cdn.kaverti.com/teams/unknown-light.png"})
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/view/:username/members', async(req, res, next) => {
|
|
try {
|
|
let user = await Team.findOne({
|
|
where: {
|
|
username: req.params.username
|
|
}
|
|
})
|
|
if(user) {
|
|
if(user.banned) {
|
|
res.status(200)
|
|
res.json([])
|
|
}
|
|
let team = await TeamMembers.findAll({
|
|
order: [['id', 'DESC']],
|
|
where: {
|
|
TeamId: user.id
|
|
},
|
|
include: [
|
|
{ model: User, attributes: ['username', 'createdAt', 'id', 'color', 'picture', 'description'] }
|
|
]
|
|
})
|
|
res.json(team)
|
|
} else {
|
|
throw Errors.accountDoesNotExist
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/view/:username/userRoles', async(req, res, next) => {
|
|
try {
|
|
let user = await Team.findOne({
|
|
where: {
|
|
username: req.params.username
|
|
}
|
|
})
|
|
if(user) {
|
|
if(user.banned) {
|
|
res.status(200)
|
|
res.json([])
|
|
}
|
|
let team = await TeamMemberRole.findAll({
|
|
order: [['id', 'DESC']],
|
|
where: {
|
|
TeamId: user.id
|
|
},
|
|
include: [
|
|
{ model: User, attributes: ['username', 'createdAt', 'id', 'color', 'picture'] },
|
|
{ model: TeamRoles, as: 'Role' },
|
|
{ model: TeamRoles, as: 'Role2' },
|
|
{ model: TeamRoles, as: 'Role3' },
|
|
{ model: TeamRoles, as: 'Role4' },
|
|
{ model: TeamRoles, as: 'Role5' },
|
|
{ model: TeamRoles, as: 'Role6' },
|
|
{ model: TeamRoles, as: 'Role7' },
|
|
{ model: TeamRoles, as: 'Role8' },
|
|
{ model: TeamRoles, as: 'Role9' },
|
|
{ model: TeamRoles, as: 'Role10' },
|
|
|
|
|
|
]
|
|
})
|
|
res.json(team)
|
|
} else {
|
|
throw Errors.accountDoesNotExist
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/view/:username/roles', async(req, res, next) => {
|
|
try {
|
|
let user = await Team.findOne({
|
|
where: {
|
|
username: req.params.username
|
|
}
|
|
})
|
|
if(user) {
|
|
if(user.banned) {
|
|
res.status(200)
|
|
res.json([])
|
|
}
|
|
let team = await TeamRoles.findAll({
|
|
order: [['id', 'DESC']],
|
|
where: {
|
|
TeamId: user.id
|
|
},
|
|
})
|
|
res.json(team)
|
|
} else {
|
|
throw Errors.accountDoesNotExist
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/view/:username/roles/id/:id', async(req, res, next) => {
|
|
try {
|
|
let user = await Team.findOne({
|
|
where: {
|
|
username: req.params.username
|
|
}
|
|
})
|
|
if(user) {
|
|
if(user.banned) {
|
|
res.status(200)
|
|
res.json([])
|
|
}
|
|
let team = await TeamMemberRole.findAll({
|
|
order: [['id', 'DESC']],
|
|
where: {
|
|
TeamId: user.id,
|
|
RoleId: req.params.id
|
|
},
|
|
include: { model: User, attributes: ['username', 'createdAt', 'id', 'color', 'picture'] },
|
|
})
|
|
res.json(team)
|
|
} else {
|
|
throw Errors.accountDoesNotExist
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/view/:username/roles/name/:id', async(req, res, next) => {
|
|
try {
|
|
let user = await Team.findOne({
|
|
where: {
|
|
username: req.params.username
|
|
}
|
|
})
|
|
let userParam = await User.findOne({
|
|
where: {
|
|
username: req.params.id
|
|
}
|
|
})
|
|
if(user && userParam) {
|
|
if(user.banned) {
|
|
res.status(200)
|
|
res.json([])
|
|
}
|
|
let team = await TeamMemberRole.findAll({
|
|
order: [['id', 'DESC']],
|
|
where: {
|
|
TeamId: user.id,
|
|
UserID: userParam.id
|
|
},
|
|
include: [ { model: User, attributes: ['username', 'createdAt', 'id', 'color', 'picture'] }, { model: TeamRoles, as: 'Role' } ]
|
|
})
|
|
res.json(team)
|
|
} else {
|
|
throw Errors.accountDoesNotExist
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/', async(req, res, next) => {
|
|
try {
|
|
let sortFields = {
|
|
createdAt: 'X.id',
|
|
username: 'X.username',
|
|
};
|
|
let offset = Number.isInteger(+req.query.offset) ? +req.query.offset : 0;
|
|
let havingClause = 'Having Teams.banned = false';
|
|
|
|
if(req.query.search) {
|
|
//I.e. if there is not already a HAVING clause
|
|
if(!havingClause.length) {
|
|
havingClause = 'HAVING ';
|
|
} else {
|
|
havingClause += ' AND ';
|
|
}
|
|
havingClause += 'Team.username LIKE $search';
|
|
}
|
|
let sql = `
|
|
SELECT X.username, X.approved, X.name, X.picture, X.id, X.forumEnabled, X.description, X.banned, X.createdAt, X.updatedAt
|
|
FROM (
|
|
SELECT Teams.*
|
|
FROM Teams
|
|
GROUP BY Teams.id
|
|
${havingClause}
|
|
) as X
|
|
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: Team,
|
|
bind: { search: req.query.search + '%' }
|
|
});
|
|
res.json(users)
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.put('/join/:username', auth, async(req, res, next) => {
|
|
try {
|
|
await Ban.ReadOnlyMode(req.userData.UserId)
|
|
let team = await Team.findOne({
|
|
where: { username: req.params.username }
|
|
})
|
|
if(team) {
|
|
if(team.banned) {
|
|
throw Errors.teamBanned
|
|
}
|
|
if(team.inviteOnly) {
|
|
throw Errors.inviteOnly
|
|
}
|
|
let queryObj3 = {
|
|
where: {userId: req.userData.UserId, teamId: team.id},
|
|
}
|
|
let teamJoinTest = await TeamMembers.findOne(queryObj3)
|
|
if(teamJoinTest) {
|
|
throw Errors.joinedTeam
|
|
}
|
|
let role = await TeamRoles.findOne({
|
|
where: {teamId: team.id, name: "Members"}
|
|
})
|
|
let join = {
|
|
userId: req.userData.UserId,
|
|
teamId: team.id,
|
|
roles: {"deprecated": "deprecated"}
|
|
}
|
|
console.log(role)
|
|
let roleUser = {
|
|
UserId: req.userData.UserId,
|
|
TeamId: team.id,
|
|
RoleId: role.id
|
|
}
|
|
await TeamMembers.create(join)
|
|
await TeamMemberRole.create(roleUser)
|
|
res.status(200)
|
|
res.json({success: true})
|
|
} else {
|
|
throw Errors.teamDoesNotExist
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/check/:username', auth, async(req, res, next) => {
|
|
try {
|
|
let team = await Team.findOne({
|
|
where: {username: req.params.username}
|
|
});
|
|
if(team) {
|
|
let queryObj3 = {
|
|
where: {userId: req.userData.UserId, teamId: team.id},
|
|
}
|
|
if(team.banned) {
|
|
res.status(200)
|
|
res.json({success: false})
|
|
}
|
|
let teamJoinTest = await TeamMembers.findOne(queryObj3)
|
|
if (teamJoinTest) {
|
|
res.status(200)
|
|
res.json({success: true})
|
|
} else if (!teamJoinTest) {
|
|
res.status(200)
|
|
res.json({success: false})
|
|
}
|
|
} else {
|
|
throw Errors.teamDoesNotExist
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.put('/leave/:username', auth, async(req, res, next) => {
|
|
try {
|
|
await Ban.ReadOnlyMode(req.userData.UserId)
|
|
let team = await Team.findOne({
|
|
where: { username: req.params.username }
|
|
})
|
|
if(team) {
|
|
if(team.banned) {
|
|
throw Errors.teamBanned
|
|
}
|
|
let queryObj3 = {
|
|
where: {userId: req.userData.UserId, teamId: team.id},
|
|
}
|
|
let teamLeaveTeam = await TeamMembers.findOne(queryObj3)
|
|
if(teamLeaveTeam) {
|
|
let queryObj4 = {
|
|
where: {UserId: req.userData.UserId, TeamId: team.id},
|
|
}
|
|
let teamLeaveRoles = await TeamMemberRole.findAll(queryObj4)
|
|
await teamLeaveTeam.leaveTeam()
|
|
teamLeaveRoles.forEach((TeamMemberRole) => TeamMemberRole.leaveTeam());
|
|
res.status(200)
|
|
res.json({success: true})
|
|
} else {
|
|
throw Errors.notInTeam
|
|
}
|
|
} else {
|
|
throw Errors.teamDoesNotExist
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
router.get('/invite/:username', async(req, res, next) => {
|
|
try {
|
|
let code = await TeamInvite.findOne({
|
|
where: {code: req.params.username},
|
|
include: {model: Team, attributes: { exclude: [ 'banReason' ]}}
|
|
})
|
|
if (code) {
|
|
if(code.maxUses === 0) {
|
|
res.status(200)
|
|
res.json(code.toJSON())
|
|
} else if(code.uses >= code.maxUses) {
|
|
throw Errors.invalidInvite
|
|
} else if(code.uses < code.maxUses) {
|
|
res.status(200)
|
|
res.json(code.toJSON())
|
|
} else {
|
|
throw Errors.invalidInvite
|
|
}
|
|
} else {
|
|
throw Errors.invalidInvite
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.post('/invite/:code', auth, async(req, res, next) => {
|
|
try {
|
|
await Ban.ReadOnlyMode(req.userData.UserId)
|
|
let code = await TeamInvite.findOne({
|
|
where: {code: req.params.code}
|
|
})
|
|
if (code) {
|
|
let team = await Team.findOne({
|
|
where: {id: code.TeamId}
|
|
})
|
|
if (team.banned) {
|
|
throw Errors.teamBanned
|
|
}
|
|
let queryObj3 = {
|
|
where: {userId: req.userData.UserId, teamId: team.id},
|
|
}
|
|
let teamJoinTest = await TeamMembers.findOne(queryObj3)
|
|
if (teamJoinTest) {
|
|
throw Errors.joinedTeam
|
|
}
|
|
if(code.maxUses >= code.uses) {
|
|
throw Errors.inviteInvalid
|
|
} else if(code.maxUses === 0) {
|
|
let role = await TeamRoles.findOne({
|
|
where: {teamId: team.id, name: "Members"}
|
|
})
|
|
if(code.RoleId >= 0) {
|
|
let roleLookup = await TeamInvite.findOne({
|
|
where: {code: req.body.RoleId, TeamId: team.id}
|
|
})
|
|
if(roleLookup) {
|
|
let join = {
|
|
userId: req.userData.UserId,
|
|
teamId: team.id,
|
|
roles: {"deprecated": "deprecated"}
|
|
}
|
|
console.log(role)
|
|
let roleUser = {
|
|
UserId: req.userData.UserId,
|
|
TeamId: team.id,
|
|
RoleId: role.id,
|
|
Role2Id: roleLookup.id
|
|
}
|
|
await TeamMembers.create(join)
|
|
await TeamMemberRole.create(roleUser)
|
|
res.status(200)
|
|
res.json({success: true})
|
|
} else {
|
|
let join = {
|
|
userId: req.userData.UserId,
|
|
teamId: team.id,
|
|
roles: {"deprecated": "deprecated"}
|
|
}
|
|
console.log(role)
|
|
let roleUser = {
|
|
UserId: req.userData.UserId,
|
|
TeamId: team.id,
|
|
RoleId: role.id
|
|
}
|
|
await TeamMembers.create(join)
|
|
await TeamMemberRole.create(roleUser)
|
|
res.status(200)
|
|
res.json({success: true})
|
|
}
|
|
} else {
|
|
let join = {
|
|
userId: req.userData.UserId,
|
|
teamId: team.id,
|
|
roles: {"deprecated": "deprecated"}
|
|
}
|
|
console.log(role)
|
|
let roleUser = {
|
|
UserId: req.userData.UserId,
|
|
TeamId: team.id,
|
|
RoleId: role.id
|
|
}
|
|
await TeamMembers.create(join)
|
|
await TeamMemberRole.create(roleUser)
|
|
res.status(200)
|
|
res.json({success: true})
|
|
}
|
|
} else if(code.uses < code.maxUses) {
|
|
let role = await TeamRoles.findOne({
|
|
where: {teamId: team.id, name: "Members"}
|
|
})
|
|
let join = {
|
|
userId: req.userData.UserId,
|
|
teamId: team.id,
|
|
roles: {"deprecated": "deprecated"}
|
|
}
|
|
console.log(role)
|
|
let roleUser = {
|
|
UserId: req.userData.UserId,
|
|
TeamId: team.id,
|
|
RoleId: role.id,
|
|
}
|
|
await TeamMembers.create(join)
|
|
await TeamMemberRole.create(roleUser)
|
|
res.status(200)
|
|
res.json({success: true})
|
|
} else {
|
|
throw Errors.inviteInvalid
|
|
}
|
|
} else {
|
|
throw Errors.inviteInvalid
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
module.exports = router;
|