mirror of
https://github.com/hknsh/project-knedita.git
synced 2024-11-28 17:41:15 +00:00
Added Cookies for authentication.
This commit is contained in:
parent
ffcb719da1
commit
2607bd56ff
35 changed files with 113 additions and 5152 deletions
|
@ -1,17 +0,0 @@
|
||||||
import { pathsToModuleNameMapper } from 'ts-jest'
|
|
||||||
import { compilerOptions } from './tsconfig.json'
|
|
||||||
import type { JestConfigWithTsJest } from 'ts-jest'
|
|
||||||
|
|
||||||
const jestConfig: JestConfigWithTsJest = {
|
|
||||||
preset: 'ts-jest',
|
|
||||||
testEnvironment: 'node',
|
|
||||||
setupFilesAfterEnv: ['<rootDir>/setupTest.ts'],
|
|
||||||
transform: {
|
|
||||||
'^.+\\.(t|j)sx?$': '@swc/jest'
|
|
||||||
},
|
|
||||||
roots: ['<rootDir>'],
|
|
||||||
modulePaths: [compilerOptions.baseUrl],
|
|
||||||
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default jestConfig
|
|
4735
package-lock.json
generated
4735
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -16,8 +16,7 @@
|
||||||
"prisma:generate": "npx prisma generate",
|
"prisma:generate": "npx prisma generate",
|
||||||
"prisma:seed": "prisma db seed",
|
"prisma:seed": "prisma db seed",
|
||||||
"prisma:studio": "npx prisma studio",
|
"prisma:studio": "npx prisma studio",
|
||||||
"prod:start": "npx prisma migrate deploy && pm2-runtime start dist/server.js",
|
"prod:start": "npx prisma migrate deploy && pm2-runtime start dist/server.js"
|
||||||
"test": "jest"
|
|
||||||
},
|
},
|
||||||
"ts-standard": {
|
"ts-standard": {
|
||||||
"project": "tsconfig.json",
|
"project": "tsconfig.json",
|
||||||
|
@ -32,13 +31,12 @@
|
||||||
"@faker-js/faker": "^8.0.2",
|
"@faker-js/faker": "^8.0.2",
|
||||||
"@swc/cli": "^0.1.62",
|
"@swc/cli": "^0.1.62",
|
||||||
"@swc/core": "^1.3.66",
|
"@swc/core": "^1.3.66",
|
||||||
"@swc/jest": "^0.2.26",
|
|
||||||
"@types/bcrypt": "^5.0.0",
|
"@types/bcrypt": "^5.0.0",
|
||||||
"@types/compression": "^1.7.2",
|
"@types/compression": "^1.7.2",
|
||||||
|
"@types/cookie-parser": "^1.4.3",
|
||||||
"@types/cors": "^2.8.13",
|
"@types/cors": "^2.8.13",
|
||||||
"@types/dotenv": "^8.2.0",
|
"@types/dotenv": "^8.2.0",
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
"@types/jest": "^29.5.2",
|
|
||||||
"@types/jsonwebtoken": "^9.0.2",
|
"@types/jsonwebtoken": "^9.0.2",
|
||||||
"@types/morgan": "^1.9.4",
|
"@types/morgan": "^1.9.4",
|
||||||
"@types/multer-s3": "^3.0.0",
|
"@types/multer-s3": "^3.0.0",
|
||||||
|
@ -53,13 +51,11 @@
|
||||||
"eslint-plugin-import": "^2.28.0",
|
"eslint-plugin-import": "^2.28.0",
|
||||||
"eslint-plugin-n": "^16.0.1",
|
"eslint-plugin-n": "^16.0.1",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"jest": "^29.6.2",
|
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
"pm2": "^4.2.3",
|
"pm2": "^4.2.3",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"prisma": "^5.0.0",
|
"prisma": "^5.0.0",
|
||||||
"supertest": "^6.3.3",
|
"supertest": "^6.3.3",
|
||||||
"ts-jest": "^29.1.0",
|
|
||||||
"ts-node-dev": "^2.0.0",
|
"ts-node-dev": "^2.0.0",
|
||||||
"tsconfig-paths": "^4.2.0",
|
"tsconfig-paths": "^4.2.0",
|
||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
|
@ -69,6 +65,7 @@
|
||||||
"aws-sdk": "^2.1414.0",
|
"aws-sdk": "^2.1414.0",
|
||||||
"bcrypt": "^5.1.0",
|
"bcrypt": "^5.1.0",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
|
"cookie-parser": "^1.4.6",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import prisma from './src/clients/prisma-client'
|
|
||||||
import redis from './src/clients/redis-client'
|
|
||||||
|
|
||||||
process.env.NODE_ENV = 'development'
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
await redis.disconnect()
|
|
||||||
await prisma.$disconnect()
|
|
||||||
})
|
|
4
src/@types/express.d.ts
vendored
4
src/@types/express.d.ts
vendored
|
@ -1,12 +1,8 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import * as express from 'express'
|
import * as express from 'express'
|
||||||
import type jwtPayload from '../interfaces/jwt'
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
namespace Express {
|
namespace Express {
|
||||||
interface Request {
|
|
||||||
user: jwtPayload | undefined
|
|
||||||
}
|
|
||||||
namespace Multer {
|
namespace Multer {
|
||||||
interface File {
|
interface File {
|
||||||
location: string
|
location: string
|
||||||
|
|
|
@ -6,6 +6,7 @@ import express from 'express'
|
||||||
import limiter from 'middlewares/rate-limit'
|
import limiter from 'middlewares/rate-limit'
|
||||||
import morganMiddleware from 'middlewares/morgan'
|
import morganMiddleware from 'middlewares/morgan'
|
||||||
import router from './routes'
|
import router from './routes'
|
||||||
|
import cookieParser from 'cookie-parser'
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ const app = express()
|
||||||
|
|
||||||
app.use(express.json())
|
app.use(express.json())
|
||||||
app.use(express.urlencoded({ extended: true }))
|
app.use(express.urlencoded({ extended: true }))
|
||||||
|
app.use(cookieParser())
|
||||||
app.use(morganMiddleware)
|
app.use(morganMiddleware)
|
||||||
app.use(limiter)
|
app.use(limiter)
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
|
|
@ -15,7 +15,7 @@ const storageTypes = {
|
||||||
filename: (req: Request, file: Express.Multer.File, callback) => {
|
filename: (req: Request, file: Express.Multer.File, callback) => {
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
const folder = req.body.isProfilePicture ? 'profile_images' : 'media'
|
const folder = req.body.isProfilePicture ? 'profile_images' : 'media'
|
||||||
const fileName: string = `${folder}/${req.user!.id}.webp`
|
const fileName: string = `${folder}/${req.res?.locals.user.id}.webp`
|
||||||
|
|
||||||
callback(null, fileName)
|
callback(null, fileName)
|
||||||
},
|
},
|
||||||
|
@ -35,7 +35,7 @@ const storageTypes = {
|
||||||
folder = 'media'
|
folder = 'media'
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileName: string = `${folder}/${req.user!.id}.jpg`
|
const fileName: string = `${folder}/${req.res?.locals.user.id}.jpg`
|
||||||
callback(null, fileName)
|
callback(null, fileName)
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -8,7 +8,7 @@ async function commentCreateController (
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { content, postId } = req.body
|
const { content, postId } = req.body
|
||||||
const id = req.user?.id ?? ''
|
const id = res.locals.user.id
|
||||||
|
|
||||||
if (postId === undefined) {
|
if (postId === undefined) {
|
||||||
badRequest(res, 'Expected post id'); return
|
badRequest(res, 'Expected post id'); return
|
||||||
|
|
|
@ -8,7 +8,7 @@ async function commentDeleteController (
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { commentId } = req.body
|
const { commentId } = req.body
|
||||||
const id = req.user?.id ?? ''
|
const id = res.locals.user.id
|
||||||
|
|
||||||
if (commentId === undefined) {
|
if (commentId === undefined) {
|
||||||
badRequest(res, 'Expected comment id'); return
|
badRequest(res, 'Expected comment id'); return
|
||||||
|
|
|
@ -8,7 +8,7 @@ async function commentUpdateController (
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { commentId, content } = req.body
|
const { commentId, content } = req.body
|
||||||
const id = req.user?.id ?? ''
|
const id = res.locals.user.id
|
||||||
|
|
||||||
if (commentId === undefined) {
|
if (commentId === undefined) {
|
||||||
badRequest(res, 'Expected comment content'); return
|
badRequest(res, 'Expected comment content'); return
|
||||||
|
|
|
@ -8,7 +8,7 @@ async function postCreateController (
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { content } = req.body
|
const { content } = req.body
|
||||||
const id: string = req.user?.id ?? ''
|
const id = res.locals.user.id
|
||||||
|
|
||||||
if (content === undefined) {
|
if (content === undefined) {
|
||||||
badRequest(res, 'Expected post content'); return
|
badRequest(res, 'Expected post content'); return
|
||||||
|
|
|
@ -7,7 +7,7 @@ async function postDeleteController (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const userId = req.user?.id ?? ''
|
const userId = res.locals.user.id
|
||||||
const postId = req.body.postId
|
const postId = req.body.postId
|
||||||
|
|
||||||
if (postId === undefined) {
|
if (postId === undefined) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ async function postUpdateController (
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { postId, content } = req.body
|
const { postId, content } = req.body
|
||||||
const userId = req.user?.id ?? ''
|
const userId = res.locals.user.id
|
||||||
|
|
||||||
const result = await post.update(postId, content, userId)
|
const result = await post.update(postId, content, userId)
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,21 @@
|
||||||
import user from 'services/users'
|
import user from 'services/users'
|
||||||
import type { Request, Response } from 'express'
|
import type { Request, Response } from 'express'
|
||||||
import handleResponse from 'helpers/handle-response'
|
import { badRequest } from 'helpers/http-errors'
|
||||||
|
|
||||||
async function userAuthController (req: Request, res: Response): Promise<void> {
|
async function userAuthController (req: Request, res: Response): Promise<void> {
|
||||||
const { email, password } = req.body
|
const { email, password } = req.body
|
||||||
|
|
||||||
const result = await user.auth({ email, password })
|
const result = await user.auth({ email, password })
|
||||||
|
|
||||||
handleResponse(res, result)
|
if (result instanceof Error) {
|
||||||
|
badRequest(res, result.message)
|
||||||
|
} else {
|
||||||
|
res.cookie('token', result.token, {
|
||||||
|
httpOnly: true,
|
||||||
|
secure: process.env.NODE_ENV === 'production'
|
||||||
|
}).status(200)
|
||||||
|
.json({ message: 'Logged in successfully' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default userAuthController
|
export default userAuthController
|
||||||
|
|
|
@ -6,7 +6,7 @@ async function userDeleteController (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const userId = req.user?.id ?? ''
|
const userId = res.locals.user.id
|
||||||
const result = await user.delete(userId)
|
const result = await user.delete(userId)
|
||||||
|
|
||||||
handleResponse(res, result)
|
handleResponse(res, result)
|
||||||
|
|
|
@ -6,7 +6,7 @@ async function userFollowController (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const userId = req.user?.id ?? ''
|
const userId = res.locals.user.id
|
||||||
const { userToFollow } = req.body
|
const { userToFollow } = req.body
|
||||||
|
|
||||||
const result = await user.follow(userId, userToFollow)
|
const result = await user.follow(userId, userToFollow)
|
||||||
|
|
|
@ -6,7 +6,7 @@ async function userLikeCommentController (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const userId = req.user?.id ?? ''
|
const userId = res.locals.user.id
|
||||||
const { commentId } = req.body
|
const { commentId } = req.body
|
||||||
|
|
||||||
const result = await user.likeComment(commentId, userId)
|
const result = await user.likeComment(commentId, userId)
|
||||||
|
|
|
@ -6,7 +6,7 @@ async function userLikePostController (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const userId = req.user?.id ?? ''
|
const userId = res.locals.user.id
|
||||||
const { postId } = req.body
|
const { postId } = req.body
|
||||||
|
|
||||||
const result = await user.likePost(postId, userId)
|
const result = await user.likePost(postId, userId)
|
||||||
|
|
|
@ -7,7 +7,7 @@ async function userUpdateEmailController (
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { email } = req.body
|
const { email } = req.body
|
||||||
const id = req.user?.id ?? ''
|
const id = res.locals.user.id
|
||||||
|
|
||||||
const result = await user.updateEmail({ id, email })
|
const result = await user.updateEmail({ id, email })
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ async function userUpdateNameController (
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { displayName, username } = req.body
|
const { displayName, username } = req.body
|
||||||
const id = req.user?.id ?? ''
|
const id = res.locals.user.id
|
||||||
|
|
||||||
const result = await user.updateName({ id, displayName, username })
|
const result = await user.updateName({ id, displayName, username })
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ async function userUpdatePasswordController (
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { currentPassword, newPassword } = req.body
|
const { currentPassword, newPassword } = req.body
|
||||||
const id = req.user?.id ?? ''
|
const id = res.locals.user.id
|
||||||
|
|
||||||
const result = await user.updatePassword(id, currentPassword, newPassword)
|
const result = await user.updatePassword(id, currentPassword, newPassword)
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ async function userUploadPictureController (
|
||||||
badRequest(res, 'Expected a JPG or PNG file'); return
|
badRequest(res, 'Expected a JPG or PNG file'); return
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = req.user?.id ?? ''
|
const userId = res.locals.user.id
|
||||||
|
|
||||||
let url: string
|
let url: string
|
||||||
|
|
||||||
|
|
|
@ -1,55 +1,41 @@
|
||||||
import { verify } from 'jsonwebtoken'
|
import { verify } from 'jsonwebtoken'
|
||||||
import prisma from 'clients/prisma-client'
|
import prisma from 'clients/prisma-client'
|
||||||
import type { Response, Request, NextFunction } from 'express'
|
import type { Response, Request, NextFunction } from 'express'
|
||||||
import type jwtPayload from 'interfaces/jwt'
|
|
||||||
import { unauthorized } from 'helpers/http-errors'
|
import { unauthorized } from 'helpers/http-errors'
|
||||||
|
import type jwtPayload from 'interfaces/jwt'
|
||||||
|
|
||||||
async function authenticated (
|
async function authenticated (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (
|
try {
|
||||||
req.headers.authorization === undefined ||
|
const token = req.cookies.token
|
||||||
req.headers.authorization.length === 0
|
|
||||||
) {
|
if (token === undefined) {
|
||||||
unauthorized(res, 'Missing token'); return
|
unauthorized(res, 'Missing token'); return
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = req.headers.authorization.split(' ')[1]
|
const { id } = verify(token, process.env.JWT_ACCESS_SECRET ?? '') as jwtPayload
|
||||||
|
|
||||||
try {
|
if (id === undefined) {
|
||||||
const decoded = await new Promise<jwtPayload | undefined>(
|
|
||||||
(resolve, reject) => {
|
|
||||||
verify(token, process.env.JWT_ACCESS_SECRET ?? '', (error, decoded) => {
|
|
||||||
if (error != null) {
|
|
||||||
reject(error)
|
|
||||||
} else {
|
|
||||||
resolve(decoded as jwtPayload)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (decoded == null) {
|
|
||||||
unauthorized(res, 'Invalid token'); return
|
unauthorized(res, 'Invalid token'); return
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await prisma.user.findFirst({
|
const user = await prisma.user.findFirst({
|
||||||
where: {
|
where: {
|
||||||
id: decoded.id
|
id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (user == null) {
|
if (user === undefined) {
|
||||||
unauthorized(res, 'User does not exists'); return
|
unauthorized(res, 'User does not exists'); return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.user = decoded
|
res.locals.user = user
|
||||||
|
|
||||||
next()
|
next()
|
||||||
} catch (error) {
|
} catch (e) {
|
||||||
unauthorized(res, `JWT Error: ${(error as Error).message}`)
|
unauthorized(res, `JWT Error: ${(e as Error).message}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ function uploadImage (req: Request, res: Response, next: NextFunction): void {
|
||||||
const upload = multer(multerConfig).single('image')
|
const upload = multer(multerConfig).single('image')
|
||||||
|
|
||||||
upload(req, res, async (cb: multer.MulterError | Error | any) => {
|
upload(req, res, async (cb: multer.MulterError | Error | any) => {
|
||||||
if (req.user == null) {
|
if (req.res?.locals.user == null) {
|
||||||
badRequest(
|
badRequest(
|
||||||
res,
|
res,
|
||||||
'You must be logged in to upload a profile picture'
|
'You must be logged in to upload a profile picture'
|
||||||
|
|
|
@ -3,6 +3,9 @@ import { createServer } from 'http'
|
||||||
import logger from 'helpers/logger'
|
import logger from 'helpers/logger'
|
||||||
import createSocketIOInstance from './socket'
|
import createSocketIOInstance from './socket'
|
||||||
|
|
||||||
|
import prisma from 'clients/prisma-client'
|
||||||
|
import redis from 'clients/redis-client'
|
||||||
|
|
||||||
const server = createServer(app)
|
const server = createServer(app)
|
||||||
const io = createSocketIOInstance(server)
|
const io = createSocketIOInstance(server)
|
||||||
|
|
||||||
|
@ -15,3 +18,10 @@ app.use((req, res, next) => {
|
||||||
server.listen(process.env.SERVER_PORT, () => {
|
server.listen(process.env.SERVER_PORT, () => {
|
||||||
logger.info(`Server is running @ ${process.env.SERVER_PORT ?? ''}`)
|
logger.info(`Server is running @ ${process.env.SERVER_PORT ?? ''}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
process.on('SIGINT', async () => {
|
||||||
|
logger.warn('Closing server...')
|
||||||
|
await prisma.$disconnect()
|
||||||
|
await redis.disconnect()
|
||||||
|
server.close()
|
||||||
|
})
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
import app from '../../app'
|
|
||||||
import request from 'supertest'
|
|
||||||
import signUpNewUser from '../utils/create-user'
|
|
||||||
import deleteUser from '../utils/delete-user'
|
|
||||||
import type User from 'interfaces/user'
|
|
||||||
|
|
||||||
let user: User
|
|
||||||
|
|
||||||
describe('POST /post/create', () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
user = await signUpNewUser()
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
await deleteUser(user.username!)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with 200 status code if the user send the token and the content', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.post('/post/create')
|
|
||||||
.send({
|
|
||||||
content: 'Hello world'
|
|
||||||
})
|
|
||||||
.set('Authorization', `Bearer ${user.token ?? ''}`)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
expect(response.body).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
content: expect.any(String),
|
|
||||||
authorId: expect.any(String),
|
|
||||||
createdAt: expect.any(String),
|
|
||||||
updatedAt: expect.any(String)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with 400 status code if the user send no token', async () => {
|
|
||||||
const response = await request(app).post('/post/create').expect(401)
|
|
||||||
|
|
||||||
expect(response.body).toHaveProperty('error')
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,36 +0,0 @@
|
||||||
import app from '../../app'
|
|
||||||
import request from 'supertest'
|
|
||||||
import signUpNewUser from '../utils/create-user'
|
|
||||||
import deleteUser from '../utils/delete-user'
|
|
||||||
import type User from 'interfaces/user'
|
|
||||||
|
|
||||||
let user: User
|
|
||||||
|
|
||||||
describe('DELETE /post/delete', () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
user = await signUpNewUser()
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
await deleteUser(user.username!)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should delete the post successfully', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.post('/post/create')
|
|
||||||
.send({
|
|
||||||
content: 'lorem ipsum'
|
|
||||||
})
|
|
||||||
.set('Authorization', `Bearer ${user.token ?? ''}`)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.post('/post/delete')
|
|
||||||
.send({
|
|
||||||
postId: response.body.id
|
|
||||||
})
|
|
||||||
.set('Authorization', `Bearer ${user.token ?? ''}`)
|
|
||||||
.expect(200)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,54 +0,0 @@
|
||||||
import app from '../../app'
|
|
||||||
import request from 'supertest'
|
|
||||||
import signUpNewUser from '../utils/create-user'
|
|
||||||
import deleteUser from '../utils/delete-user'
|
|
||||||
import type User from 'interfaces/user'
|
|
||||||
|
|
||||||
let postId: string
|
|
||||||
|
|
||||||
let user: User
|
|
||||||
|
|
||||||
describe('POST /post/info', () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
user = await signUpNewUser()
|
|
||||||
|
|
||||||
const token = user.token ?? ''
|
|
||||||
|
|
||||||
const post = await request(app)
|
|
||||||
.post('/post/create')
|
|
||||||
.send({
|
|
||||||
content: 'Hello world'
|
|
||||||
})
|
|
||||||
.set('Authorization', `Bearer ${token}`)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
postId = post.body.id
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
await deleteUser(user.username!)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with 200 status code and return some info about the post', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/post/info?id=${postId}`)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
expect(response.body).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
content: expect.any(String),
|
|
||||||
createdAt: expect.any(String),
|
|
||||||
updatedAt: expect.any(String),
|
|
||||||
author: expect.any(Object)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with 400 status code if the post does not exists', async () => {
|
|
||||||
const response = await request(app).get('/post/info?id=abc').expect(400)
|
|
||||||
|
|
||||||
expect(response.body).toHaveProperty('error')
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,56 +0,0 @@
|
||||||
import app from '../../app'
|
|
||||||
import request from 'supertest'
|
|
||||||
import signUpNewUser from '../utils/create-user'
|
|
||||||
import deleteUser from '../utils/delete-user'
|
|
||||||
import type User from 'interfaces/user'
|
|
||||||
|
|
||||||
let user: User
|
|
||||||
|
|
||||||
describe('PUT /post/update', () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
user = await signUpNewUser()
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
await deleteUser(user.username!)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should create a new post and update the content of it', async () => {
|
|
||||||
const post = await request(app)
|
|
||||||
.post('/post/create')
|
|
||||||
.send({
|
|
||||||
content: 'Lorem'
|
|
||||||
})
|
|
||||||
.set('Authorization', `Bearer ${user.token ?? ''}`)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
expect(post.body).toHaveProperty('id')
|
|
||||||
|
|
||||||
const fieldsToUpdate = {
|
|
||||||
postId: post.body.id,
|
|
||||||
content: 'Lorem ipsum'
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.put('/post/update')
|
|
||||||
.send(fieldsToUpdate)
|
|
||||||
.set('Authorization', `Bearer ${user.token ?? ''}`)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
// Post content should be Lorem Ipsum
|
|
||||||
if (post.body.content === response.body.content) {
|
|
||||||
throw new Error("Post didn't update")
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(response.body).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
content: expect.any(String),
|
|
||||||
createdAt: expect.any(String),
|
|
||||||
updatedAt: expect.any(String),
|
|
||||||
author: expect.any(Object)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,45 +0,0 @@
|
||||||
import request from 'supertest'
|
|
||||||
import app from '../../app'
|
|
||||||
import deleteUser from '../utils/delete-user'
|
|
||||||
import signUpNewUser from '../utils/create-user'
|
|
||||||
import type User from 'interfaces/user'
|
|
||||||
|
|
||||||
let user: User
|
|
||||||
|
|
||||||
describe('POST /user/auth', () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
user = await signUpNewUser()
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
await deleteUser(user.username!)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with a error if the user does not exists', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.post('/user/auth')
|
|
||||||
.send({ email: 'mm@mm.com', password: 'aa' })
|
|
||||||
.expect(400)
|
|
||||||
|
|
||||||
expect(response.body).toHaveProperty('error')
|
|
||||||
expect(response.body.error).toBe('Invalid email or password')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with a error if receive an invalid email or password', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.post('/user/auth')
|
|
||||||
.send({ email: user.email, password: 'fake_pass' })
|
|
||||||
.expect(400)
|
|
||||||
|
|
||||||
expect(response.body).toHaveProperty('error')
|
|
||||||
expect(response.body.error).toBe('Invalid email or password')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with a error if receive an empty body', async () => {
|
|
||||||
const response = await request(app).post('/user/auth').send({}).expect(400)
|
|
||||||
|
|
||||||
expect(response.body).toHaveProperty('error')
|
|
||||||
expect(response.body.error).toBe('Missing fields')
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,19 +0,0 @@
|
||||||
import app from '../../app'
|
|
||||||
import request from 'supertest'
|
|
||||||
import signUpNewUser from '../utils/create-user'
|
|
||||||
import type User from 'interfaces/user'
|
|
||||||
|
|
||||||
let user: User
|
|
||||||
|
|
||||||
describe('DELETE /user/delete', () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
user = await signUpNewUser()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should delete the user successfully', async () => {
|
|
||||||
await request(app)
|
|
||||||
.post('/user/delete')
|
|
||||||
.set('Authorization', `Bearer ${user.token ?? ''}`)
|
|
||||||
.expect(200)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,36 +0,0 @@
|
||||||
import app from '../../app'
|
|
||||||
import request from 'supertest'
|
|
||||||
import deleteUser from '../utils/delete-user'
|
|
||||||
import signUpNewUser from '../utils/create-user'
|
|
||||||
import type User from 'interfaces/user'
|
|
||||||
|
|
||||||
let user: User
|
|
||||||
|
|
||||||
describe('POST /user/info', () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
user = await signUpNewUser()
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
await deleteUser(user.username!)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with 200 status code and return the user data', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/user/info?u=${user.username ?? ''}`)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
expect(response.body).toHaveProperty('profileImage')
|
|
||||||
expect(response.body).toHaveProperty('displayName')
|
|
||||||
expect(response.body).toHaveProperty('username')
|
|
||||||
expect(response.body).toHaveProperty('createdAt')
|
|
||||||
expect(response.body).toHaveProperty('posts')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with 400 status code if the user send no username', async () => {
|
|
||||||
const response = await request(app).get('/user/info?u=').expect(400)
|
|
||||||
|
|
||||||
expect(response.body).toHaveProperty('error')
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,45 +0,0 @@
|
||||||
import request from 'supertest'
|
|
||||||
import app from '../../app'
|
|
||||||
import deleteUser from '../utils/delete-user'
|
|
||||||
import signUpNewUser from '../utils/create-user'
|
|
||||||
import type User from 'interfaces/user'
|
|
||||||
|
|
||||||
let user: User
|
|
||||||
|
|
||||||
describe('POST /user/signup', () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
user = await signUpNewUser()
|
|
||||||
delete user.token
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
await deleteUser(user.username!)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with a 400 status code if sent any invalid data', async () => {
|
|
||||||
await request(app)
|
|
||||||
.post('/user/signup')
|
|
||||||
.send({
|
|
||||||
username: 'username12@',
|
|
||||||
email: user.email,
|
|
||||||
password: user.password
|
|
||||||
})
|
|
||||||
.expect(400)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with a 400 status code for an existing username or email', async () => {
|
|
||||||
await request(app)
|
|
||||||
.post('/user/signup')
|
|
||||||
.send({
|
|
||||||
username: user.username,
|
|
||||||
email: user.email,
|
|
||||||
password: user.password
|
|
||||||
})
|
|
||||||
.expect(400)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with a 400 status code if receive an empty body', async () => {
|
|
||||||
await request(app).post('/user/signup').send({}).expect(400)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,37 +0,0 @@
|
||||||
import app from '../../app'
|
|
||||||
import request from 'supertest'
|
|
||||||
import { faker } from '@faker-js/faker'
|
|
||||||
import type User from '../../interfaces/user'
|
|
||||||
|
|
||||||
async function signUpNewUser (): Promise<User> {
|
|
||||||
// To avoid conflicts with existing usernames or emails
|
|
||||||
const username = faker.internet.userName({ lastName: 'doe' }).toLowerCase()
|
|
||||||
const email = faker.internet.email()
|
|
||||||
const password = faker.internet.password() + '@1'
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.post('/user/signup')
|
|
||||||
.send({
|
|
||||||
username,
|
|
||||||
email,
|
|
||||||
password
|
|
||||||
})
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.post('/user/auth')
|
|
||||||
.send({
|
|
||||||
email,
|
|
||||||
password
|
|
||||||
})
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
return {
|
|
||||||
username,
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
token: response.body.token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default signUpNewUser
|
|
|
@ -1,17 +0,0 @@
|
||||||
import prisma from '../../clients/prisma-client'
|
|
||||||
|
|
||||||
export default async function deleteUser (username: string) {
|
|
||||||
await prisma.post.deleteMany({
|
|
||||||
where: {
|
|
||||||
author: {
|
|
||||||
username
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
await prisma.user.deleteMany({
|
|
||||||
where: {
|
|
||||||
username
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
Reference in a new issue