From 2871c4c9e0d05c472da76d66814e0c002badcae2 Mon Sep 17 00:00:00 2001 From: Divlo Date: Tue, 28 Dec 2021 21:52:28 +0000 Subject: [PATCH] feat(services): add GET /guilds/[guildId]/channels --- .../20211228190900_init_3/migration.sql | 14 ++++ prisma/schema.prisma | 10 +-- .../[guildId]/channels/__test__/get.test.ts | 50 +++++++++++++ src/services/guilds/[guildId]/channels/get.ts | 75 +++++++++++++++++++ src/services/guilds/[guildId]/get.ts | 1 + src/services/guilds/__test__/get.test.ts | 3 +- src/services/guilds/get.ts | 2 +- src/services/guilds/index.ts | 2 + 8 files changed, 149 insertions(+), 8 deletions(-) create mode 100644 prisma/migrations/20211228190900_init_3/migration.sql create mode 100644 src/services/guilds/[guildId]/channels/__test__/get.test.ts create mode 100644 src/services/guilds/[guildId]/channels/get.ts diff --git a/prisma/migrations/20211228190900_init_3/migration.sql b/prisma/migrations/20211228190900_init_3/migration.sql new file mode 100644 index 0000000..2e37be8 --- /dev/null +++ b/prisma/migrations/20211228190900_init_3/migration.sql @@ -0,0 +1,14 @@ +-- DropIndex +DROP INDEX "Channel_guildId_key"; + +-- DropIndex +DROP INDEX "Member_guildId_key"; + +-- DropIndex +DROP INDEX "Member_userId_key"; + +-- DropIndex +DROP INDEX "Message_channelId_key"; + +-- DropIndex +DROP INDEX "Message_memberId_key"; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 203308a..b9338eb 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -64,9 +64,9 @@ model Member { Message Message[] createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt - userId Int @unique + userId Int user User? @relation(fields: [userId], references: [id]) - guildId Int @unique + guildId Int guild Guild? @relation(fields: [guildId], references: [id]) } @@ -86,7 +86,7 @@ model Channel { name String @db.VarChar(20) createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt - guildId Int @unique + guildId Int guild Guild? @relation(fields: [guildId], references: [id]) messages Message[] } @@ -98,8 +98,8 @@ model Message { mimetype String @default("text/plain") @db.VarChar(127) createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt - memberId Int @unique + memberId Int member Member? @relation(fields: [memberId], references: [id]) - channelId Int @unique + channelId Int channel Channel? @relation(fields: [channelId], references: [id]) } diff --git a/src/services/guilds/[guildId]/channels/__test__/get.test.ts b/src/services/guilds/[guildId]/channels/__test__/get.test.ts new file mode 100644 index 0000000..51497fe --- /dev/null +++ b/src/services/guilds/[guildId]/channels/__test__/get.test.ts @@ -0,0 +1,50 @@ +import { application } from '../../../../../application.js' +import { authenticateUserTest } from '../../../../../__test__/utils/authenticateUserTest.js' +import { prismaMock } from '../../../../../__test__/setup.js' +import { memberExample } from '../../../../../models/Member' +import { guildExample } from '../../../../../models/Guild' +import { channelExample } from '../../../../../models/Channel.js' + +describe('GET /guilds/[guildId]/channels', () => { + it('succeeds', async () => { + prismaMock.member.findFirst.mockResolvedValue(memberExample) + prismaMock.channel.findMany.mockResolvedValue([channelExample]) + const { accessToken } = await authenticateUserTest() + const response = await application.inject({ + method: 'GET', + url: `/guilds/${guildExample.id}/channels`, + headers: { + authorization: `Bearer ${accessToken}` + } + }) + const responseJson = response.json() + expect(response.statusCode).toEqual(200) + expect(responseJson.length).toEqual(1) + expect(responseJson[0].id).toEqual(channelExample.id) + expect(responseJson[0].name).toEqual(channelExample.name) + expect(responseJson[0].guildId).toEqual(channelExample.guildId) + }) + + it('fails with not found guild', async () => { + const { accessToken } = await authenticateUserTest() + prismaMock.member.findFirst.mockResolvedValue(null) + const response = await application.inject({ + method: 'GET', + url: '/guilds/1/channels', + headers: { + authorization: `Bearer ${accessToken}` + } + }) + const responseJson = response.json() + expect(response.statusCode).toEqual(404) + expect(responseJson.message).toEqual('Member not found') + }) + + it('fails with unauthenticated user', async () => { + const response = await application.inject({ + method: 'GET', + url: '/guilds/1/channels' + }) + expect(response.statusCode).toEqual(401) + }) +}) diff --git a/src/services/guilds/[guildId]/channels/get.ts b/src/services/guilds/[guildId]/channels/get.ts new file mode 100644 index 0000000..b09a1c1 --- /dev/null +++ b/src/services/guilds/[guildId]/channels/get.ts @@ -0,0 +1,75 @@ +import { Static, Type } from '@sinclair/typebox' +import { FastifyPluginAsync, FastifySchema } from 'fastify' + +import prisma from '../../../../tools/database/prisma.js' +import { fastifyErrors } from '../../../../models/utils.js' +import authenticateUser from '../../../../tools/plugins/authenticateUser.js' +import { guildSchema } from '../../../../models/Guild' +import { channelSchema } from '../../../../models/Channel.js' +import { + getPaginationOptions, + queryPaginationObjectSchema +} from '../../../../tools/database/pagination.js' + +type QuerySchemaType = Static + +const parametersSchema = Type.Object({ + guildId: guildSchema.id +}) + +type Parameters = Static + +const getServiceSchema: FastifySchema = { + description: 'GET all the channels of a guild with its id.', + tags: ['channels'] as string[], + security: [ + { + bearerAuth: [] + } + ] as Array<{ [key: string]: [] }>, + params: parametersSchema, + querystring: queryPaginationObjectSchema, + response: { + 200: Type.Array(Type.Object(channelSchema)), + 400: fastifyErrors[400], + 401: fastifyErrors[401], + 403: fastifyErrors[403], + 404: fastifyErrors[404], + 500: fastifyErrors[500] + } +} as const + +export const getChannelsByGuildIdService: FastifyPluginAsync = async ( + fastify +) => { + await fastify.register(authenticateUser) + + fastify.route<{ + Params: Parameters + Querystring: QuerySchemaType + }>({ + method: 'GET', + url: '/guilds/:guildId/channels', + schema: getServiceSchema, + handler: async (request, reply) => { + if (request.user == null) { + throw fastify.httpErrors.forbidden() + } + const { guildId } = request.params + const member = await prisma.member.findFirst({ + where: { guildId, userId: request.user.current.id } + }) + if (member == null) { + throw fastify.httpErrors.notFound('Member not found') + } + const channels = await prisma.channel.findMany({ + ...getPaginationOptions(request.query), + where: { + guildId + } + }) + reply.statusCode = 200 + return channels + } + }) +} diff --git a/src/services/guilds/[guildId]/get.ts b/src/services/guilds/[guildId]/get.ts index 2af8044..3f1a940 100644 --- a/src/services/guilds/[guildId]/get.ts +++ b/src/services/guilds/[guildId]/get.ts @@ -34,6 +34,7 @@ const getServiceSchema: FastifySchema = { 400: fastifyErrors[400], 401: fastifyErrors[401], 403: fastifyErrors[403], + 404: fastifyErrors[404], 500: fastifyErrors[500] } } as const diff --git a/src/services/guilds/__test__/get.test.ts b/src/services/guilds/__test__/get.test.ts index c42c445..7bd3c7e 100644 --- a/src/services/guilds/__test__/get.test.ts +++ b/src/services/guilds/__test__/get.test.ts @@ -16,8 +16,7 @@ describe('GET /guilds', () => { url: '/guilds', headers: { authorization: `Bearer ${accessToken}` - }, - payload: {} + } }) const responseJson = response.json() expect(response.statusCode).toEqual(200) diff --git a/src/services/guilds/get.ts b/src/services/guilds/get.ts index e16929c..51ecf6d 100644 --- a/src/services/guilds/get.ts +++ b/src/services/guilds/get.ts @@ -10,7 +10,7 @@ import { queryPaginationObjectSchema } from '../../tools/database/pagination.js' -export type QuerySchemaType = Static +type QuerySchemaType = Static const getServiceSchema: FastifySchema = { description: 'GET all the guilds of an user.', diff --git a/src/services/guilds/index.ts b/src/services/guilds/index.ts index 921bfbb..968f826 100644 --- a/src/services/guilds/index.ts +++ b/src/services/guilds/index.ts @@ -3,6 +3,7 @@ import { FastifyPluginAsync } from 'fastify' import { getGuilds } from './get.js' import { postGuilds } from './post.js' import { getGuildsPublic } from './public/get.js' +import { getChannelsByGuildIdService } from './[guildId]/channels/get.js' import { getGuildMemberByIdService } from './[guildId]/get.js' import { putGuildIconById } from './[guildId]/icon/put.js' @@ -11,5 +12,6 @@ export const guildsService: FastifyPluginAsync = async (fastify) => { await fastify.register(getGuilds) await fastify.register(putGuildIconById) await fastify.register(getGuildMemberByIdService) + await fastify.register(getChannelsByGuildIdService) await fastify.register(getGuildsPublic) }