made pretty and fixed message posting
This commit is contained in:
@@ -1,127 +1,126 @@
|
|||||||
import { Context } from "hono";
|
import { Context } from "hono";
|
||||||
import { sendMessageToChannel, removeMessageFromChannel } from "../services/realtime.js"
|
import {
|
||||||
|
sendMessageToChannel,
|
||||||
|
removeMessageFromChannel,
|
||||||
|
} from "../services/realtime.js";
|
||||||
import { success } from "zod";
|
import { success } from "zod";
|
||||||
|
|
||||||
|
export async function postMessageToChannel(io: any, c: Context) {
|
||||||
|
try {
|
||||||
|
io = c.get("io");
|
||||||
|
|
||||||
export async function postMessageToChannel(
|
const instanceId = c.req.param("instanceId");
|
||||||
io: any,
|
const categoryId = c.req.param("categoryId");
|
||||||
c: Context
|
const channelId = c.req.param("channelId");
|
||||||
) {
|
const message = await c.req.json();
|
||||||
try {
|
|
||||||
io = c.get("io");
|
|
||||||
|
|
||||||
const instanceId = c.req.param("instanceId");
|
const result = await sendMessageToChannel(
|
||||||
const categoryId = c.req.param("categoryId");
|
instanceId,
|
||||||
const channelId = c.req.param("channelId");
|
categoryId,
|
||||||
const message = await c.req.json();
|
channelId,
|
||||||
|
message,
|
||||||
|
"new_channel_message",
|
||||||
|
io,
|
||||||
|
);
|
||||||
|
|
||||||
const result = await sendMessageToChannel(
|
if (result === "Event not implemented") {
|
||||||
instanceId,
|
console.log(
|
||||||
categoryId,
|
"controller::realtime::postMessageToChannel - Failed to send message",
|
||||||
channelId,
|
);
|
||||||
message,
|
return c.json({
|
||||||
"new_channel_message",
|
success: false,
|
||||||
io
|
message: "Event not implemented or recognized",
|
||||||
)
|
status: 400,
|
||||||
|
});
|
||||||
if(result === "Event not implemented"){
|
|
||||||
console.log("controller::realtime::postMessageToChannel - Failed to send message")
|
|
||||||
return c.json({
|
|
||||||
success: false,
|
|
||||||
message: "Event not implemented or recognized",
|
|
||||||
status: 400
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if(result === "no acknowledgment"){
|
|
||||||
console.log("controller::realtime::postMessageToChannel - No acknowledgment received from client")
|
|
||||||
return c.json({
|
|
||||||
success: false,
|
|
||||||
message: "No acknowledgment received from client",
|
|
||||||
status: 500
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!result){
|
|
||||||
throw new Error("failed to send message");
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.json({
|
|
||||||
success: true,
|
|
||||||
message: "Message sent successfully",
|
|
||||||
status: 200
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
const errMessage = err as Error;
|
|
||||||
console.log("controller::realtime::postMessageToChannel - ", errMessage);
|
|
||||||
return c.json({
|
|
||||||
success: false,
|
|
||||||
message: errMessage.message,
|
|
||||||
status: 500
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result === "no acknowledgment") {
|
||||||
|
console.log(
|
||||||
|
"controller::realtime::postMessageToChannel - No acknowledgment received from client",
|
||||||
|
);
|
||||||
|
return c.json({
|
||||||
|
success: false,
|
||||||
|
message: "No acknowledgment received from client",
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
throw new Error("failed to send message");
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.json({
|
||||||
|
success: true,
|
||||||
|
message: "Message sent successfully",
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
const errMessage = err as Error;
|
||||||
|
console.log("controller::realtime::postMessageToChannel - ", errMessage);
|
||||||
|
return c.json({
|
||||||
|
success: false,
|
||||||
|
message: errMessage.message,
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteMessageFromChannel(
|
export async function deleteMessageFromChannel(io: any, c: Context) {
|
||||||
io: any,
|
try {
|
||||||
c: Context
|
io = c.get("io");
|
||||||
){
|
|
||||||
try {
|
|
||||||
|
|
||||||
io = c.get("io");
|
const instanceId = c.req.param("instanceId");
|
||||||
|
const categoryId = c.req.param("categoryId");
|
||||||
|
const channelId = c.req.param("channelId");
|
||||||
|
const messageId = c.req.param("messageId");
|
||||||
|
|
||||||
const instanceId = c.req.param("instanceId");
|
const result = await removeMessageFromChannel(
|
||||||
const categoryId = c.req.param("categoryId");
|
instanceId,
|
||||||
const channelId = c.req.param("channelId");
|
categoryId,
|
||||||
const messageId = c.req.param("messageId");
|
channelId,
|
||||||
|
messageId,
|
||||||
|
"delete_channel_message",
|
||||||
|
io,
|
||||||
|
);
|
||||||
|
|
||||||
const result = await removeMessageFromChannel(
|
if (result === "event not implemented") {
|
||||||
instanceId,
|
console.log(
|
||||||
categoryId,
|
"controller::realtime::deleteMessageFromChannel - Event not implemented",
|
||||||
channelId,
|
);
|
||||||
messageId,
|
return c.json({
|
||||||
"delete_channel_message",
|
success: false,
|
||||||
io
|
message: "Event not implemented or recognized",
|
||||||
)
|
status: 400,
|
||||||
|
});
|
||||||
if(result === "event not implemented"){
|
|
||||||
console.log("controller::realtime::deleteMessageFromChannel - Event not implemented")
|
|
||||||
return c.json({
|
|
||||||
success: false,
|
|
||||||
message: "Event not implemented or recognized",
|
|
||||||
status: 400
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(result === "no acknowledgment"){
|
|
||||||
console.log("controller::realtime::deleteMessageFromChannel - No acknowledgment received from client")
|
|
||||||
return c.json({
|
|
||||||
success: false,
|
|
||||||
message: "No acknowledgment received from client",
|
|
||||||
status: 500
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!result){
|
|
||||||
throw new Error("failed to delete message");
|
|
||||||
}
|
|
||||||
|
|
||||||
c.json({
|
|
||||||
success: true,
|
|
||||||
message: "Message deleted successfully",
|
|
||||||
status: 200
|
|
||||||
})
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
|
|
||||||
const errMessage = err as Error;
|
|
||||||
console.log("services::realtime::deleteMessageFromChannel - ", errMessage);
|
|
||||||
return c.json({
|
|
||||||
success: false,
|
|
||||||
message: errMessage.message,
|
|
||||||
status: 500
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result === "no acknowledgment") {
|
||||||
|
console.log(
|
||||||
|
"controller::realtime::deleteMessageFromChannel - No acknowledgment received from client",
|
||||||
|
);
|
||||||
|
return c.json({
|
||||||
|
success: false,
|
||||||
|
message: "No acknowledgment received from client",
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
throw new Error("failed to delete message");
|
||||||
|
}
|
||||||
|
|
||||||
|
c.json({
|
||||||
|
success: true,
|
||||||
|
message: "Message deleted successfully",
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
const errMessage = err as Error;
|
||||||
|
console.log("services::realtime::deleteMessageFromChannel - ", errMessage);
|
||||||
|
return c.json({
|
||||||
|
success: false,
|
||||||
|
message: errMessage.message,
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { getAllUsersFrom, getUserInformation, createUser } from "../services/userService";
|
import {
|
||||||
|
getAllUsersFrom,
|
||||||
|
getUserInformation,
|
||||||
|
createUser,
|
||||||
|
} from "../services/userService";
|
||||||
import { CreateUserInput } from "../validators/userValidator";
|
import { CreateUserInput } from "../validators/userValidator";
|
||||||
|
|
||||||
export async function fetchUserData(id: string) {
|
export async function fetchUserData(id: string) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as crypto from 'crypto';
|
import * as crypto from "crypto";
|
||||||
|
|
||||||
export default function shaHash(data:string, salt:string) : string {
|
export default function shaHash(data: string, salt: string): string {
|
||||||
return crypto.createHmac('sha256', salt).update(data).digest('hex');
|
return crypto.createHmac("sha256", salt).update(data).digest("hex");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,21 +53,19 @@ app.use(
|
|||||||
app.route("/api", routes);
|
app.route("/api", routes);
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
'/openapi',
|
"/openapi",
|
||||||
openAPIRouteHandler(app, {
|
openAPIRouteHandler(app, {
|
||||||
documentation: {
|
documentation: {
|
||||||
info: {
|
info: {
|
||||||
title: 'Hono API',
|
title: "Hono API",
|
||||||
version: '1.0.0',
|
version: "1.0.0",
|
||||||
description: 'Greeting API',
|
description: "Greeting API",
|
||||||
},
|
},
|
||||||
servers: [
|
servers: [{ url: "http://localhost:3000", description: "Local Server" }],
|
||||||
{ url: 'http://localhost:3000', description: 'Local Server' },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
})
|
}),
|
||||||
)
|
);
|
||||||
|
|
||||||
app.get('/scalar', Scalar({ url: '/openapi' }))
|
app.get("/scalar", Scalar({ url: "/openapi" }));
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { describeRoute, resolver } from "hono-openapi";
|
import { describeRoute, resolver } from "hono-openapi";
|
||||||
import { postMessageToChannel,
|
import {
|
||||||
deleteMessageFromChannel
|
postMessageToChannel,
|
||||||
|
deleteMessageFromChannel,
|
||||||
} from "../controller/realtime";
|
} from "../controller/realtime";
|
||||||
|
|
||||||
const app = new Hono();
|
const app = new Hono();
|
||||||
|
|
||||||
app.post(
|
app.post(
|
||||||
"message/",
|
"message/",
|
||||||
zValidator({
|
zValidator({
|
||||||
body: z.object({
|
body: z.object({
|
||||||
content: z.string().min(1).max(500)
|
content: z.string().min(1).max(500),
|
||||||
})
|
|
||||||
}),
|
}),
|
||||||
async (c) => {
|
}),
|
||||||
const { instanceId, categoryId, channelId } = c.req.params;
|
async (c) => {
|
||||||
const { content } = c.req.body;
|
const { instanceId, categoryId, channelId } = c.req.params;
|
||||||
|
const { content } = c.req.body;
|
||||||
|
|
||||||
return postMessageToChannel(c.get("io"), {
|
return postMessageToChannel(c.get("io"), {
|
||||||
instanceId,
|
instanceId,
|
||||||
categoryId,
|
categoryId,
|
||||||
channelId,
|
channelId,
|
||||||
content
|
content,
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
@@ -1,29 +1,38 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { fetchAllUsers, fetchUserData, createNewUser } from "../controller/userController";
|
import {
|
||||||
import { createUserSchema, queryAllUsersByInstanceId, queryUserByIdSchema } from "../validators/userValidator";
|
fetchAllUsers,
|
||||||
|
fetchUserData,
|
||||||
|
createNewUser,
|
||||||
|
} from "../controller/userController";
|
||||||
|
import {
|
||||||
|
createUserSchema,
|
||||||
|
queryAllUsersByInstanceId,
|
||||||
|
queryUserByIdSchema,
|
||||||
|
} from "../validators/userValidator";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { describeRoute, resolver } from "hono-openapi";
|
import { describeRoute, resolver } from "hono-openapi";
|
||||||
const actions = new Hono();
|
const actions = new Hono();
|
||||||
|
|
||||||
actions.get("user/:id",
|
actions.get(
|
||||||
|
"user/:id",
|
||||||
describeRoute({
|
describeRoute({
|
||||||
description: "Get user by id",
|
description: "Get user by id",
|
||||||
responses: {
|
responses: {
|
||||||
200: {
|
200: {
|
||||||
description: "Success getting user",
|
description: "Success getting user",
|
||||||
content: {
|
content: {
|
||||||
"application/json": { schema: resolver(queryUserByIdSchema) }
|
"application/json": { schema: resolver(queryUserByIdSchema) },
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
404: {
|
404: {
|
||||||
description: "User id not found",
|
description: "User id not found",
|
||||||
content: {
|
content: {
|
||||||
"application/json": { schema: resolver(queryUserByIdSchema) }
|
"application/json": { schema: resolver(queryUserByIdSchema) },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
zValidator('param', queryUserByIdSchema),
|
zValidator("param", queryUserByIdSchema),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const id = c.req.param("id");
|
const id = c.req.param("id");
|
||||||
const userData = await fetchUserData(id);
|
const userData = await fetchUserData(id);
|
||||||
@@ -32,22 +41,23 @@ actions.get("user/:id",
|
|||||||
} else {
|
} else {
|
||||||
return c.json({ error: "User not found" }, 404);
|
return c.json({ error: "User not found" }, 404);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
actions.get("user",
|
actions.get(
|
||||||
|
"user",
|
||||||
describeRoute({
|
describeRoute({
|
||||||
description: "Get all users by instance id",
|
description: "Get all users by instance id",
|
||||||
responses: {
|
responses: {
|
||||||
200: {
|
200: {
|
||||||
description: "Success getting all users in instance",
|
description: "Success getting all users in instance",
|
||||||
content: {
|
content: {
|
||||||
"application/json": { schema: resolver(queryAllUsersByInstanceId) }
|
"application/json": { schema: resolver(queryAllUsersByInstanceId) },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
zValidator('query', queryAllUsersByInstanceId),
|
zValidator("query", queryAllUsersByInstanceId),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const instanceId = c.req.query("instanceId");
|
const instanceId = c.req.query("instanceId");
|
||||||
if (!instanceId) {
|
if (!instanceId) {
|
||||||
@@ -60,7 +70,7 @@ actions.get("user",
|
|||||||
} else {
|
} else {
|
||||||
return c.json({ error: "Error getting all users from instance" }, 500);
|
return c.json({ error: "Error getting all users from instance" }, 500);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
actions.post(
|
actions.post(
|
||||||
@@ -71,18 +81,18 @@ actions.post(
|
|||||||
201: {
|
201: {
|
||||||
description: "Success",
|
description: "Success",
|
||||||
content: {
|
content: {
|
||||||
'application/json': { schema: resolver(createUserSchema) },
|
"application/json": { schema: resolver(createUserSchema) },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
400: {
|
400: {
|
||||||
description: "Bad request (user exists)",
|
description: "Bad request (user exists)",
|
||||||
content: {
|
content: {
|
||||||
'application/json': { schema: resolver(createUserSchema) }
|
"application/json": { schema: resolver(createUserSchema) },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
zValidator('json', createUserSchema),
|
zValidator("json", createUserSchema),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
try {
|
try {
|
||||||
const data = await c.req.json();
|
const data = await c.req.json();
|
||||||
@@ -94,7 +104,7 @@ actions.post(
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
return c.json({ error: "Error creating user" }, 500);
|
return c.json({ error: "Error creating user" }, 500);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export default actions;
|
export default actions;
|
||||||
|
|||||||
@@ -3,75 +3,76 @@ import {
|
|||||||
MessagePing,
|
MessagePing,
|
||||||
PrismaClient,
|
PrismaClient,
|
||||||
Role,
|
Role,
|
||||||
Reply
|
Reply,
|
||||||
|
|
||||||
} from "@prisma/client";
|
} from "@prisma/client";
|
||||||
import { CreateUserInput } from '../validators/userValidator';
|
import { CreateUserInput } from "../validators/userValidator";
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
class MessageService {
|
export async function sendMessageToChannel(
|
||||||
public async function sendMessageToChannel(
|
channelId: string,
|
||||||
channelId: string,
|
userId: string,
|
||||||
userId: string,
|
content: string,
|
||||||
content: string,
|
repliedMessageId: string | null,
|
||||||
repliedMessageId: string | null
|
): Promise<{
|
||||||
): Promise<{
|
id: string;
|
||||||
id: string,
|
channelId: string;
|
||||||
channelId: string,
|
userId: string;
|
||||||
userId: string,
|
text: string;
|
||||||
text: string,
|
deleted: boolean;
|
||||||
deleted: boolean,
|
replies: null | {
|
||||||
replies: null | {
|
messageId: string;
|
||||||
messageId: string,
|
repliesToId: string;
|
||||||
repliesToId: string,
|
repliesToText: string;
|
||||||
repliesToText: string
|
};
|
||||||
}
|
} | null> {
|
||||||
} | null> {
|
try {
|
||||||
try {
|
const newMessage = await prisma.message.create({
|
||||||
|
data: {
|
||||||
|
channelId: channelId,
|
||||||
const newMessage = await prisma.message.create({
|
userId: userId,
|
||||||
data: {
|
text: content,
|
||||||
channelId: channelId,
|
deleted: false,
|
||||||
userId: userId,
|
},
|
||||||
text: content,
|
});
|
||||||
deleted: false,
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
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,
|
|
||||||
replies: repliedMessageId ? {
|
|
||||||
messageId: newMessage.id,
|
|
||||||
repliesToId: origMessage?.id,
|
|
||||||
repliesToText: origMessage?.text
|
|
||||||
} : null
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,88 +1,90 @@
|
|||||||
import { readonly } from "zod";
|
import { readonly } from "zod";
|
||||||
|
|
||||||
const EVENTS = {
|
const EVENTS = {
|
||||||
NEW_CHANNEL_MESSAGE: "new_channel_message",
|
NEW_CHANNEL_MESSAGE: "new_channel_message",
|
||||||
DELETE_CHANNEL_MESSAGE: "delete_channel_message",
|
DELETE_CHANNEL_MESSAGE: "delete_channel_message",
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function sendMessageToChannel(
|
export async function sendMessageToChannel(
|
||||||
instanceId: string,
|
instanceId: string,
|
||||||
categoryId: string,
|
categoryId: string,
|
||||||
channelId: string,
|
channelId: string,
|
||||||
message: any,
|
message: any,
|
||||||
event: string,
|
event: string,
|
||||||
io: any,
|
io: any,
|
||||||
): Promise<string | boolean> {
|
): Promise<string | boolean> {
|
||||||
try {
|
try {
|
||||||
|
//TODO: implement middleware to replace this
|
||||||
//TODO: implement middleware to replace this
|
if (EVENTS.NEW_CHANNEL_MESSAGE === event) {
|
||||||
if(EVENTS.NEW_CHANNEL_MESSAGE === event){
|
throw new Error("Event not implemented");
|
||||||
throw new Error("Event not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: add prisma to save channel message to DB
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
io.to(instanceId).emit(event, message, (ack: any) => {
|
|
||||||
if (ack && ack.status === 'received') {
|
|
||||||
console.log(`Message ${ack.messageId} acknowledged by client.`);
|
|
||||||
resolve(true);
|
|
||||||
} else {
|
|
||||||
console.log('services::realtime::sendMessageToChannel No acknowledgment received from client.');
|
|
||||||
resolve("no acknowledgment");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
const errMessage = err as Error;
|
|
||||||
if (errMessage.message === "Event not implemented") {
|
|
||||||
console.log(`services::realtime::sendMessageToChannel - Event not implemented. Attempted event: ${event}`)
|
|
||||||
return "event not implemented"
|
|
||||||
}
|
|
||||||
console.log("services::realtime::sendMessageToChannel - ", errMessage);
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: add prisma to save channel message to DB
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
io.to(instanceId).emit(event, message, (ack: any) => {
|
||||||
|
if (ack && ack.status === "received") {
|
||||||
|
console.log(`Message ${ack.messageId} acknowledged by client.`);
|
||||||
|
resolve(true);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
"services::realtime::sendMessageToChannel No acknowledgment received from client.",
|
||||||
|
);
|
||||||
|
resolve("no acknowledgment");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
const errMessage = err as Error;
|
||||||
|
if (errMessage.message === "Event not implemented") {
|
||||||
|
console.log(
|
||||||
|
`services::realtime::sendMessageToChannel - Event not implemented. Attempted event: ${event}`,
|
||||||
|
);
|
||||||
|
return "event not implemented";
|
||||||
|
}
|
||||||
|
console.log("services::realtime::sendMessageToChannel - ", errMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function removeMessageFromChannel(
|
export async function removeMessageFromChannel(
|
||||||
instanceId: string,
|
instanceId: string,
|
||||||
categoryId: string,
|
categoryId: string,
|
||||||
channelId: string,
|
channelId: string,
|
||||||
messageId: string,
|
messageId: string,
|
||||||
event: string,
|
event: string,
|
||||||
io: any
|
io: any,
|
||||||
): Promise<string | boolean>{
|
): Promise<string | boolean> {
|
||||||
try {
|
try {
|
||||||
|
//TODO: implement middleware to replace this
|
||||||
//TODO: implement middleware to replace this
|
if (EVENTS.DELETE_CHANNEL_MESSAGE === event) {
|
||||||
if(EVENTS.DELETE_CHANNEL_MESSAGE === event){
|
throw new Error("event not implemented");
|
||||||
throw new Error("event not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: add prisma to flag a channel message as deleted
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
io.to(instanceId).emit(event, { messageId }, (ack: any) => {
|
|
||||||
if (ack && ack.status === 'received') {
|
|
||||||
console.log(`Message ${ack.messageId} acknowledged by client.`);
|
|
||||||
resolve(true);
|
|
||||||
} else {
|
|
||||||
console.log('services::realtime::deleteMessageFromChannel No acknowledgment received from client.');
|
|
||||||
resolve("no acknowledgment");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
const errMessage = err as Error;
|
|
||||||
if (errMessage.message === "Event not implemented") {
|
|
||||||
console.log(`services::realtime::deleteMessageFromChannel - Event not implemented. Attempted event: ${event}`)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
console.log("services::realtime::deleteMessageFromChannel - ", errMessage);
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: add prisma to flag a channel message as deleted
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
io.to(instanceId).emit(event, { messageId }, (ack: any) => {
|
||||||
|
if (ack && ack.status === "received") {
|
||||||
|
console.log(`Message ${ack.messageId} acknowledged by client.`);
|
||||||
|
resolve(true);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
"services::realtime::deleteMessageFromChannel No acknowledgment received from client.",
|
||||||
|
);
|
||||||
|
resolve("no acknowledgment");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
const errMessage = err as Error;
|
||||||
|
if (errMessage.message === "Event not implemented") {
|
||||||
|
console.log(
|
||||||
|
`services::realtime::deleteMessageFromChannel - Event not implemented. Attempted event: ${event}`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
console.log("services::realtime::deleteMessageFromChannel - ", errMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,31 +5,35 @@ import {
|
|||||||
Role,
|
Role,
|
||||||
UserAuth,
|
UserAuth,
|
||||||
} from "@prisma/client";
|
} from "@prisma/client";
|
||||||
import { CreateUserInput } from '../validators/userValidator';
|
import { CreateUserInput } from "../validators/userValidator";
|
||||||
import shaHash from "../helper/hashing";
|
import shaHash from "../helper/hashing";
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
export async function createUser(data: CreateUserInput): Promise<{
|
export async function createUser(data: CreateUserInput): Promise<{
|
||||||
username: string,
|
username: string;
|
||||||
nickname: string | null,
|
nickname: string | null;
|
||||||
bio: string | null,
|
bio: string | null;
|
||||||
picture: string | null,
|
picture: string | null;
|
||||||
banner: string | null,
|
banner: string | null;
|
||||||
status: string,
|
status: string;
|
||||||
admin: boolean
|
admin: boolean;
|
||||||
} | null> {
|
} | null> {
|
||||||
const requestingUser = await getUserInformation(data.requestingUserId);
|
const requestingUser = await getUserInformation(data.requestingUserId);
|
||||||
const requestingUserCredentials = await getUserCredentials(data.requestingUserId)
|
const requestingUserCredentials = await getUserCredentials(
|
||||||
if (!requestingUser
|
data.requestingUserId,
|
||||||
|| !requestingUserCredentials
|
);
|
||||||
|| !requestingUser.admin
|
if (
|
||||||
|| requestingUserCredentials.token == null
|
!requestingUser ||
|
||||||
|| data.requestingUserToken != requestingUserCredentials.token) {
|
!requestingUserCredentials ||
|
||||||
|
!requestingUser.admin ||
|
||||||
|
requestingUserCredentials.token == null ||
|
||||||
|
data.requestingUserToken != requestingUserCredentials.token
|
||||||
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await prisma.user.count({ where: { username: data.username }}) >= 1) {
|
if ((await prisma.user.count({ where: { username: data.username } })) >= 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,13 +49,15 @@ export async function createUser(data: CreateUserInput): Promise<{
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!(await prisma.userAuth.create({
|
if (
|
||||||
data: {
|
!(await prisma.userAuth.create({
|
||||||
userId: userData.id,
|
data: {
|
||||||
password: shaHash(data.passwordhash, userData.id),
|
userId: userData.id,
|
||||||
token: null,
|
password: shaHash(data.passwordhash, userData.id),
|
||||||
}
|
token: null,
|
||||||
}))) {
|
},
|
||||||
|
}))
|
||||||
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,52 +65,52 @@ export async function createUser(data: CreateUserInput): Promise<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getUserCredentials(userId: string): Promise<{
|
export async function getUserCredentials(userId: string): Promise<{
|
||||||
userId: string,
|
userId: string;
|
||||||
password: string,
|
password: string;
|
||||||
token: string | null
|
token: string | null;
|
||||||
} | null> {
|
} | null> {
|
||||||
try {
|
try {
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
throw new Error("missing userId");
|
throw new Error("missing userId");
|
||||||
}
|
}
|
||||||
|
|
||||||
const userAuth = await prisma.userAuth.findUnique({
|
const userAuth = await prisma.userAuth.findUnique({
|
||||||
where: {
|
where: {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!userAuth) {
|
if (!userAuth) {
|
||||||
throw new Error("could not find user credentials");
|
throw new Error("could not find user credentials");
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
userId: userAuth.userId,
|
userId: userAuth.userId,
|
||||||
password: userAuth.password,
|
password: userAuth.password,
|
||||||
token: userAuth.token,
|
token: userAuth.token,
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errMessage = err as Error;
|
const errMessage = err as Error;
|
||||||
|
|
||||||
if (errMessage.message === "missing userId") {
|
if (errMessage.message === "missing userId") {
|
||||||
console.log("services::actions::getUserCredentials - missing userId");
|
console.log("services::actions::getUserCredentials - missing userId");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errMessage.message === "could not find user credentials") {
|
|
||||||
console.log(
|
|
||||||
"services::actions::getUserCredentials - unable to find user credentials",
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (errMessage.message === "could not find user credentials") {
|
||||||
console.log(
|
console.log(
|
||||||
"services::actions::getUserCredentials - unknown error",
|
"services::actions::getUserCredentials - unable to find user credentials",
|
||||||
errMessage,
|
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"services::actions::getUserCredentials - unknown error",
|
||||||
|
errMessage,
|
||||||
|
);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function getUserInformation(userId: string): Promise<{
|
export async function getUserInformation(userId: string): Promise<{
|
||||||
id: string;
|
id: string;
|
||||||
@@ -196,9 +202,9 @@ export async function getAllUsersFrom(instanceId: string): Promise<
|
|||||||
try {
|
try {
|
||||||
const instances = await prisma.instance.count({
|
const instances = await prisma.instance.count({
|
||||||
where: {
|
where: {
|
||||||
id: instanceId
|
id: instanceId,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
if (instances < 1) {
|
if (instances < 1) {
|
||||||
throw new Error("could not find given instance id");
|
throw new Error("could not find given instance id");
|
||||||
}
|
}
|
||||||
@@ -218,8 +224,8 @@ export async function getAllUsersFrom(instanceId: string): Promise<
|
|||||||
|
|
||||||
const admins = await prisma.user.findMany({
|
const admins = await prisma.user.findMany({
|
||||||
where: {
|
where: {
|
||||||
admin: true
|
admin: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
if (!admins) {
|
if (!admins) {
|
||||||
throw new Error("could not get all admins");
|
throw new Error("could not get all admins");
|
||||||
@@ -249,13 +255,13 @@ export async function getAllUsersFrom(instanceId: string): Promise<
|
|||||||
).includes(u.status as any)
|
).includes(u.status as any)
|
||||||
? (u.status as "online" | "offline" | "dnd" | "idle" | "invis")
|
? (u.status as "online" | "offline" | "dnd" | "idle" | "invis")
|
||||||
: "offline",
|
: "offline",
|
||||||
role: adminRoles.map(r => ({
|
role: adminRoles.map((r) => ({
|
||||||
userId: r.userId,
|
userId: r.userId,
|
||||||
instanceId: r.instanceId,
|
instanceId: r.instanceId,
|
||||||
})),
|
})),
|
||||||
}
|
};
|
||||||
})
|
}),
|
||||||
)
|
);
|
||||||
|
|
||||||
const userData = await Promise.all(
|
const userData = await Promise.all(
|
||||||
users.map(async (u) => {
|
users.map(async (u) => {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { z } from 'zod'
|
import { z } from "zod";
|
||||||
|
|
||||||
export const queryUserByIdSchema = z.object({
|
export const queryUserByIdSchema = z.object({
|
||||||
id: z.uuidv7()
|
id: z.uuidv7(),
|
||||||
})
|
});
|
||||||
|
|
||||||
export const queryAllUsersByInstanceId = z.object({
|
export const queryAllUsersByInstanceId = z.object({
|
||||||
instanceId: z.uuidv7()
|
instanceId: z.uuidv7(),
|
||||||
})
|
});
|
||||||
|
|
||||||
export const createUserSchema = z.object({
|
export const createUserSchema = z.object({
|
||||||
username: z.string().min(3).max(30),
|
username: z.string().min(3).max(30),
|
||||||
@@ -14,13 +14,17 @@ export const createUserSchema = z.object({
|
|||||||
bio: z.string().max(500).optional(),
|
bio: z.string().max(500).optional(),
|
||||||
picture: z.url().optional(),
|
picture: z.url().optional(),
|
||||||
banner: z.url().optional(),
|
banner: z.url().optional(),
|
||||||
status: z.enum(['online', 'offline', 'dnd', 'idle', 'invis']).default('online'),
|
status: z
|
||||||
|
.enum(["online", "offline", "dnd", "idle", "invis"])
|
||||||
|
.default("online"),
|
||||||
admin: z.boolean().default(false),
|
admin: z.boolean().default(false),
|
||||||
requestingUserId: z.uuidv7(),
|
requestingUserId: z.uuidv7(),
|
||||||
requestingUserToken: z.uuidv4(),
|
requestingUserToken: z.uuidv4(),
|
||||||
passwordhash: z.string(),
|
passwordhash: z.string(),
|
||||||
})
|
});
|
||||||
|
|
||||||
export type QueryUserByIdInput = z.infer<typeof queryUserByIdSchema>
|
export type QueryUserByIdInput = z.infer<typeof queryUserByIdSchema>;
|
||||||
export type QueryAllUsersByInstanceIdInput = z.infer<typeof queryAllUsersByInstanceId>
|
export type QueryAllUsersByInstanceIdInput = z.infer<
|
||||||
export type CreateUserInput = z.infer<typeof createUserSchema>
|
typeof queryAllUsersByInstanceId
|
||||||
|
>;
|
||||||
|
export type CreateUserInput = z.infer<typeof createUserSchema>;
|
||||||
|
|||||||
Reference in New Issue
Block a user