1
0
mirror of https://github.com/sasjs/server.git synced 2026-01-07 22:50:05 +00:00

chore: swagger docs generated

This commit is contained in:
Saad Jutt
2021-11-04 18:47:40 +05:00
parent 728f277f5c
commit 882f36d30e
21 changed files with 1811 additions and 282 deletions

1
.gitignore vendored
View File

@@ -6,5 +6,6 @@ node_modules/
sas/ sas/
tmp/ tmp/
build/ build/
public/
certificates/ certificates/
.env .env

1572
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,9 +4,11 @@
"description": "SASjs server", "description": "SASjs server",
"main": "./src/server.ts", "main": "./src/server.ts",
"scripts": { "scripts": {
"prestart": "npm run swagger",
"start": "nodemon ./src/server.ts", "start": "nodemon ./src/server.ts",
"start:prod": "nodemon ./src/prod-server.ts", "start:prod": "nodemon ./src/prod-server.ts",
"build": "rimraf build && tsc", "build": "rimraf build && tsc",
"swagger": "tsoa spec",
"semantic-release": "semantic-release -d", "semantic-release": "semantic-release -d",
"prepare": "[ -d .git ] && git config core.hooksPath ./.git-hooks || true", "prepare": "[ -d .git ] && git config core.hooksPath ./.git-hooks || true",
"test": "mkdir -p tmp && jest --coverage", "test": "mkdir -p tmp && jest --coverage",
@@ -27,16 +29,21 @@
"joi": "^17.4.2", "joi": "^17.4.2",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"mongoose": "^6.0.12", "mongoose": "^6.0.12",
"multer": "^1.4.3" "morgan": "^1.10.0",
"multer": "^1.4.3",
"swagger-ui-express": "^4.1.6",
"tsoa": "^3.14.0"
}, },
"devDependencies": { "devDependencies": {
"@types/bcryptjs": "^2.4.2", "@types/bcryptjs": "^2.4.2",
"@types/express": "^4.17.12", "@types/express": "^4.17.12",
"@types/jest": "^26.0.24", "@types/jest": "^26.0.24",
"@types/jsonwebtoken": "^8.5.5", "@types/jsonwebtoken": "^8.5.5",
"@types/morgan": "^1.9.3",
"@types/multer": "^1.4.7", "@types/multer": "^1.4.7",
"@types/node": "^15.12.2", "@types/node": "^15.12.2",
"@types/supertest": "^2.0.11", "@types/supertest": "^2.0.11",
"@types/swagger-ui-express": "^4.1.3",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"jest": "^27.0.6", "jest": "^27.0.6",
"mongodb-memory-server": "^8.0.0", "mongodb-memory-server": "^8.0.0",

View File

@@ -1,10 +1,13 @@
import express from 'express' import express from 'express'
import morgan from 'morgan'
import webRouter from './routes/web' import webRouter from './routes/web'
import apiRouter from './routes/api' import apiRouter from './routes/api'
const app = express() const app = express()
app.use(express.json({ limit: '50mb' })) app.use(express.json({ limit: '50mb' }))
app.use(morgan('tiny'))
app.use(express.static('public'))
app.use('/', webRouter) app.use('/', webRouter)
app.use('/SASjsApi', apiRouter) app.use('/SASjsApi', apiRouter)

View File

@@ -1,32 +0,0 @@
import bcrypt from 'bcryptjs'
import User from '../model/User'
export const createUser = async (data: any) => {
const { displayName, username, password, isAdmin, isActive } = data
// Checking if user is already in the database
const usernameExist = await User.findOne({ username })
if (usernameExist) throw new Error('Username already exists.')
// Hash passwords
const salt = await bcrypt.genSalt(10)
const hashPassword = await bcrypt.hash(password, salt)
// Create a new user
const user = new User({
displayName,
username,
password: hashPassword,
isAdmin,
isActive
})
const savedUser = await user.save()
return {
displayName: savedUser.displayName,
username: savedUser.username,
isAdmin: savedUser.isAdmin,
isActive: savedUser.isActive
}
}

View File

@@ -1,20 +0,0 @@
import bcrypt from 'bcryptjs'
import User from '../model/User'
export const deleteUser = async (
username: string,
isAdmin: boolean,
data: any
) => {
const { password } = data
const user = await User.findOne({ username })
if (!user) throw new Error('Username is not found.')
if (!isAdmin) {
const validPass = await bcrypt.compare(password, user.password)
if (!validPass) throw new Error('Invalid password.')
}
await User.deleteOne({ username })
}

View File

@@ -1,35 +0,0 @@
import bcrypt from 'bcryptjs'
import User from '../model/User'
export const updateUser = async (currentUsername: string, data: any) => {
const { displayName, username, password, isAdmin, isActive } = data
const params: any = { displayName, isAdmin, isActive }
if (username && currentUsername !== username) {
// Checking if username is already in the database
const usernameExist = await User.findOne({ username })
if (usernameExist) throw new Error('Username already exists.')
params.username = username
}
if (password) {
// Hash passwords
const salt = await bcrypt.genSalt(10)
params.password = await bcrypt.hash(password, salt)
}
const updatedUser = await User.findOneAndUpdate(
{ username: currentUsername },
params,
{ new: true }
)
return {
displayName: updatedUser.displayName,
username: updatedUser.username,
isAdmin: updatedUser.isAdmin,
isActive: updatedUser.isActive
}
}

180
src/controllers/user.ts Normal file
View File

@@ -0,0 +1,180 @@
import {
Route,
Path,
Query,
Example,
Get,
Post,
Patch,
Delete,
Body,
Hidden
} from 'tsoa'
import bcrypt from 'bcryptjs'
import User, { UserPayload } from '../model/User'
interface userResponse {
username: string
displayName: string
}
interface userDetailsResponse {
displayName: string
username: string
isActive: boolean
isAdmin: boolean
}
@Route('user')
export default class UserController {
/**
* Get list of all users (username, displayname). All users can request this.
*
*/
@Example<userResponse[]>([
{
username: 'johnusername',
displayName: 'John'
},
{
username: 'starkusername',
displayName: 'Stark'
}
])
@Get('/')
public async getAllUsers(): Promise<userResponse[]> {
return getAllUsers()
}
/**
* Create user with the following attributes: UserId, UserName, Password, isAdmin, isActive. Admin only task.
*
*/
@Example<userDetailsResponse>({
displayName: 'John Snow',
username: 'johnSnow01',
isAdmin: false,
isActive: true
})
@Post('/')
public async createUser(
@Body() body: UserPayload
): Promise<userDetailsResponse> {
return createUser(body)
}
/**
* Update user properties - such as displayName. Can be performed either by admins, or the user in question.
* @param username The user's identifier
* @example username "johnSnow01"
*/
@Example<userDetailsResponse>({
displayName: 'John Snow',
username: 'johnSnow01',
isAdmin: false,
isActive: true
})
@Patch('{username}')
public async updateUser(
@Path() username: string,
@Body() body: UserPayload
): Promise<userDetailsResponse> {
return updateUser(username, body)
}
/**
* Delete a user. Can be performed either by admins, or the user in question.
* @param username The user's identifier
* @example username "johnSnow01"
*/
@Delete('{username}')
public async deleteUser(
@Path() username: string,
@Body() body: { password?: string },
@Query() @Hidden() isAdmin: boolean = false
) {
return deleteUser(username, isAdmin, body)
}
}
const getAllUsers = async () =>
await User.find({}).select({ _id: 0, username: 1, displayName: 1 }).exec()
const createUser = async (data: any): Promise<userDetailsResponse> => {
const { displayName, username, password, isAdmin, isActive } = data
// Checking if user is already in the database
const usernameExist = await User.findOne({ username })
if (usernameExist) throw new Error('Username already exists.')
// Hash passwords
const salt = await bcrypt.genSalt(10)
const hashPassword = await bcrypt.hash(password, salt)
// Create a new user
const user = new User({
displayName,
username,
password: hashPassword,
isAdmin,
isActive
})
const savedUser = await user.save()
return {
displayName: savedUser.displayName,
username: savedUser.username,
isAdmin: savedUser.isAdmin,
isActive: savedUser.isActive
}
}
const updateUser = async (currentUsername: string, data: any) => {
const { displayName, username, password, isAdmin, isActive } = data
const params: any = { displayName, isAdmin, isActive }
if (username && currentUsername !== username) {
// Checking if username is already in the database
const usernameExist = await User.findOne({ username })
if (usernameExist) throw new Error('Username already exists.')
params.username = username
}
if (password) {
// Hash passwords
const salt = await bcrypt.genSalt(10)
params.password = await bcrypt.hash(password, salt)
}
const updatedUser = await User.findOneAndUpdate(
{ username: currentUsername },
params,
{ new: true }
)
if (!updatedUser) throw new Error('Unable to update user')
return {
displayName: updatedUser.displayName,
username: updatedUser.username,
isAdmin: updatedUser.isAdmin,
isActive: updatedUser.isActive
}
}
const deleteUser = async (username: string, isAdmin: boolean, data: any) => {
const { password } = data
const user = await User.findOne({ username })
if (!user) throw new Error('Username is not found.')
if (!isAdmin) {
const validPass = await bcrypt.compare(password, user.password)
if (!validPass) throw new Error('Invalid password.')
}
await User.deleteOne({ username })
}

View File

@@ -1,2 +1,3 @@
export * from './authenticateToken' export * from './authenticateToken'
export * from './verifyAdmin' export * from './verifyAdmin'
export * from './verifyAdminIfNeeded'

View File

@@ -0,0 +1,9 @@
export const verifyAdminIfNeeded = (req: any, res: any, next: any) => {
const { user } = req
const { username } = req.params
if (!user.isAdmin && user.username !== username) {
return res.status(401).send('Admin account required')
}
next()
}

View File

@@ -1,42 +1,76 @@
import mongoose from 'mongoose' import { Schema, model } from 'mongoose'
const userSchema = new mongoose.Schema({ export interface UserPayload {
displayName: { /**
type: String, * Display name for user
required: true * @example "John Snow"
}, */
username: { displayName: string
type: String, /**
required: true * Username for user
}, * @example "johnSnow01"
password: { */
type: String, username: string
required: true /**
}, * Password for user
isAdmin: { */
type: Boolean, password: string
default: false /**
}, * Account should be admin or not, defaults to false
isActive: { * @example "false"
type: Boolean, */
default: true isAdmin?: boolean
}, /**
tokens: [ * Account should be active or not, defaults to true
{ * @example "true"
clientId: { */
type: String, isActive?: boolean
required: true }
},
accessToken: { interface UserSchema extends UserPayload {
type: String, isAdmin: boolean
required: true isActive: boolean
}, tokens: [{ [key: string]: string }]
refreshToken: { }
type: String,
required: true export default model(
'User',
new Schema<UserSchema>({
displayName: {
type: String,
required: true
},
username: {
type: String,
required: true
},
password: {
type: String,
required: true
},
isAdmin: {
type: Boolean,
default: false
},
isActive: {
type: Boolean,
default: true
},
tokens: [
{
clientId: {
type: String,
required: true
},
accessToken: {
type: String,
required: true
},
refreshToken: {
type: String,
required: true
}
} }
} ]
] })
}) )
export default mongoose.model('User', userSchema)

