feat(communication): add chat reactions emojis and images
This commit is contained in:
@@ -111,6 +111,9 @@ export async function collaborationRoutes(server: FastifyInstance, options: Coll
|
||||
if (action === "room") return service.room(ctx.principal, id)
|
||||
if (action === "messages") return service.messages(ctx.principal, id, input)
|
||||
if (action === "send") return service.send(ctx.principal, id, input)
|
||||
if (action === "image") return service.image(ctx.principal, id, input)
|
||||
if (action === "reactions") return service.reactions(ctx.principal, id, input)
|
||||
if (action === "react") return service.react(ctx.principal, id, input)
|
||||
if (action === "read") return service.markRead(ctx.principal, id, input.seq)
|
||||
return { members: await service.members(ctx.principal, id) }
|
||||
}
|
||||
@@ -118,6 +121,9 @@ export async function collaborationRoutes(server: FastifyInstance, options: Coll
|
||||
server.get("/collaboration/rooms/:id/messages", async (req) => request(req, "messages"))
|
||||
server.post("/collaboration/rooms/:id/messages", async (req) => request(req, "send"))
|
||||
server.post("/collaboration/rooms/:id/read", async (req) => request(req, "read"))
|
||||
server.get("/collaboration/rooms/:id/image", async (req) => request(req, "image"))
|
||||
server.get("/collaboration/rooms/:id/reactions", async (req) => request(req, "reactions"))
|
||||
server.put("/collaboration/rooms/:id/reactions", async (req) => request(req, "react"))
|
||||
server.get("/collaboration/rooms/:id/members", async (req) => request(req, "members"))
|
||||
}
|
||||
|
||||
@@ -137,5 +143,8 @@ export async function collaborationGuestRoutes(server: FastifyInstance, { servic
|
||||
server.get("/guest/api/rooms/:id/messages", async (req: any) => service.messages(await principal(req), req.params.id, req.query))
|
||||
server.get("/guest/api/rooms/:id/members", async (req: any) => ({ members: await service.members(await principal(req), req.params.id) }))
|
||||
server.post("/guest/api/rooms/:id/messages", async (req: any) => service.send(await principal(req), req.params.id, body(req)))
|
||||
server.get("/guest/api/rooms/:id/image", async (req: any) => service.image(await principal(req), req.params.id, req.query))
|
||||
server.get("/guest/api/rooms/:id/reactions", async (req: any) => service.reactions(await principal(req), req.params.id, req.query))
|
||||
server.put("/guest/api/rooms/:id/reactions", async (req: any) => service.react(await principal(req), req.params.id, body(req)))
|
||||
server.post("/guest/api/rooms/:id/read", async (req: any) => service.markRead(await principal(req), req.params.id, body(req).seq))
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from "../../db/schema"
|
||||
import { NotificationService, UserDirectory } from "../modules/notification.service"
|
||||
import { assertCustomRoomKey, chatError, projectChatAccess } from "../modules/communication-access"
|
||||
import { chatContent, chatImage, chatReactions, imageMetadata, setChatReaction } from "../modules/chat-content"
|
||||
|
||||
type ChatUser = {
|
||||
userId: string
|
||||
@@ -160,7 +161,10 @@ export default async function communicationRoutes(server: FastifyInstance) {
|
||||
const messagesForRoom = async (roomId: string, currentUserId: string, tenantId: number, afterId = 0, limit = 50) => {
|
||||
const conditions = [eq(communicationMessages.roomId, roomId)]
|
||||
if (afterId > 0) conditions.push(gt(communicationMessages.id, afterId))
|
||||
const rows = await server.db.select().from(communicationMessages)
|
||||
const rows = await server.db.select({ id: communicationMessages.id, body: communicationMessages.body,
|
||||
authorUserId: communicationMessages.authorUserId, createdAt: communicationMessages.createdAt,
|
||||
image: sql`${communicationMessages.image} - 'dataUrl'`,
|
||||
}).from(communicationMessages)
|
||||
.where(and(...conditions))
|
||||
.orderBy(afterId > 0 ? asc(communicationMessages.id) : desc(communicationMessages.id))
|
||||
.limit(Math.min(Math.max(limit, 1), 100))
|
||||
@@ -181,6 +185,7 @@ export default async function communicationRoutes(server: FastifyInstance) {
|
||||
return orderedRows.map((message) => ({
|
||||
id: message.id,
|
||||
body: message.body,
|
||||
image: imageMetadata(message.image),
|
||||
sender: message.authorUserId,
|
||||
senderDisplayName: displayName(authorById.get(message.authorUserId) || {}),
|
||||
timestamp: message.createdAt.getTime(),
|
||||
@@ -466,17 +471,33 @@ export default async function communicationRoutes(server: FastifyInstance) {
|
||||
return { ...roomToApi(room), messages, nextId: messages[messages.length - 1]?.id || afterId }
|
||||
})
|
||||
|
||||
server.post("/communication/chat/rooms/:roomKey/messages", async (req: any, reply) => {
|
||||
server.post("/communication/chat/rooms/:roomKey/messages", async (req: any) => {
|
||||
const tenantId = await requireTenant(req)
|
||||
const room = await requireRoom(req, tenantId, req.user.user_id, req.params.roomKey)
|
||||
const body = String(req.body?.text || "").trim()
|
||||
if (!body) return reply.code(400).send({ error: "Nachricht darf nicht leer sein" })
|
||||
if (body.length > 10_000) return reply.code(400).send({ error: "Nachricht ist zu lang" })
|
||||
const { body, image } = await chatContent(req.body)
|
||||
const [created] = await server.db.insert(communicationMessages).values({
|
||||
tenantId, roomId: room.id, authorUserId: req.user.user_id, body,
|
||||
tenantId, roomId: room.id, authorUserId: req.user.user_id, body, image,
|
||||
}).returning()
|
||||
await notifyMessageRecipients(tenantId, room, req.user.user_id, { id: created.id, body })
|
||||
return { id: created.id, body: created.body, sender: created.authorUserId, senderDisplayName: "Du", timestamp: created.createdAt.getTime(), own: true }
|
||||
await notifyMessageRecipients(tenantId, room, req.user.user_id, { id: created.id, body: body || "📷 Bild" })
|
||||
return { id: created.id, body: created.body, image: imageMetadata(created.image), sender: created.authorUserId, senderDisplayName: "Du", timestamp: created.createdAt.getTime(), own: true }
|
||||
})
|
||||
|
||||
server.get("/communication/chat/rooms/:roomKey/image", async (req: any, reply) => {
|
||||
reply.header("Cache-Control", "no-store")
|
||||
const tenantId = await requireTenant(req)
|
||||
const room = await requireRoom(req, tenantId, req.user.user_id, req.params.roomKey)
|
||||
return chatImage(server.db, "communication", room.id, req.query.messageId)
|
||||
})
|
||||
server.get("/communication/chat/rooms/:roomKey/reactions", async (req: any, reply) => {
|
||||
reply.header("Cache-Control", "no-store")
|
||||
const tenantId = await requireTenant(req)
|
||||
const room = await requireRoom(req, tenantId, req.user.user_id, req.params.roomKey)
|
||||
return chatReactions(server.db, "communication", room.id, req.user.user_id, req.query.ids)
|
||||
})
|
||||
server.put("/communication/chat/rooms/:roomKey/reactions", async (req: any) => {
|
||||
const tenantId = await requireTenant(req)
|
||||
const room = await requireRoom(req, tenantId, req.user.user_id, req.params.roomKey)
|
||||
return setChatReaction(server.db, "communication", room.id, req.user.user_id, req.body)
|
||||
})
|
||||
|
||||
server.post("/communication/chat/rooms/:roomKey/read", async (req: any) => {
|
||||
|
||||
Reference in New Issue
Block a user