Message post and get by id + Deps fixed

This commit is contained in:
Kevin Puig
2025-09-27 18:47:34 -04:00
parent da1310b9c8
commit 0ee3984262
11 changed files with 343 additions and 132 deletions

View File

@@ -0,0 +1,21 @@
import { getMessageInformation, sendMessageToChannel } from "../services/messageService";
export async function fetchMessageData(id:string) {
return await getMessageInformation(id);
}
export async function sendMessage(
channelId: string,
userId: string,
content: string,
token: string,
repliedMessageId: string | null
) {
return await sendMessageToChannel(
channelId,
userId,
content,
token,
repliedMessageId
);
}

View File

@@ -1,9 +1,11 @@
//place exported routes below this line
import { Hono } from "hono";
import actions from "./userRoutes";
import userRoutes from "./userRoutes";
import messageRoutes from "./messageRoutes";
const routes = new Hono();
routes.route("/", actions);
routes.route("/user", userRoutes);
routes.route("/message", messageRoutes);
export default routes;

View File

@@ -0,0 +1,86 @@
import { Hono } from "hono";
import { describeResponse, describeRoute, resolver } from "hono-openapi";
import { getMessageByIdSchema, sendMessageSchema } from "../validators/messageValidator";
import { zValidator } from "@hono/zod-validator";
import { fetchMessageData, sendMessage } from "../controller/messageController";
const messageRoutes = new Hono();
messageRoutes.get(
"/:id",
describeRoute({
description: "Get message by id",
responses: {
200: {
description: "Success getting message",
content: {
"application/json": { schema: resolver(getMessageByIdSchema) }
}
},
404: {
description: "Message id not found",
content: {
"application/json": { schema: resolver(getMessageByIdSchema) }
}
}
}
}),
zValidator("param", getMessageByIdSchema),
async (c) => {
const id = c.req.param("id");
const messageData = await fetchMessageData(id);
if (messageData) {
return c.json(messageData, 200);
} else {
return c.json({ error: "Message not found" }, 404);
}
}
)
messageRoutes.post(
"",
describeRoute({
description: "Send a message to a channel",
responses: {
201: {
description: "Message sent successfully",
content: {
"application/json": { schema: resolver(sendMessageSchema) }
}
},
401: {
description: "Unauthorized - invalid token or user credentials",
content: {
"application/json": { schema: { type: "object", properties: { error: { type: "string" } } } }
}
},
500: {
description: "Server error",
content: {
"application/json": { schema: { type: "object", properties: { error: { type: "string" } } } }
}
}
}
}),
zValidator("json", sendMessageSchema),
async (c) => {
const { channelId, userId, content, token, repliedMessageId } = await c.req.json();
const result = await sendMessage(
channelId,
userId,
content,
token,
repliedMessageId || null
);
if (result) {
return c.json(result, 201);
} else {
return c.json({ error: "Failed to send message. Check your credentials and try again." }, 401);
}
}
)
export default messageRoutes;

View File

