sistema-de-chamados/src/app/api/admin/invites/[id]/route.ts

93 lines
3 KiB
TypeScript

import { NextResponse } from "next/server"
import { ConvexHttpClient } from "convex/browser"
// @ts-expect-error Convex runtime API lacks generated types at build time in Next routes
import { api } from "@/convex/_generated/api"
import { assertAdminSession } from "@/lib/auth-server"
import { env } from "@/lib/env"
import { prisma } from "@/lib/prisma"
import { computeInviteStatus, normalizeInvite, type NormalizedInvite } from "@/server/invite-utils"
type RevokePayload = {
reason?: string
}
async function syncInvite(invite: NormalizedInvite) {
const convexUrl = env.NEXT_PUBLIC_CONVEX_URL
if (!convexUrl) return
const client = new ConvexHttpClient(convexUrl)
await client.mutation(api.invites.sync, {
tenantId: invite.tenantId,
inviteId: invite.id,
email: invite.email,
name: invite.name ?? undefined,
role: invite.role.toUpperCase(),
status: invite.status,
token: invite.token,
expiresAt: Date.parse(invite.expiresAt),
createdAt: Date.parse(invite.createdAt),
createdById: invite.createdById ?? undefined,
acceptedAt: invite.acceptedAt ? Date.parse(invite.acceptedAt) : undefined,
acceptedById: invite.acceptedById ?? undefined,
revokedAt: invite.revokedAt ? Date.parse(invite.revokedAt) : undefined,
revokedById: invite.revokedById ?? undefined,
revokedReason: invite.revokedReason ?? undefined,
})
}
export async function PATCH(request: Request, { params }: { params: { id: string } }) {
const session = await assertAdminSession()
if (!session) {
return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
}
const body = (await request.json().catch(() => null)) as Partial<RevokePayload> | null
const reason = typeof body?.reason === "string" && body.reason.trim() ? body.reason.trim() : null
const invite = await prisma.authInvite.findUnique({
where: { id: params.id },
include: { events: { orderBy: { createdAt: "asc" } } },
})
if (!invite) {
return NextResponse.json({ error: "Convite não encontrado" }, { status: 404 })
}
const now = new Date()
const status = computeInviteStatus(invite, now)
if (status === "accepted") {
return NextResponse.json({ error: "Convite já aceito" }, { status: 400 })
}
if (status === "revoked") {
const normalized = normalizeInvite(invite, now)
await syncInvite(normalized)
return NextResponse.json({ invite: normalized })
}
const updated = await prisma.authInvite.update({
where: { id: invite.id },
data: {
status: "revoked",
revokedAt: now,
revokedById: session.user.id ?? null,
revokedReason: reason,
},
})
const event = await prisma.authInviteEvent.create({
data: {
inviteId: invite.id,
type: "revoked",
payload: reason ? { reason } : null,
actorId: session.user.id ?? null,
},
})
const normalized = normalizeInvite({ ...updated, events: [...invite.events, event] }, now)
await syncInvite(normalized)
return NextResponse.json({ invite: normalized })
}