KI-AGENT: Telefonie-Trunk in Firmeneinstellungen verschieben

This commit is contained in:
2026-05-21 16:19:56 +02:00
parent ee6c2d7420
commit f6fb607008
7 changed files with 408 additions and 15 deletions

View File

@@ -1,6 +1,6 @@
import { FastifyInstance } from "fastify"
import { and, desc, eq } from "drizzle-orm"
import { telephonyCalls } from "../../db/schema"
import { telephonyCalls, telephonyTrunks } from "../../db/schema"
const envFlag = (value: string | undefined, fallback: boolean) => {
if (value === undefined || value === "") return fallback
@@ -43,7 +43,20 @@ const testAccounts = () => [
},
]
const externalTelephonyConfig = () => {
const sanitizeTrunk = (trunk: any) => ({
id: trunk?.id || null,
provider: trunk?.provider || "telekom",
enabled: Boolean(trunk?.enabled),
registrar: trunk?.registrar || "tel.t-online.de",
sipUser: trunk?.sipUser || "",
authUser: trunk?.authUser || "",
passwordConfigured: Boolean(trunk?.password),
callerId: trunk?.callerId || "",
inboundExtension: trunk?.inboundExtension || "1001",
outboundPrefix: trunk?.outboundPrefix || "0",
})
const envExternalTelephonyConfig = () => {
const provider = process.env.TELEPHONY_EXTERNAL_PROVIDER || (
envFlag(process.env.TELEPHONY_TELEKOM_ENABLED, false) ? "telekom" : ""
)
@@ -107,16 +120,50 @@ const durationSeconds = (startedAt?: Date | null, endedAt?: Date | null) => {
}
export default async function telephonyRoutes(server: FastifyInstance) {
server.get("/telephony/config", async () => ({
enabled: telephonyEnabled(),
provider: "asterisk",
mode: "local-test",
sipDomain: sipDomain(),
sipWebSocketUrl: publicAsteriskWsUrl(),
echoExtension: process.env.TELEPHONY_ECHO_EXTENSION || "600",
testAccounts: testAccounts(),
external: externalTelephonyConfig(),
}))
const loadTenantTrunk = async (tenantId: number | null, provider = "telekom") => {
if (!tenantId) return null
const [trunk] = await server.db
.select()
.from(telephonyTrunks)
.where(and(
eq(telephonyTrunks.tenantId, tenantId),
eq(telephonyTrunks.provider, provider)
))
.limit(1)
return trunk || null
}
const externalTelephonyConfig = async (tenantId: number | null) => {
const trunk = await loadTenantTrunk(tenantId)
if (trunk) {
return {
enabled: trunk.enabled,
provider: trunk.provider,
inboundExtension: trunk.inboundExtension,
outboundPrefix: trunk.outboundPrefix,
registrar: trunk.registrar,
sipUserConfigured: Boolean(trunk.sipUser),
authUserConfigured: Boolean(trunk.authUser),
passwordConfigured: Boolean(trunk.password),
callerIdConfigured: Boolean(trunk.callerId),
}
}
return envExternalTelephonyConfig()
}
server.get("/telephony/config", async (req) => ({
enabled: telephonyEnabled(),
provider: "asterisk",
mode: "local-test",
sipDomain: sipDomain(),
sipWebSocketUrl: publicAsteriskWsUrl(),
echoExtension: process.env.TELEPHONY_ECHO_EXTENSION || "600",
testAccounts: testAccounts(),
external: await externalTelephonyConfig(req.user?.tenant_id || null),
}))
server.get("/telephony/status", async () => {
const enabled = telephonyEnabled()
@@ -169,6 +216,66 @@ export default async function telephonyRoutes(server: FastifyInstance) {
}
})
server.get("/telephony/trunk-config", async (req) => {
const tenantId = requireTenant(req.user.tenant_id)
const trunk = await loadTenantTrunk(tenantId)
return sanitizeTrunk(trunk)
})
server.put("/telephony/trunk-config", async (req, reply) => {
const tenantId = requireTenant(req.user.tenant_id)
const body = (req.body || {}) as any
const existing = await loadTenantTrunk(tenantId)
const password = bodyString(body, "password")
const clearPassword = body?.clearPassword === true
const now = new Date()
const values = {
tenantId,
provider: "telekom",
enabled: Boolean(body.enabled),
registrar: bodyString(body, "registrar") || "tel.t-online.de",
sipUser: bodyString(body, "sipUser"),
authUser: bodyString(body, "authUser"),
callerId: bodyString(body, "callerId"),
inboundExtension: bodyString(body, "inboundExtension") || "1001",
outboundPrefix: bodyString(body, "outboundPrefix") || "0",
password: clearPassword ? null : (password || existing?.password || null),
updatedAt: now,
updatedBy: req.user.user_id,
}
if (values.enabled && (!values.sipUser || !values.password)) {
return reply.code(400).send({
error: "SIP-ID und Kennwort sind erforderlich, wenn der Trunk aktiviert wird.",
})
}
if (existing) {
const [updated] = await server.db
.update(telephonyTrunks)
.set(values)
.where(and(
eq(telephonyTrunks.tenantId, tenantId),
eq(telephonyTrunks.provider, "telekom")
))
.returning()
return sanitizeTrunk(updated)
}
const [created] = await server.db
.insert(telephonyTrunks)
.values({
...values,
createdAt: now,
createdBy: req.user.user_id,
})
.returning()
return sanitizeTrunk(created)
})
server.get("/telephony/calls", async (req) => {
const tenantId = requireTenant(req.user.tenant_id)
const limit = Math.min(