feat: migrate from express to fastify
This commit is contained in:
@ -1,25 +0,0 @@
|
||||
/channels/{channelId}:
|
||||
delete:
|
||||
security:
|
||||
- bearerAuth: []
|
||||
tags:
|
||||
- 'channels'
|
||||
summary: 'DELETE a channel with its id'
|
||||
parameters:
|
||||
- name: 'channelId'
|
||||
in: 'path'
|
||||
required: true
|
||||
responses:
|
||||
allOf:
|
||||
- $ref: '#/definitions/BadRequestError'
|
||||
- $ref: '#/definitions/UnauthorizedError'
|
||||
- $ref: '#/definitions/ForbiddenError'
|
||||
- $ref: '#/definitions/NotFoundError'
|
||||
- '200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: 'object'
|
||||
properties:
|
||||
deletedChannelId:
|
||||
type: 'number'
|
@ -1,41 +0,0 @@
|
||||
/channels/{channelId}:
|
||||
put:
|
||||
security:
|
||||
- bearerAuth: []
|
||||
tags:
|
||||
- 'channels'
|
||||
summary: 'UPDATE a channel with its id'
|
||||
parameters:
|
||||
- name: 'channelId'
|
||||
in: 'path'
|
||||
required: true
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: 'object'
|
||||
properties:
|
||||
name:
|
||||
type: 'string'
|
||||
minLength: 3
|
||||
maxLength: 30
|
||||
description:
|
||||
type: 'string'
|
||||
maxLength: 160
|
||||
isDefault:
|
||||
type: 'boolean'
|
||||
responses:
|
||||
allOf:
|
||||
- $ref: '#/definitions/BadRequestError'
|
||||
- $ref: '#/definitions/UnauthorizedError'
|
||||
- $ref: '#/definitions/ForbiddenError'
|
||||
- $ref: '#/definitions/NotFoundError'
|
||||
- '200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: 'object'
|
||||
properties:
|
||||
channel:
|
||||
allOf:
|
||||
- $ref: '#/definitions/Channel'
|
@ -1,71 +0,0 @@
|
||||
import request from 'supertest'
|
||||
|
||||
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUser'
|
||||
import { formatErrors } from '../../../../__test__/utils/formatErrors'
|
||||
import application from '../../../../application'
|
||||
import Channel from '../../../../models/Channel'
|
||||
import { errorsMessages } from '../delete'
|
||||
import { createChannels } from '../../__test__/utils/createChannel'
|
||||
|
||||
describe('DELETE /channels/:channelId', () => {
|
||||
it('succeeds and delete the channel', async () => {
|
||||
const channel1 = { name: 'general1', description: 'testing' }
|
||||
const result = await createChannels([channel1])
|
||||
const channelToDelete = result.channels[0]
|
||||
const response = await request(application)
|
||||
.delete(`/channels/${channelToDelete.id as number}`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send()
|
||||
.expect(200)
|
||||
expect(response.body.deletedChannelId).toEqual(channelToDelete.id)
|
||||
const foundChannel = await Channel.findOne({
|
||||
where: { id: channelToDelete.id }
|
||||
})
|
||||
expect(foundChannel).toBeNull()
|
||||
})
|
||||
|
||||
it("fails if the channel doesn't exist", async () => {
|
||||
const userToken = await authenticateUserTest()
|
||||
const response = await request(application)
|
||||
.delete('/channels/23')
|
||||
.set('Authorization', `${userToken.type} ${userToken.accessToken}`)
|
||||
.send()
|
||||
.expect(404)
|
||||
const errors = formatErrors(response.body.errors)
|
||||
expect(errors.length).toEqual(1)
|
||||
expect(errors).toEqual(expect.arrayContaining(['Not Found']))
|
||||
})
|
||||
|
||||
it('fails if the user is not the owner', async () => {
|
||||
const channel1 = { name: 'general1', description: 'testing' }
|
||||
const result = await createChannels([channel1])
|
||||
const channelToDelete = result.channels[0]
|
||||
const userToken = await authenticateUserTest()
|
||||
const response = await request(application)
|
||||
.delete(`/channels/${channelToDelete.id as number}`)
|
||||
.set('Authorization', `${userToken.type} ${userToken.accessToken}`)
|
||||
.send()
|
||||
.expect(404)
|
||||
const errors = formatErrors(response.body.errors)
|
||||
expect(errors.length).toEqual(1)
|
||||
expect(errors).toEqual(expect.arrayContaining(['Not Found']))
|
||||
})
|
||||
|
||||
it("fails if it's the default channel", async () => {
|
||||
const result = await createChannels([])
|
||||
const defaultChannel = await Channel.findOne({
|
||||
where: { guildId: result.guild.id as number, isDefault: true }
|
||||
})
|
||||
expect(defaultChannel).not.toBeNull()
|
||||
const response = await request(application)
|
||||
.delete(`/channels/${defaultChannel?.id as number}`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send()
|
||||
.expect(400)
|
||||
const errors = formatErrors(response.body.errors)
|
||||
expect(errors.length).toEqual(1)
|
||||
expect(errors).toEqual(
|
||||
expect.arrayContaining([errorsMessages.channel.shouldNotBeTheDefault])
|
||||
)
|
||||
})
|
||||
})
|
@ -1,120 +0,0 @@
|
||||
import request from 'supertest'
|
||||
|
||||
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUser'
|
||||
import { formatErrors } from '../../../../__test__/utils/formatErrors'
|
||||
import application from '../../../../application'
|
||||
import Channel from '../../../../models/Channel'
|
||||
import { commonErrorsMessages } from '../../../../tools/configurations/constants'
|
||||
import { randomString } from '../../../../tools/utils/random'
|
||||
import { createChannels } from '../../__test__/utils/createChannel'
|
||||
|
||||
describe('PUT /channels/:channelId', () => {
|
||||
it('succeeds and edit name/description of the channel', async () => {
|
||||
const name = 'general-updated'
|
||||
const description = 'general-description'
|
||||
const channel1 = { name: 'general1', description: 'testing' }
|
||||
const result = await createChannels([channel1])
|
||||
const channelToEdit = result.channels[0]
|
||||
const response = await request(application)
|
||||
.put(`/channels/${channelToEdit.id as number}`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send({ name, description })
|
||||
.expect(200)
|
||||
expect(response.body.channel.name).toEqual(name)
|
||||
expect(response.body.channel.description).toEqual(description)
|
||||
})
|
||||
|
||||
it('succeeds and set default channel to true', async () => {
|
||||
const channel1 = { name: 'general1', description: 'testing' }
|
||||
const result = await createChannels([channel1])
|
||||
const channelToEdit = result.channels[0]
|
||||
const response = await request(application)
|
||||
.put(`/channels/${channelToEdit.id as number}`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send({ isDefault: true })
|
||||
.expect(200)
|
||||
const defaultChannels = await Channel.findAll({
|
||||
where: { guildId: result.guild.id as number, isDefault: true }
|
||||
})
|
||||
expect(defaultChannels.length).toEqual(1)
|
||||
expect(response.body.channel.name).toEqual(channel1.name)
|
||||
expect(response.body.channel.isDefault).toBeTruthy()
|
||||
})
|
||||
|
||||
it('succeeds with invalid slug name', async () => {
|
||||
const channel1 = { name: 'general1', description: 'testing' }
|
||||
const result = await createChannels([channel1])
|
||||
const channelToEdit = result.channels[0]
|
||||
const name = 'random channel'
|
||||
const response = await request(application)
|
||||
.put(`/channels/${channelToEdit.id as number}`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send({ name })
|
||||
.expect(200)
|
||||
expect(response.body.channel.name).toEqual(name)
|
||||
expect(response.body.channel.isDefault).toBeFalsy()
|
||||
})
|
||||
|
||||
it('fails with too long description', async () => {
|
||||
const channel1 = { name: 'general1', description: 'testing' }
|
||||
const result = await createChannels([channel1])
|
||||
const channelToEdit = result.channels[0]
|
||||
const response = await request(application)
|
||||
.put(`/channels/${channelToEdit.id as number}`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send({ description: randomString(170) })
|
||||
.expect(400)
|
||||
const errors = formatErrors(response.body.errors)
|
||||
expect(errors.length).toEqual(1)
|
||||
expect(errors).toEqual(
|
||||
expect.arrayContaining([
|
||||
commonErrorsMessages.charactersLength('description', { max: 160 })
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it('fails with too long name', async () => {
|
||||
const channel1 = { name: 'general1', description: 'testing' }
|
||||
const result = await createChannels([channel1])
|
||||
const channelToEdit = result.channels[0]
|
||||
const response = await request(application)
|
||||
.put(`/channels/${channelToEdit.id as number}`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send({ name: ' random channel name ' + randomString(35) })
|
||||
.expect(400)
|
||||
const errors = formatErrors(response.body.errors)
|
||||
expect(errors.length).toEqual(1)
|
||||
expect(errors).toEqual(
|
||||
expect.arrayContaining([
|
||||
commonErrorsMessages.charactersLength('name', { max: 30, min: 3 })
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("fails if the channel doesn't exist", async () => {
|
||||
const userToken = await authenticateUserTest()
|
||||
const response = await request(application)
|
||||
.put('/channels/23')
|
||||
.set('Authorization', `${userToken.type} ${userToken.accessToken}`)
|
||||
.send()
|
||||
.expect(404)
|
||||
const errors = formatErrors(response.body.errors)
|
||||
expect(errors.length).toEqual(1)
|
||||
expect(errors).toEqual(expect.arrayContaining(['Not Found']))
|
||||
})
|
||||
|
||||
it('fails if the user is not the owner', async () => {
|
||||
const channel1 = { name: 'general1', description: 'testing' }
|
||||
const result = await createChannels([channel1])
|
||||
const channelToRemove = result.channels[0]
|
||||
const userToken = await authenticateUserTest()
|
||||
const response = await request(application)
|
||||
.put(`/channels/${channelToRemove.id as number}`)
|
||||
.set('Authorization', `${userToken.type} ${userToken.accessToken}`)
|
||||
.send()
|
||||
.expect(404)
|
||||
const errors = formatErrors(response.body.errors)
|
||||
expect(errors.length).toEqual(1)
|
||||
expect(errors).toEqual(expect.arrayContaining(['Not Found']))
|
||||
})
|
||||
})
|
@ -1,56 +0,0 @@
|
||||
import { Request, Response, Router } from 'express'
|
||||
|
||||
import { authenticateUser } from '../../../tools/middlewares/authenticateUser'
|
||||
import Channel from '../../../models/Channel'
|
||||
import Member from '../../../models/Member'
|
||||
import { BadRequestError } from '../../../tools/errors/BadRequestError'
|
||||
import { ForbiddenError } from '../../../tools/errors/ForbiddenError'
|
||||
import { NotFoundError } from '../../../tools/errors/NotFoundError'
|
||||
import { deleteMessages } from '../../../tools/utils/deleteFiles'
|
||||
import Message from '../../../models/Message'
|
||||
import { emitToMembers } from '../../../tools/socket/emitEvents'
|
||||
|
||||
export const errorsMessages = {
|
||||
channel: {
|
||||
shouldNotBeTheDefault: 'The channel to delete should not be the default'
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteByIdChannelsRouter = Router()
|
||||
|
||||
deleteByIdChannelsRouter.delete(
|
||||
'/channels/:channelId',
|
||||
authenticateUser,
|
||||
async (req: Request, res: Response) => {
|
||||
if (req.user == null) {
|
||||
throw new ForbiddenError()
|
||||
}
|
||||
const user = req.user.current
|
||||
const { channelId } = req.params as { channelId: string }
|
||||
const channel = await Channel.findOne({
|
||||
where: { id: channelId },
|
||||
include: [Message]
|
||||
})
|
||||
if (channel == null) {
|
||||
throw new NotFoundError()
|
||||
}
|
||||
const member = await Member.findOne({
|
||||
where: { userId: user.id, guildId: channel.guildId, isOwner: true }
|
||||
})
|
||||
if (member == null) {
|
||||
throw new NotFoundError()
|
||||
}
|
||||
if (channel.isDefault) {
|
||||
throw new BadRequestError(errorsMessages.channel.shouldNotBeTheDefault)
|
||||
}
|
||||
const deletedChannelId = channel.id
|
||||
await deleteMessages(channel.messages)
|
||||
await channel.destroy()
|
||||
await emitToMembers({
|
||||
event: 'channels',
|
||||
guildId: channel.guildId,
|
||||
payload: { action: 'delete', item: channel }
|
||||
})
|
||||
return res.status(200).json({ deletedChannelId })
|
||||
}
|
||||
)
|
@ -1,33 +0,0 @@
|
||||
/channels/{channelId}/messages:
|
||||
get:
|
||||
security:
|
||||
- bearerAuth: []
|
||||
tags:
|
||||
- 'messages'
|
||||
summary: 'GET all the messages of a channel'
|
||||
parameters:
|
||||
- name: 'channelId'
|
||||
in: 'path'
|
||||
required: true
|
||||
allOf:
|
||||
- $ref: '#/definitions/PaginateModelParameters'
|
||||
responses:
|
||||
allOf:
|
||||
- $ref: '#/definitions/UnauthorizedError'
|
||||
- $ref: '#/definitions/ForbiddenError'
|
||||
- $ref: '#/definitions/BadRequestError'
|
||||
- $ref: '#/definitions/NotFoundError'
|
||||
- '200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/PaginateModel'
|
||||
type: 'object'
|
||||
properties:
|
||||
rows:
|
||||
type: 'array'
|
||||
items:
|
||||
allOf:
|
||||
- $ref: '#/definitions/Message'
|
||||
- $ref: '#/definitions/User'
|
@ -1,44 +0,0 @@
|
||||
/channels/{channelId}/messages:
|
||||
post:
|
||||
security:
|
||||
- bearerAuth: []
|
||||
tags:
|
||||
- 'messages'
|
||||
summary: 'Create a new message'
|
||||
parameters:
|
||||
- name: 'channelId'
|
||||
in: 'path'
|
||||
required: true
|
||||
requestBody:
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: 'object'
|
||||
properties:
|
||||
value:
|
||||
type: 'string'
|
||||
minLength: 1
|
||||
maxLength: 50_000
|
||||
type:
|
||||
allOf:
|
||||
- $ref: '#/definitions/MessageType'
|
||||
file:
|
||||
type: 'string'
|
||||
format: 'binary'
|
||||
responses:
|
||||
allOf:
|
||||
- $ref: '#/definitions/UnauthorizedError'
|
||||
- $ref: '#/definitions/ForbiddenError'
|
||||
- $ref: '#/definitions/BadRequestError'
|
||||
- $ref: '#/definitions/NotFoundError'
|
||||
- $ref: '#/definitions/PayloadTooLargeError'
|
||||
- '201':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: 'object'
|
||||
properties:
|
||||
message:
|
||||
allOf:
|
||||
- $ref: '#/definitions/Message'
|
||||
- $ref: '#/definitions/User'
|
@ -1,23 +0,0 @@
|
||||
import request from 'supertest'
|
||||
|
||||
import application from '../../../../../application'
|
||||
import { createMessages } from '../../../../messages/__test__/utils/createMessages'
|
||||
|
||||
describe('GET /channels/:channelId/messages', () => {
|
||||
it('should get all the messages of the channel', async () => {
|
||||
const messages = ['Hello world!', 'some random message']
|
||||
const result = await createMessages(messages)
|
||||
const response = await request(application)
|
||||
.get(`/channels/${result.channelId}/messages`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send()
|
||||
.expect(200)
|
||||
expect(response.body.hasMore).toBeFalsy()
|
||||
expect(response.body.totalItems).toEqual(messages.length)
|
||||
expect(response.body.rows[0].value).toEqual(messages[0])
|
||||
expect(response.body.rows[1].value).toEqual(messages[1])
|
||||
expect(response.body.rows[1].user).not.toBeNull()
|
||||
expect(response.body.rows[1].user.id).toEqual(result.user.id)
|
||||
expect(response.body.rows[1].user.password).not.toBeDefined()
|
||||
})
|
||||
})
|
@ -1,69 +0,0 @@
|
||||
import request from 'supertest'
|
||||
|
||||
import { authenticateUserTest } from '../../../../../__test__/utils/authenticateUser'
|
||||
import { formatErrors } from '../../../../../__test__/utils/formatErrors'
|
||||
import application from '../../../../../application'
|
||||
import { createChannels } from '../../../__test__/utils/createChannel'
|
||||
|
||||
const channel1 = { name: 'general1', description: 'testing' }
|
||||
|
||||
describe('POST /channels/:channelId/messages', () => {
|
||||
it('succeeds and create the message', async () => {
|
||||
const value = 'my awesome message'
|
||||
const result = await createChannels([channel1])
|
||||
expect(result.channels.length).toEqual(1)
|
||||
const channel = result.channels[0]
|
||||
const response = await request(application)
|
||||
.post(`/channels/${channel.id as number}/messages`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send({ value, type: 'text' })
|
||||
.expect(201)
|
||||
expect(response.body.message).not.toBeNull()
|
||||
expect(response.body.message.value).toEqual(value)
|
||||
expect(response.body.message.type).toEqual('text')
|
||||
expect(response.body.message.user).not.toBeNull()
|
||||
expect(response.body.message.user.id).toEqual(result.user.id)
|
||||
})
|
||||
|
||||
it('fails with empty message', async () => {
|
||||
const result = await createChannels([channel1])
|
||||
expect(result.channels.length).toEqual(1)
|
||||
const channel = result.channels[0]
|
||||
const response1 = await request(application)
|
||||
.post(`/channels/${channel.id as number}/messages`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send({ type: 'text' })
|
||||
.expect(400)
|
||||
const response2 = await request(application)
|
||||
.post(`/channels/${channel.id as number}/messages`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send({ type: 'file' })
|
||||
.expect(400)
|
||||
expect(response1.body.errors.length).toEqual(1)
|
||||
expect(response2.body.errors.length).toEqual(1)
|
||||
})
|
||||
|
||||
it("fails if the channel doesn't exist", async () => {
|
||||
const userToken = await authenticateUserTest()
|
||||
const response = await request(application)
|
||||
.post('/channels/2/messages')
|
||||
.set('Authorization', `${userToken.type} ${userToken.accessToken}`)
|
||||
.send({ type: 'text', value: 'awesome' })
|
||||
.expect(404)
|
||||
expect(response.body.errors.length).toEqual(1)
|
||||
})
|
||||
|
||||
it('fails if the user is not in the guild with this channel', async () => {
|
||||
const result = await createChannels([channel1])
|
||||
const channel = result.channels[0]
|
||||
const userToken = await authenticateUserTest()
|
||||
const response = await request(application)
|
||||
.post(`/channels/${channel.id as number}/messages`)
|
||||
.set('Authorization', `${userToken.type} ${userToken.accessToken}`)
|
||||
.send({ value: 'some random message', type: 'text' })
|
||||
.expect(404)
|
||||
const errors = formatErrors(response.body.errors)
|
||||
expect(errors.length).toEqual(1)
|
||||
expect(errors).toEqual(expect.arrayContaining(['Not Found']))
|
||||
})
|
||||
})
|
@ -1,60 +0,0 @@
|
||||
import { Request, Response, Router } from 'express'
|
||||
|
||||
import { authenticateUser } from '../../../../tools/middlewares/authenticateUser'
|
||||
import Channel from '../../../../models/Channel'
|
||||
import Member from '../../../../models/Member'
|
||||
import Message from '../../../../models/Message'
|
||||
import { paginateModel } from '../../../../tools/database/paginateModel'
|
||||
import { ForbiddenError } from '../../../../tools/errors/ForbiddenError'
|
||||
import { NotFoundError } from '../../../../tools/errors/NotFoundError'
|
||||
import User from '../../../../models/User'
|
||||
|
||||
export const getMessagesRouter = Router()
|
||||
|
||||
getMessagesRouter.get(
|
||||
'/channels/:channelId/messages',
|
||||
authenticateUser,
|
||||
async (req: Request, res: Response) => {
|
||||
if (req.user == null) {
|
||||
throw new ForbiddenError()
|
||||
}
|
||||
const { itemsPerPage, page } = req.query as {
|
||||
itemsPerPage: string
|
||||
page: string
|
||||
}
|
||||
const { channelId } = req.params as { channelId: string }
|
||||
const user = req.user.current
|
||||
const channel = await Channel.findOne({ where: { id: channelId } })
|
||||
if (channel == null) {
|
||||
throw new NotFoundError()
|
||||
}
|
||||
const member = await Member.findOne({
|
||||
where: { userId: user.id, guildId: channel.guildId }
|
||||
})
|
||||
if (member == null) {
|
||||
throw new NotFoundError()
|
||||
}
|
||||
member.lastVisitedChannelId = channel.id
|
||||
await member.save()
|
||||
const result = await paginateModel({
|
||||
Model: Message,
|
||||
queryOptions: { itemsPerPage, page },
|
||||
findOptions: {
|
||||
order: [['createdAt', 'DESC']],
|
||||
include: [{ model: Member, include: [User] }],
|
||||
where: {
|
||||
channelId: channel.id
|
||||
}
|
||||
}
|
||||
})
|
||||
return res.status(200).json({
|
||||
hasMore: result.hasMore,
|
||||
totalItems: result.totalItems,
|
||||
itemsPerPage: result.itemsPerPage,
|
||||
page: result.page,
|
||||
rows: result.rows.reverse().map((row: any) => {
|
||||
return { ...row.toJSON(), user: row.member.user.toJSON() }
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
@ -1,9 +0,0 @@
|
||||
import { Router } from 'express'
|
||||
|
||||
import { postMessagesRouter } from './post'
|
||||
import { getMessagesRouter } from './get'
|
||||
|
||||
export const messagesChannelsRouter = Router()
|
||||
|
||||
messagesChannelsRouter.use('/', postMessagesRouter)
|
||||
messagesChannelsRouter.use('/', getMessagesRouter)
|
@ -1,122 +0,0 @@
|
||||
import { Request, Response, Router } from 'express'
|
||||
import { body } from 'express-validator'
|
||||
import fileUpload from 'express-fileupload'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import path from 'path'
|
||||
|
||||
import { authenticateUser } from '../../../../tools/middlewares/authenticateUser'
|
||||
import { validateRequest } from '../../../../tools/middlewares/validateRequest'
|
||||
import Channel from '../../../../models/Channel'
|
||||
import Member from '../../../../models/Member'
|
||||
import Message, { MessageType, messageTypes } from '../../../../models/Message'
|
||||
import {
|
||||
commonErrorsMessages,
|
||||
fileUploadOptions,
|
||||
messagesFilePath,
|
||||
tempPath
|
||||
} from '../../../../tools/configurations/constants'
|
||||
import { ForbiddenError } from '../../../../tools/errors/ForbiddenError'
|
||||
import { NotFoundError } from '../../../../tools/errors/NotFoundError'
|
||||
import { onlyPossibleValuesValidation } from '../../../../tools/validations/onlyPossibleValuesValidation'
|
||||
import { deleteAllFilesInDirectory } from '../../../../tools/utils/deleteFiles'
|
||||
import { PayloadTooLargeError } from '../../../../tools/errors/PayloadTooLargeError'
|
||||
import { BadRequestError } from '../../../../tools/errors/BadRequestError'
|
||||
import { emitToMembers } from '../../../../tools/socket/emitEvents'
|
||||
|
||||
export const errorsMessages = {
|
||||
type: {
|
||||
shouldNotBeEmpty: 'Type should not be empty'
|
||||
}
|
||||
}
|
||||
|
||||
export const postMessagesRouter = Router()
|
||||
|
||||
postMessagesRouter.post(
|
||||
'/channels/:channelId/messages',
|
||||
authenticateUser,
|
||||
fileUpload(fileUploadOptions),
|
||||
[
|
||||
body('value')
|
||||
.optional({ nullable: true })
|
||||
.trim()
|
||||
.escape()
|
||||
.isLength({ min: 1, max: 50_000 })
|
||||
.withMessage(
|
||||
commonErrorsMessages.charactersLength('value', { min: 1, max: 50_000 })
|
||||
),
|
||||
body('type')
|
||||
.notEmpty()
|
||||
.withMessage(errorsMessages.type.shouldNotBeEmpty)
|
||||
.trim()
|
||||
.isString()
|
||||
.custom(async (type: MessageType) => {
|
||||
return await onlyPossibleValuesValidation(messageTypes, 'type', type)
|
||||
})
|
||||
],
|
||||
validateRequest,
|
||||
async (req: Request, res: Response) => {
|
||||
if (req.user == null) {
|
||||
throw new ForbiddenError()
|
||||
}
|
||||
const user = req.user.current
|
||||
const { value, type } = req.body as {
|
||||
value?: string
|
||||
type: MessageType
|
||||
}
|
||||
const file = req.files?.file
|
||||
const { channelId } = req.params as { channelId: string }
|
||||
const channel = await Channel.findOne({
|
||||
where: { id: channelId, type: 'text' }
|
||||
})
|
||||
if (channel == null) {
|
||||
throw new NotFoundError()
|
||||
}
|
||||
const member = await Member.findOne({
|
||||
where: { userId: user.id, guildId: channel.guildId }
|
||||
})
|
||||
if (member == null) {
|
||||
throw new NotFoundError()
|
||||
}
|
||||
if (
|
||||
(type === 'file' && file == null) ||
|
||||
(type === 'text' && value == null)
|
||||
) {
|
||||
throw new BadRequestError("You can't send an empty message")
|
||||
}
|
||||
let filename: string | null = null
|
||||
let mimetype = 'text/plain'
|
||||
if (
|
||||
value == null &&
|
||||
type === 'file' &&
|
||||
file != null &&
|
||||
!Array.isArray(file)
|
||||
) {
|
||||
if (file.truncated) {
|
||||
await deleteAllFilesInDirectory(tempPath)
|
||||
throw new PayloadTooLargeError(
|
||||
commonErrorsMessages.tooLargeFile('file')
|
||||
)
|
||||
}
|
||||
mimetype = file.mimetype
|
||||
const splitedMimetype = mimetype.split('/')
|
||||
const fileExtension = splitedMimetype[1]
|
||||
filename = `${uuidv4()}.${fileExtension}`
|
||||
await file.mv(path.join(messagesFilePath.filePath, filename))
|
||||
await deleteAllFilesInDirectory(tempPath)
|
||||
}
|
||||
const messageCreated = await Message.create({
|
||||
value: filename != null ? `${messagesFilePath.name}/${filename}` : value,
|
||||
type,
|
||||
mimetype,
|
||||
memberId: member.id,
|
||||
channelId: channel.id
|
||||
})
|
||||
const message = { ...messageCreated.toJSON(), user: req.user.current }
|
||||
await emitToMembers({
|
||||
event: 'messages',
|
||||
guildId: member.guildId,
|
||||
payload: { action: 'create', item: message }
|
||||
})
|
||||
return res.status(201).json({ message })
|
||||
}
|
||||
)
|
@ -1,92 +0,0 @@
|
||||
import { Request, Response, Router } from 'express'
|
||||
import { body } from 'express-validator'
|
||||
|
||||
import { authenticateUser } from '../../../tools/middlewares/authenticateUser'
|
||||
import { validateRequest } from '../../../tools/middlewares/validateRequest'
|
||||
import Channel from '../../../models/Channel'
|
||||
import Member from '../../../models/Member'
|
||||
import { commonErrorsMessages } from '../../../tools/configurations/constants'
|
||||
import { ForbiddenError } from '../../../tools/errors/ForbiddenError'
|
||||
import { NotFoundError } from '../../../tools/errors/NotFoundError'
|
||||
import { emitToMembers } from '../../../tools/socket/emitEvents'
|
||||
|
||||
export const putByIdChannelsRouter = Router()
|
||||
|
||||
putByIdChannelsRouter.put(
|
||||
'/channels/:channelId',
|
||||
authenticateUser,
|
||||
[
|
||||
body('name')
|
||||
.optional({ nullable: true })
|
||||
.isString()
|
||||
.trim()
|
||||
.escape()
|
||||
.isLength({ max: 30, min: 3 })
|
||||
.withMessage(
|
||||
commonErrorsMessages.charactersLength('name', { max: 30, min: 3 })
|
||||
),
|
||||
body('description')
|
||||
.optional({ nullable: true })
|
||||
.trim()
|
||||
.escape()
|
||||
.isLength({ max: 160 })
|
||||
.withMessage(
|
||||
commonErrorsMessages.charactersLength('description', { max: 160 })
|
||||
),
|
||||
body('isDefault').optional({ nullable: true }).isBoolean()
|
||||
],
|
||||
validateRequest,
|
||||
async (req: Request, res: Response) => {
|
||||
if (req.user == null) {
|
||||
throw new ForbiddenError()
|
||||
}
|
||||
const user = req.user.current
|
||||
const { channelId } = req.params as { channelId: string }
|
||||
const { name, description, isDefault } = req.body as {
|
||||
name?: string
|
||||
description?: string
|
||||
isDefault?: boolean
|
||||
}
|
||||
const channel = await Channel.findOne({
|
||||
where: { id: channelId }
|
||||
})
|
||||
if (channel == null) {
|
||||
throw new NotFoundError()
|
||||
}
|
||||
const member = await Member.findOne({
|
||||
where: { userId: user.id, guildId: channel.guildId, isOwner: true }
|
||||
})
|
||||
if (member == null) {
|
||||
throw new NotFoundError()
|
||||
}
|
||||
channel.name = name ?? channel.name
|
||||
channel.description = description ?? channel.description
|
||||
if (isDefault != null) {
|
||||
const defaultChannel = await Channel.findOne({
|
||||
where: { isDefault: true, guildId: member.guildId }
|
||||
})
|
||||
if (isDefault && defaultChannel != null) {
|
||||
defaultChannel.isDefault = false
|
||||
channel.isDefault = true
|
||||
await defaultChannel.save()
|
||||
const defaultChannelMembers = await Member.findAll({
|
||||
where: {
|
||||
guildId: member.guildId,
|
||||
lastVisitedChannelId: defaultChannel.id
|
||||
}
|
||||
})
|
||||
for (const defaultChannelMember of defaultChannelMembers) {
|
||||
defaultChannelMember.lastVisitedChannelId = channel.id
|
||||
await defaultChannelMember.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
await channel.save()
|
||||
await emitToMembers({
|
||||
event: 'channels',
|
||||
guildId: channel.guildId,
|
||||
payload: { action: 'update', item: channel }
|
||||
})
|
||||
return res.status(200).json({ channel })
|
||||
}
|
||||
)
|
@ -1,24 +0,0 @@
|
||||
definitions:
|
||||
Channel:
|
||||
type: 'object'
|
||||
properties:
|
||||
id:
|
||||
type: 'integer'
|
||||
description: 'Unique id'
|
||||
name:
|
||||
type: 'string'
|
||||
type:
|
||||
type: 'string'
|
||||
enum: ['text', 'voice']
|
||||
description:
|
||||
type: 'string'
|
||||
isDefault:
|
||||
type: 'boolean'
|
||||
guildId:
|
||||
type: 'integer'
|
||||
createdAt:
|
||||
type: 'string'
|
||||
format: 'date-time'
|
||||
updatedAt:
|
||||
type: 'string'
|
||||
format: 'date-time'
|
@ -1,42 +0,0 @@
|
||||
import request from 'supertest'
|
||||
|
||||
import application from '../../../../application'
|
||||
import Channel from '../../../../models/Channel'
|
||||
import {
|
||||
createGuild,
|
||||
CreateGuildResult
|
||||
} from '../../../guilds/__test__/utils/createGuild'
|
||||
|
||||
interface ChannelOptions {
|
||||
name: string
|
||||
description: string
|
||||
}
|
||||
|
||||
interface CreateChannelsResult extends CreateGuildResult {
|
||||
channels: Channel[]
|
||||
}
|
||||
|
||||
export const createChannels = async (
|
||||
channels: ChannelOptions[]
|
||||
): Promise<CreateChannelsResult> => {
|
||||
const result = await createGuild({
|
||||
guild: { description: 'description', name: 'guild' },
|
||||
user: {
|
||||
email: 'test@test.com',
|
||||
name: 'Test'
|
||||
}
|
||||
})
|
||||
const channelsResponses: Channel[] = []
|
||||
for (const { name, description } of channels) {
|
||||
const response = await request(application)
|
||||
.post(`/guilds/${result.guild.id as number}/channels`)
|
||||
.set('Authorization', `${result.user.type} ${result.user.accessToken}`)
|
||||
.send({ name, description })
|
||||
.expect(201)
|
||||
channelsResponses.push(response.body.channel)
|
||||
}
|
||||
return {
|
||||
...result,
|
||||
channels: channelsResponses
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import { Router } from 'express'
|
||||
|
||||
import { deleteByIdChannelsRouter } from './[channelId]/delete'
|
||||
import { messagesChannelsRouter } from './[channelId]/messages'
|
||||
import { putByIdChannelsRouter } from './[channelId]/put'
|
||||
|
||||
export const channelsRouter = Router()
|
||||
|
||||
channelsRouter.use('/', deleteByIdChannelsRouter)
|
||||
channelsRouter.use('/', putByIdChannelsRouter)
|
||||
channelsRouter.use('/', messagesChannelsRouter)
|
Reference in New Issue
Block a user