KI-AGENT: Anrufhistorie für Telefonie ergänzen
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { FastifyInstance } from "fastify"
|
||||
import { and, desc, eq } from "drizzle-orm"
|
||||
import { telephonyCalls } from "../../db/schema"
|
||||
|
||||
const envFlag = (value: string | undefined, fallback: boolean) => {
|
||||
if (value === undefined || value === "") return fallback
|
||||
@@ -52,6 +54,32 @@ const fetchWithTimeout = async (url: string, timeoutMs = 2500) => {
|
||||
}
|
||||
}
|
||||
|
||||
const requireTenant = (tenantId: number | null) => {
|
||||
if (!tenantId) {
|
||||
throw Object.assign(new Error("Kein aktiver Mandant"), { statusCode: 400 })
|
||||
}
|
||||
|
||||
return tenantId
|
||||
}
|
||||
|
||||
const bodyString = (body: any, key: string) => {
|
||||
const value = body?.[key]
|
||||
return typeof value === "string" && value.trim() ? value.trim() : null
|
||||
}
|
||||
|
||||
const bodyDate = (body: any, key: string) => {
|
||||
const value = body?.[key]
|
||||
if (!value) return null
|
||||
|
||||
const date = new Date(value)
|
||||
return Number.isNaN(date.getTime()) ? null : date
|
||||
}
|
||||
|
||||
const durationSeconds = (startedAt?: Date | null, endedAt?: Date | null) => {
|
||||
if (!startedAt || !endedAt) return null
|
||||
return Math.max(0, Math.round((endedAt.getTime() - startedAt.getTime()) / 1000))
|
||||
}
|
||||
|
||||
export default async function telephonyRoutes(server: FastifyInstance) {
|
||||
server.get("/telephony/config", async () => ({
|
||||
enabled: telephonyEnabled(),
|
||||
@@ -113,4 +141,93 @@ export default async function telephonyRoutes(server: FastifyInstance) {
|
||||
: (lastError?.message || "Asterisk ist nicht erreichbar."),
|
||||
}
|
||||
})
|
||||
|
||||
server.get("/telephony/calls", async (req) => {
|
||||
const tenantId = requireTenant(req.user.tenant_id)
|
||||
const limit = Math.min(
|
||||
Math.max(Number((req.query as { limit?: string })?.limit || 25), 1),
|
||||
100
|
||||
)
|
||||
|
||||
return await server.db
|
||||
.select()
|
||||
.from(telephonyCalls)
|
||||
.where(eq(telephonyCalls.tenantId, tenantId))
|
||||
.orderBy(desc(telephonyCalls.startedAt))
|
||||
.limit(limit)
|
||||
})
|
||||
|
||||
server.post("/telephony/calls", async (req, reply) => {
|
||||
const tenantId = requireTenant(req.user.tenant_id)
|
||||
const body = (req.body || {}) as any
|
||||
const now = new Date()
|
||||
const startedAt = bodyDate(body, "startedAt") || now
|
||||
const direction = bodyString(body, "direction") === "incoming" ? "incoming" : "outgoing"
|
||||
const status = bodyString(body, "status") || (direction === "incoming" ? "ringing" : "dialing")
|
||||
|
||||
const [created] = await server.db
|
||||
.insert(telephonyCalls)
|
||||
.values({
|
||||
tenantId,
|
||||
direction,
|
||||
status,
|
||||
localExtension: bodyString(body, "localExtension"),
|
||||
remoteNumber: bodyString(body, "remoteNumber"),
|
||||
remoteDisplayName: bodyString(body, "remoteDisplayName"),
|
||||
sipCallId: bodyString(body, "sipCallId"),
|
||||
startedAt,
|
||||
createdBy: req.user.user_id,
|
||||
})
|
||||
.returning()
|
||||
|
||||
return reply.code(201).send(created)
|
||||
})
|
||||
|
||||
server.patch("/telephony/calls/:id", async (req, reply) => {
|
||||
const tenantId = requireTenant(req.user.tenant_id)
|
||||
const params = req.params as { id: string }
|
||||
const body = (req.body || {}) as any
|
||||
|
||||
const [existing] = await server.db
|
||||
.select()
|
||||
.from(telephonyCalls)
|
||||
.where(and(
|
||||
eq(telephonyCalls.tenantId, tenantId),
|
||||
eq(telephonyCalls.id, params.id)
|
||||
))
|
||||
.limit(1)
|
||||
|
||||
if (!existing) {
|
||||
return reply.code(404).send({ error: "Anruf nicht gefunden" })
|
||||
}
|
||||
|
||||
const answeredAt = bodyDate(body, "answeredAt")
|
||||
const endedAt = bodyDate(body, "endedAt")
|
||||
const startedAt = existing.startedAt ? new Date(existing.startedAt) : null
|
||||
const computedDuration = endedAt
|
||||
? durationSeconds(answeredAt || startedAt, endedAt)
|
||||
: null
|
||||
|
||||
const [updated] = await server.db
|
||||
.update(telephonyCalls)
|
||||
.set({
|
||||
status: bodyString(body, "status") || existing.status,
|
||||
localExtension: bodyString(body, "localExtension") || existing.localExtension,
|
||||
remoteNumber: bodyString(body, "remoteNumber") || existing.remoteNumber,
|
||||
remoteDisplayName: bodyString(body, "remoteDisplayName") || existing.remoteDisplayName,
|
||||
sipCallId: bodyString(body, "sipCallId") || existing.sipCallId,
|
||||
answeredAt: answeredAt || existing.answeredAt,
|
||||
endedAt: endedAt || existing.endedAt,
|
||||
durationSeconds: computedDuration ?? existing.durationSeconds,
|
||||
updatedAt: new Date(),
|
||||
updatedBy: req.user.user_id,
|
||||
})
|
||||
.where(and(
|
||||
eq(telephonyCalls.tenantId, tenantId),
|
||||
eq(telephonyCalls.id, params.id)
|
||||
))
|
||||
.returning()
|
||||
|
||||
return updated
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user