112 lines
3.0 KiB
TypeScript
112 lines
3.0 KiB
TypeScript
import type { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox'
|
|
import { Type } from 'typebox'
|
|
import { ChatMessageSchema, NewChatMessagePayloadSchema } from '../plugins/schemas/chat.ts'
|
|
|
|
const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
|
|
fastify.post(
|
|
'/chat/send',
|
|
{
|
|
schema: {
|
|
summary: 'Send message',
|
|
tags: ['Chat'],
|
|
operationId: 'chat.send',
|
|
body: NewChatMessagePayloadSchema,
|
|
response: {
|
|
200: ChatMessageSchema,
|
|
},
|
|
},
|
|
},
|
|
async (req, reply) => {
|
|
const user = req.user!
|
|
|
|
const message = await fastify.prisma.message.create({
|
|
data: {
|
|
text: req.body.text,
|
|
senderId: user.id,
|
|
attachments: {
|
|
create: (req.body.attachments ?? []).map((attachmentId) => {
|
|
return {
|
|
attachment: {
|
|
connect: {
|
|
id: attachmentId,
|
|
},
|
|
},
|
|
}
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
|
|
if (!message) {
|
|
return reply.unprocessableEntity()
|
|
}
|
|
|
|
const response = {
|
|
id: message.id,
|
|
senderId: user.id,
|
|
text: message.text,
|
|
createdAt: message.createdAt.toISOString(),
|
|
updatedAt: message.updatedAt.toISOString(),
|
|
attachments: req.body.attachments ?? [],
|
|
}
|
|
|
|
fastify.bus.emit('chat:new-message', response)
|
|
|
|
return response
|
|
},
|
|
)
|
|
|
|
fastify.get(
|
|
'/chat',
|
|
{
|
|
schema: {
|
|
summary: 'Get messages',
|
|
tags: ['Chat'],
|
|
operationId: 'chat.messages',
|
|
querystring: Type.Object({
|
|
cursor: Type.Optional(Type.String({ format: 'uuid', description: 'Cursor to message' })),
|
|
limit: Type.Number({ minimum: 1, maximum: 100, default: 10 }),
|
|
}),
|
|
response: {
|
|
200: Type.Object({
|
|
messages: Type.Array(ChatMessageSchema),
|
|
nextCursor: Type.Optional(Type.String({ format: 'uuid', description: 'Cursor to last message' })),
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
// eslint-disable-next-line ts/ban-ts-comment
|
|
// @ts-expect-error
|
|
async (req) => {
|
|
const messages = await fastify.prisma.message.findMany({
|
|
orderBy: { createdAt: 'desc' },
|
|
take: req.query.limit + 1,
|
|
include: { attachments: true },
|
|
...(req.query.cursor && {
|
|
cursor: {
|
|
id: req.query.cursor,
|
|
},
|
|
// skip: 1,
|
|
}),
|
|
})
|
|
|
|
const hasMore = messages.length > req.query.limit
|
|
const cursorMessage = hasMore ? messages.pop() : undefined
|
|
|
|
return {
|
|
messages: messages.map((message) => {
|
|
return {
|
|
...message,
|
|
createdAt: message.createdAt.toISOString(),
|
|
updatedAt: message.updatedAt.toISOString(),
|
|
attachments: message.attachments.map(({ attachmentId }) => attachmentId),
|
|
}
|
|
}),
|
|
nextCursor: cursorMessage?.id,
|
|
}
|
|
},
|
|
)
|
|
}
|
|
|
|
export default plugin
|