@@ -11,10 +11,10 @@ import {
} from "../validators/userValidator";
import { zValidator } from "@hono/zod-validator";
import { describeRoute, resolver } from "hono-openapi";
const actions = new Hono();
const userRoutes = new Hono();
actions.get(
"user/:id",
userRoutes.get(
"/:id",
describeRoute({
description: "Get user by id",
responses: {
@@ -44,8 +44,8 @@ actions.get(
},
);
actions.get(
"user",
userRoutes.get(
"",
describeRoute({
description: "Get all users by instance id",
responses: {
@@ -73,8 +73,8 @@ actions.get(
},
);
actions.post(
"user",
userRoutes.post(
"",
describeRoute({
description: "Create a new user",
responses: {
@@ -107,4 +107,4 @@ actions.post(
},
);
export default actions;
export default userRoutes;

View File

@@ -1,78 +0,0 @@
import {
Message,
MessagePing,
PrismaClient,
Role,
Reply,
} from "@prisma/client";
import { CreateUserInput } from "../validators/userValidator";
const prisma = new PrismaClient();
export async function sendMessageToChannel(
channelId: string,
userId: string,
content: string,
repliedMessageId: string | null,
): Promise<{
id: string;
channelId: string;
userId: string;
text: string;
deleted: boolean;
replies: null | {
messageId: string;
repliesToId: string;
repliesToText: string;
};
} | null> {
try {
const newMessage = await prisma.message.create({
data: {
channelId: channelId,
userId: userId,
text: content,
deleted: false,
},
});
if (!newMessage) {
return null;
}
let origMessage;
if (repliedMessageId) {
origMessage = await prisma.message.findUnique({
where: {
id: repliedMessageId,
},
});
if (!origMessage) {
throw new Error("could not find original message to reply to");
}
await prisma.reply.create({
data: {
messageId: newMessage.id,
repliesToId: origMessage.id,
},
});
}
return {
...newMessage,
channelId: newMessage.channelId!,
userId: newMessage.userId!,
replies: origMessage
? {
messageId: newMessage.id,
repliesToId: origMessage?.id,
repliesToText: origMessage?.text,
}
: null,
};
} catch (error) {
return null;
}
}

View File

@@ -0,0 +1,160 @@
import {
PrismaClient,
} from "@prisma/client";
import { getUserCredentials } from "./userService";
const prisma = new PrismaClient();
export async function getMessageInformation(id:string): Promise<{
id: string,
channelId: string,
userId: string,
text: string,
deleted: boolean,
replies: null | {
messageId: string;
repliesToId: string;
repliesToText: string;
};
} | null> {
try {
if (!id) {
throw new Error("missing messageId");
}
const message = await prisma.message.findUnique({
where: {
id: id,
},
});
if (!message) {
throw new Error("could not find message");
}
// Check if this message is a reply to another message
const replyData = await prisma.reply.findFirst({
where: {
messageId: 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,
};
} catch (err) {
const errMessage = err as Error;
if (errMessage.message === "missing messageId") {
console.log("services::actions::getMessageInformation - missing messageId");
return null;
}
if (errMessage.message === "could not find message") {
console.log(
"services::actions::getMessageInformation - unable to find message"
);
return null;
}
console.log(
"services::actions::getMessageInformation - unknown error",
errMessage
);
return null;
}
}
export async function sendMessageToChannel(
channelId: string,
userId: string,
content: string,
token: string,
repliedMessageId: string | null,
): Promise<{
id: string;
channelId: string;
userId: string;
text: string;
deleted: boolean;
replies: null | {
messageId: string;
repliesToId: string;
repliesToText: string;
};
} | null> {
try {
const userCreds = await getUserCredentials(userId);
if (!userCreds || userCreds.token != token) {
return null;
}
const newMessage = await prisma.message.create({
data: {
channelId: channelId,
userId: userId,
text: content,
deleted: false,
},
});
if (!newMessage) {
return null;
}
let origMessage;
if (repliedMessageId) {
origMessage = await prisma.message.findUnique({
where: {
id: repliedMessageId,
},
});
if (!origMessage) {
throw new Error("could not find original message to reply to");
}
await prisma.reply.create({
data: {
messageId: newMessage.id,
repliesToId: origMessage.id,
},
});
}
return {
...newMessage,
channelId: newMessage.channelId!,
userId: newMessage.userId!,
replies: origMessage
? {
messageId: newMessage.id,
repliesToId: origMessage?.id,
repliesToText: origMessage?.text,
}
: null,
};
} catch (error) {
return null;
}
}

View File

@@ -0,0 +1,13 @@
import { z } from "zod";
export const getMessageByIdSchema = z.object({
id: z.uuidv7()
})
export const sendMessageSchema = z.object({
channelId: z.uuidv7(),
userId: z.uuidv7(),
content: z.string(),
token: z.string(),
repliedMessageId: z.uuidv7().nullable().optional()
})