From 9b46852e20c081c490589e83a38233a9711f95d1 Mon Sep 17 00:00:00 2001 From: Kevin Puig <119972216+k-puig@users.noreply.github.com> Date: Sat, 27 Sep 2025 19:37:56 -0400 Subject: [PATCH] Get up to 50 messages before ISO 8601 timestamp --- .../src/controller/messageController.ts | 6 +- concord-server/src/routes/messageRoutes.ts | 39 ++++++++++- concord-server/src/services/messageService.ts | 68 +++++++++++++++++++ .../src/validators/messageValidator.ts | 7 ++ 4 files changed, 117 insertions(+), 3 deletions(-) diff --git a/concord-server/src/controller/messageController.ts b/concord-server/src/controller/messageController.ts index d8c9a27..e96b404 100644 --- a/concord-server/src/controller/messageController.ts +++ b/concord-server/src/controller/messageController.ts @@ -1,9 +1,13 @@ -import { getMessageInformation, sendMessageToChannel } from "../services/messageService"; +import { getMessageInformation, getMessagesBefore, sendMessageToChannel } from "../services/messageService"; export async function fetchMessageData(id:string) { return await getMessageInformation(id); } +export async function fetchMessagesBefore(date:string, channelId:string) { + return getMessagesBefore(date, channelId); +} + export async function sendMessage( channelId: string, userId: string, diff --git a/concord-server/src/routes/messageRoutes.ts b/concord-server/src/routes/messageRoutes.ts index 3b7085c..2733231 100644 --- a/concord-server/src/routes/messageRoutes.ts +++ b/concord-server/src/routes/messageRoutes.ts @@ -1,8 +1,8 @@ import { Hono } from "hono"; import { describeResponse, describeRoute, resolver } from "hono-openapi"; -import { getMessageByIdSchema, sendMessageSchema } from "../validators/messageValidator"; +import { getMessageByIdSchema, getMessagesBeforeDate, sendMessageSchema } from "../validators/messageValidator"; import { zValidator } from "@hono/zod-validator"; -import { fetchMessageData, sendMessage } from "../controller/messageController"; +import { fetchMessageData, fetchMessagesBefore, sendMessage } from "../controller/messageController"; const messageRoutes = new Hono(); @@ -38,6 +38,41 @@ messageRoutes.get( } ) +messageRoutes.get( + "", + describeRoute({ + description: "Get up to 50 messages prior to given datetime", + responses: { + 200: { + description: "Success getting up to 50 messages", + content: { + "application/json": { schema: resolver(getMessagesBeforeDate) } + } + } + } + }), + zValidator("query", getMessagesBeforeDate), + async (c) => { + const date = c.req.query("date"); + if (!date) { + return c.json({ error: "date not provided" }, 400); + } + + const channelId = c.req.query("channelId"); + if (!channelId) { + return c.json({ error: "channelId not provided" }, 400); + } + + const messagesArr = await fetchMessagesBefore(date, channelId); + + if (messagesArr) { + return c.json(messagesArr, 200); + } else { + return c.json({ error: "Failed to fetch messages" }, 500); + } + } +) + messageRoutes.post( "", describeRoute({ diff --git a/concord-server/src/services/messageService.ts b/concord-server/src/services/messageService.ts index f75eead..33c3ca1 100644 --- a/concord-server/src/services/messageService.ts +++ b/concord-server/src/services/messageService.ts @@ -85,6 +85,74 @@ export async function getMessageInformation(id:string): Promise<{ } } +export async function getMessagesBefore(date:string, channelId:string) { + try { + if (!date || !channelId) { + throw new Error("missing date or channelId"); + } + + const messages = await prisma.message.findMany({ + where: { + channelId: channelId, + createdAt: { + lt: new Date(date), + }, + }, + orderBy: { + createdAt: "desc", + }, + take: 50, + }); + + const messageInformationPromises = messages.map(async (message) => { + const replyData = await prisma.reply.findFirst({ + where: { + messageId: message.id, + }, + }); + + let originalMessage = null; + if (replyData) { + originalMessage = await prisma.message.findUnique({ + where: { + id: replyData.repliesToId, + }, + }); + } + + return { + id: message.id, + channelId: message.channelId!, + userId: message.userId!, + text: message.text, + deleted: message.deleted, + replies: originalMessage + ? { + messageId: message.id, + repliesToId: originalMessage.id, + repliesToText: originalMessage.text, + } + : null, + }; + }); + + return Promise.all(messageInformationPromises); + } catch (err) { + const errMessage = err as Error; + + if (errMessage.message === "missing date or channelId") { + console.log("services::actions::getMessagesBefore - missing date or channelId"); + return null; + } + + console.log( + "services::actions::getMessagesBefore - unknown error", + errMessage + ); + return null; + } +} + export async function sendMessageToChannel( channelId: string, userId: string, diff --git a/concord-server/src/validators/messageValidator.ts b/concord-server/src/validators/messageValidator.ts index 96774db..83e4920 100644 --- a/concord-server/src/validators/messageValidator.ts +++ b/concord-server/src/validators/messageValidator.ts @@ -4,6 +4,13 @@ export const getMessageByIdSchema = z.object({ id: z.uuidv7() }) +export const getMessagesBeforeDate = z.object({ + date: z.string().refine((val) => !isNaN(Date.parse(val)), { + message: "Invalid date string format" + }), + channelId: z.uuidv7() +}) + export const sendMessageSchema = z.object({ channelId: z.uuidv7(), userId: z.uuidv7(),