View File

@@ -1,5 +1,6 @@
import express from 'express' import express from 'express'
import dotenv from 'dotenv' import dotenv from 'dotenv'
import swaggerUi from 'swagger-ui-express'
import { authenticateAccessToken, verifyAdmin } from '../../middlewares' import { authenticateAccessToken, verifyAdmin } from '../../middlewares'
@@ -19,5 +20,14 @@ router.use('/stp', authenticateAccessToken, stpRouter)
router.use('/user', userRouter) router.use('/user', userRouter)
router.use('/client', authenticateAccessToken, verifyAdmin, clientRouter) router.use('/client', authenticateAccessToken, verifyAdmin, clientRouter)
router.use('/auth', authRouter) router.use('/auth', authRouter)
router.use(
'/',
swaggerUi.serve,
swaggerUi.setup(undefined, {
swaggerOptions: {
url: '/swagger.json'
}
})
)
export default router export default router

View File

@@ -2,7 +2,7 @@ import mongoose, { Mongoose } from 'mongoose'
import { MongoMemoryServer } from 'mongodb-memory-server' import { MongoMemoryServer } from 'mongodb-memory-server'
import request from 'supertest' import request from 'supertest'
import app from '../../../app' import app from '../../../app'
import { createUser } from '../../../controllers/createUser' import UserController from '../../../controllers/user'
import { createClient } from '../../../controllers/createClient' import { createClient } from '../../../controllers/createClient'
import { import {
generateAccessToken, generateAccessToken,
@@ -27,6 +27,7 @@ const user = {
describe('auth', () => { describe('auth', () => {
let con: Mongoose let con: Mongoose
let mongoServer: MongoMemoryServer let mongoServer: MongoMemoryServer
const userController = new UserController()
beforeAll(async () => { beforeAll(async () => {
mongoServer = await MongoMemoryServer.create() mongoServer = await MongoMemoryServer.create()
@@ -49,7 +50,7 @@ describe('auth', () => {
}) })
it('should respond with authorization code', async () => { it('should respond with authorization code', async () => {
await createUser(user) await userController.createUser(user)
const res = await request(app) const res = await request(app)
.post('/SASjsApi/auth/authorize') .post('/SASjsApi/auth/authorize')
@@ -117,7 +118,7 @@ describe('auth', () => {
}) })
it('should respond with Forbidden if password is incorrect', async () => { it('should respond with Forbidden if password is incorrect', async () => {
await createUser(user) await userController.createUser(user)
const res = await request(app) const res = await request(app)
.post('/SASjsApi/auth/authorize') .post('/SASjsApi/auth/authorize')
@@ -133,7 +134,7 @@ describe('auth', () => {
}) })
it('should respond with Forbidden if clientId is incorrect', async () => { it('should respond with Forbidden if clientId is incorrect', async () => {
await createUser(user) await userController.createUser(user)
const res = await request(app) const res = await request(app)
.post('/SASjsApi/auth/authorize') .post('/SASjsApi/auth/authorize')
@@ -155,7 +156,7 @@ describe('auth', () => {
username: user.username username: user.username
} }
beforeAll(async () => { beforeAll(async () => {
await createUser(user) await userController.createUser(user)
}) })
afterAll(async () => { afterAll(async () => {
const collections = mongoose.connection.collections const collections = mongoose.connection.collections
@@ -250,7 +251,7 @@ describe('auth', () => {
}) })
beforeEach(async () => { beforeEach(async () => {
await createUser(user) await userController.createUser(user)
await saveTokensInDB(user.username, clientId, 'accessToken', refreshToken) await saveTokensInDB(user.username, clientId, 'accessToken', refreshToken)
}) })
@@ -294,7 +295,7 @@ describe('auth', () => {
}) })
beforeEach(async () => { beforeEach(async () => {
await createUser(user) await userController.createUser(user)
await saveTokensInDB(user.username, clientId, accessToken, 'refreshToken') await saveTokensInDB(user.username, clientId, accessToken, 'refreshToken')
}) })

View File

@@ -3,8 +3,8 @@ import { MongoMemoryServer } from 'mongodb-memory-server'
import request from 'supertest' import request from 'supertest'
import app from '../../../app' import app from '../../../app'
import { createClient } from '../../../controllers/createClient' import { createClient } from '../../../controllers/createClient'
import UserController from '../../../controllers/user'
import { generateAccessToken } from '../auth' import { generateAccessToken } from '../auth'
import { createUser } from '../../../controllers/createUser'
import { saveTokensInDB } from '../../../utils' import { saveTokensInDB } from '../../../utils'
const client = { const client = {
@@ -23,9 +23,10 @@ const newClient = {
clientSecret: 'newClientSecret' clientSecret: 'newClientSecret'
} }
describe('user', () => { describe('client', () => {
let con: Mongoose let con: Mongoose
let mongoServer: MongoMemoryServer let mongoServer: MongoMemoryServer
const userController = new UserController()
beforeAll(async () => { beforeAll(async () => {
mongoServer = await MongoMemoryServer.create() mongoServer = await MongoMemoryServer.create()
@@ -45,7 +46,7 @@ describe('user', () => {
}) })
beforeAll(async () => { beforeAll(async () => {
await createUser(adminUser) await userController.createUser(adminUser)
await saveTokensInDB( await saveTokensInDB(
adminUser.username, adminUser.username,
client.clientId, client.clientId,
@@ -93,7 +94,7 @@ describe('user', () => {
clientId: client.clientId, clientId: client.clientId,
username: user.username username: user.username
}) })
await createUser(user) await userController.createUser(user)
await saveTokensInDB( await saveTokensInDB(
user.username, user.username,
client.clientId, client.clientId,
@@ -105,7 +106,7 @@ describe('user', () => {
.post('/SASjsApi/client') .post('/SASjsApi/client')
.auth(accessToken, { type: 'bearer' }) .auth(accessToken, { type: 'bearer' })
.send(newClient) .send(newClient)
.expect(403) .expect(401)
expect(res.text).toEqual('Admin account required') expect(res.text).toEqual('Admin account required')
expect(res.body).toEqual({}) expect(res.body).toEqual({})

View File

@@ -3,11 +3,11 @@ import { MongoMemoryServer } from 'mongodb-memory-server'
import request from 'supertest' import request from 'supertest'
import app from '../../../app' import app from '../../../app'
import { getTreeExample } from '../../../controllers/deploy' import { getTreeExample } from '../../../controllers/deploy'
import UserController from '../../../controllers/user'
import { getTmpFilesFolderPath } from '../../../utils/file' import { getTmpFilesFolderPath } from '../../../utils/file'
import { folderExists, fileExists, readFile, deleteFolder } from '@sasjs/utils' import { folderExists, fileExists, readFile, deleteFolder } from '@sasjs/utils'
import path from 'path' import path from 'path'
import { generateAccessToken } from '../auth' import { generateAccessToken } from '../auth'
import { createUser } from '../../../controllers/createUser'
import { saveTokensInDB } from '../../../utils' import { saveTokensInDB } from '../../../utils'
const clientId = 'someclientID' const clientId = 'someclientID'
@@ -22,6 +22,7 @@ const user = {
describe('files', () => { describe('files', () => {
let con: Mongoose let con: Mongoose
let mongoServer: MongoMemoryServer let mongoServer: MongoMemoryServer
const controller = new UserController()
beforeAll(async () => { beforeAll(async () => {
mongoServer = await MongoMemoryServer.create() mongoServer = await MongoMemoryServer.create()
@@ -40,7 +41,7 @@ describe('files', () => {
}) })
beforeAll(async () => { beforeAll(async () => {
await createUser(user) await controller.createUser(user)
await saveTokensInDB(user.username, clientId, accessToken, 'refreshToken') await saveTokensInDB(user.username, clientId, accessToken, 'refreshToken')
}) })
const shouldFailAssertion = async (payload: any) => { const shouldFailAssertion = async (payload: any) => {

View File

@@ -2,7 +2,7 @@ import mongoose, { Mongoose } from 'mongoose'
import { MongoMemoryServer } from 'mongodb-memory-server' import { MongoMemoryServer } from 'mongodb-memory-server'
import request from 'supertest' import request from 'supertest'
import app from '../../../app' import app from '../../../app'
import { createUser } from '../../../controllers/createUser' import UserController from '../../../controllers/user'
import { generateAccessToken } from '../auth' import { generateAccessToken } from '../auth'
import { saveTokensInDB } from '../../../utils' import { saveTokensInDB } from '../../../utils'
@@ -25,6 +25,7 @@ const user = {
describe('user', () => { describe('user', () => {
let con: Mongoose let con: Mongoose
let mongoServer: MongoMemoryServer let mongoServer: MongoMemoryServer
const controller = new UserController()
beforeAll(async () => { beforeAll(async () => {
mongoServer = await MongoMemoryServer.create() mongoServer = await MongoMemoryServer.create()
@@ -44,7 +45,7 @@ describe('user', () => {
}) })
beforeEach(async () => { beforeEach(async () => {
await createUser(adminUser) await controller.createUser(adminUser)
await saveTokensInDB( await saveTokensInDB(
adminUser.username, adminUser.username,
clientId, clientId,
@@ -87,21 +88,21 @@ describe('user', () => {
clientId, clientId,
username: user.username username: user.username
}) })
await createUser(user) await controller.createUser(user)
await saveTokensInDB(user.username, clientId, accessToken, 'refreshToken') await saveTokensInDB(user.username, clientId, accessToken, 'refreshToken')
const res = await request(app) const res = await request(app)
.post('/SASjsApi/user') .post('/SASjsApi/user')
.auth(accessToken, { type: 'bearer' }) .auth(accessToken, { type: 'bearer' })
.send(user) .send(user)
.expect(403) .expect(401)
expect(res.text).toEqual('Admin account required') expect(res.text).toEqual('Admin account required')
expect(res.body).toEqual({}) expect(res.body).toEqual({})
}) })
it('should respond with Forbidden if username is already present', async () => { it('should respond with Forbidden if username is already present', async () => {
await createUser(user) await controller.createUser(user)
const res = await request(app) const res = await request(app)
.post('/SASjsApi/user') .post('/SASjsApi/user')

View File

@@ -1,8 +1,10 @@
import express from 'express' import express from 'express'
import { createUser } from '../../controllers/createUser' import UserController from '../../controllers/user'
import { updateUser } from '../../controllers/updateUser' import {
import { deleteUser } from '../../controllers/deleteUser' authenticateAccessToken,
import { authenticateAccessToken, verifyAdmin } from '../../middlewares' verifyAdmin,
verifyAdminIfNeeded
} from '../../middlewares'
import User from '../../model/User' import User from '../../model/User'
import { import {
deleteUserValidation, deleteUserValidation,
@@ -12,29 +14,31 @@ import {
const userRouter = express.Router() const userRouter = express.Router()
// create user
userRouter.post('/', authenticateAccessToken, verifyAdmin, async (req, res) => { userRouter.post('/', authenticateAccessToken, verifyAdmin, async (req, res) => {
const { error, value: data } = registerUserValidation(req.body) const { error, value: body } = registerUserValidation(req.body)
if (error) return res.status(400).send(error.details[0].message) if (error) return res.status(400).send(error.details[0].message)
const controller = new UserController()
try { try {
const savedUser = await createUser(data) const response = await controller.createUser(body)
res.send(savedUser) res.send(response)
} catch (err: any) { } catch (err: any) {
res.status(403).send(err.toString()) res.status(403).send(err.toString())
} }
}) })
userRouter.get('/', authenticateAccessToken, async (req, res) => { userRouter.get('/', authenticateAccessToken, async (req, res) => {
const controller = new UserController()
try { try {
const users = await User.find({}) const response = await controller.getAllUsers()
.select({ _id: 0, username: 1, displayName: 1, isAdmin: 1, isActive: 1 }) res.send(response)
.exec()
res.send(users)
} catch (err: any) { } catch (err: any) {
res.status(403).send(err.toString()) res.status(403).send(err.toString())
} }
}) })
// get one user
userRouter.get('/:username', authenticateAccessToken, async (req: any, res) => { userRouter.get('/:username', authenticateAccessToken, async (req: any, res) => {
const { username } = req.params const { username } = req.params
try { try {
@@ -47,48 +51,45 @@ userRouter.get('/:username', authenticateAccessToken, async (req: any, res) => {
} }
}) })
// update user
userRouter.patch( userRouter.patch(
'/:username', '/:username',
authenticateAccessToken, authenticateAccessToken,
verifyAdminIfNeeded,
async (req: any, res) => { async (req: any, res) => {
const { user } = req const { user } = req
const { username } = req.params const { username } = req.params
// only an admin can update other users
if (!user.isAdmin && user.username !== username) {
return res.status(401).send('Admin account required')
}
// only an admin can update `isActive` and `isAdmin` fields // only an admin can update `isActive` and `isAdmin` fields
const { error, value: data } = updateUserValidation(req.body, user.isAdmin) const { error, value: body } = updateUserValidation(req.body, user.isAdmin)
if (error) return res.status(400).send(error.details[0].message) if (error) return res.status(400).send(error.details[0].message)
const controller = new UserController()
try { try {
const user = await updateUser(username, data) const response = await controller.updateUser(username, body)
res.send(user) res.send(response)
} catch (err: any) { } catch (err: any) {
res.status(403).send(err.toString()) res.status(403).send(err.toString())
} }
} }
) )
// delete user
userRouter.delete( userRouter.delete(
'/:username', '/:username',
authenticateAccessToken, authenticateAccessToken,
verifyAdminIfNeeded,
async (req: any, res) => { async (req: any, res) => {
const { user } = req const { user } = req
const { username } = req.params const { username } = req.params
// only an admin can delete other users // only an admin can delete user without providing password
if (!user.isAdmin && user.username !== username) {
return res.status(401).send('Admin account required')
}
const { error, value: data } = deleteUserValidation(req.body, user.isAdmin) const { error, value: data } = deleteUserValidation(req.body, user.isAdmin)
if (error) return res.status(400).send(error.details[0].message) if (error) return res.status(400).send(error.details[0].message)
const controller = new UserController()
try { try {
await deleteUser(username, user.isAdmin, data) await controller.deleteUser(username, data, user.isAdmin)
res.status(200).send('Account Deleted!') res.status(200).send('Account Deleted!')
} catch (err: any) { } catch (err: any) {
res.status(403).send(err.toString()) res.status(403).send(err.toString())

View File

@@ -2,6 +2,7 @@ import User from '../model/User'
export const removeTokensInDB = async (username: string, clientId: string) => { export const removeTokensInDB = async (username: string, clientId: string) => {
const user = await User.findOne({ username }) const user = await User.findOne({ username })
if (!user) return
const tokenObjIndex = user.tokens.findIndex( const tokenObjIndex = user.tokens.findIndex(
(tokenObj: any) => tokenObj.clientId === clientId (tokenObj: any) => tokenObj.clientId === clientId

View File

@@ -7,6 +7,7 @@ export const saveTokensInDB = async (
refreshToken: string refreshToken: string
) => { ) => {
const user = await User.findOne({ username }) const user = await User.findOne({ username })
if (!user) return
const currentTokenObj = user.tokens.find( const currentTokenObj = user.tokens.find(
(tokenObj: any) => tokenObj.clientId === clientId (tokenObj: any) => tokenObj.clientId === clientId

View File

@@ -6,7 +6,9 @@
"outDir": "./build", "outDir": "./build",
"esModuleInterop": true, "esModuleInterop": true,
"strict": true, "strict": true,
"resolveJsonModule": true "resolveJsonModule": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}, },
"ts-node": { "ts-node": {
"files": true "files": true

8
tsoa.json Normal file
View File

@@ -0,0 +1,8 @@
{
"entryFile": "src/app.ts",
"noImplicitAdditionalProperties": "throw-on-extras",
"spec": {
"outputDirectory": "public",
"specVersion": 3
}
}