feat: melhorar gerenciamento de acesso remoto de máquinas
This commit is contained in:
parent
714b199879
commit
192a5c2909
5 changed files with 664 additions and 261 deletions
|
|
@ -4,6 +4,7 @@ import { ConvexHttpClient } from "convex/browser"
|
|||
|
||||
import { assertStaffSession } from "@/lib/auth-server"
|
||||
import type { Id } from "@/convex/_generated/dataModel"
|
||||
import { api } from "@/convex/_generated/api"
|
||||
|
||||
export const runtime = "nodejs"
|
||||
|
||||
|
|
@ -13,7 +14,8 @@ const schema = z.object({
|
|||
identifier: z.string().optional(),
|
||||
url: z.string().optional(),
|
||||
notes: z.string().optional(),
|
||||
action: z.enum(["save", "clear"]).optional(),
|
||||
entryId: z.string().optional(),
|
||||
action: z.enum(["save", "upsert", "clear", "delete", "remove"]).optional(),
|
||||
})
|
||||
|
||||
export async function POST(request: Request) {
|
||||
|
|
@ -21,9 +23,6 @@ export async function POST(request: Request) {
|
|||
if (!session) {
|
||||
return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
|
||||
}
|
||||
if (!session.user.id) {
|
||||
return NextResponse.json({ error: "Sessão inválida" }, { status: 400 })
|
||||
}
|
||||
|
||||
let parsed: z.infer<typeof schema>
|
||||
try {
|
||||
|
|
@ -41,49 +40,103 @@ export async function POST(request: Request) {
|
|||
const client = new ConvexHttpClient(convexUrl)
|
||||
|
||||
try {
|
||||
const action = parsed.action ?? "save"
|
||||
const tenantId =
|
||||
session.user.tenantId ??
|
||||
process.env.SYNC_TENANT_ID ??
|
||||
process.env.SEED_USER_TENANT ??
|
||||
"tenant-atlas"
|
||||
const ensured = (await client.mutation(api.users.ensureUser, {
|
||||
tenantId,
|
||||
email: session.user.email,
|
||||
name: session.user.name ?? session.user.email,
|
||||
avatarUrl: session.user.avatarUrl ?? undefined,
|
||||
role: session.user.role.toUpperCase(),
|
||||
})) as { _id?: Id<"users"> } | null
|
||||
|
||||
if (action === "clear") {
|
||||
const result = (await (client as unknown as { mutation: (name: string, args: Record<string, unknown>) => Promise<unknown> }).mutation("machines:updateRemoteAccess", {
|
||||
machineId: parsed.machineId as Id<"machines">,
|
||||
actorId: session.user.id as Id<"users">,
|
||||
clear: true,
|
||||
})) as { remoteAccess?: unknown } | null
|
||||
return NextResponse.json({ ok: true, remoteAccess: result?.remoteAccess ?? null })
|
||||
const actorId = ensured?._id as Id<"users"> | undefined
|
||||
if (!actorId) {
|
||||
return NextResponse.json(
|
||||
{ error: "Usuário não encontrado no Convex para executar esta ação." },
|
||||
{ status: 403 }
|
||||
)
|
||||
}
|
||||
|
||||
const actionRaw = (parsed.action ?? "save").toLowerCase()
|
||||
const normalizedAction =
|
||||
actionRaw === "clear"
|
||||
? "clear"
|
||||
: actionRaw === "delete" || actionRaw === "remove"
|
||||
? "delete"
|
||||
: "upsert"
|
||||
|
||||
const provider = (parsed.provider ?? "").trim()
|
||||
const identifier = (parsed.identifier ?? "").trim()
|
||||
if (!provider || !identifier) {
|
||||
return NextResponse.json({ error: "Informe o provedor e o identificador do acesso remoto." }, { status: 400 })
|
||||
}
|
||||
const notes = (parsed.notes ?? "").trim()
|
||||
|
||||
let normalizedUrl: string | undefined
|
||||
const rawUrl = (parsed.url ?? "").trim()
|
||||
if (rawUrl.length > 0) {
|
||||
const candidate = /^https?:\/\//i.test(rawUrl) ? rawUrl : `https://${rawUrl}`
|
||||
try {
|
||||
new URL(candidate)
|
||||
normalizedUrl = candidate
|
||||
} catch {
|
||||
return NextResponse.json({ error: "URL inválida. Informe um endereço iniciado com http:// ou https://." }, { status: 422 })
|
||||
if (normalizedAction === "upsert") {
|
||||
if (!provider || !identifier) {
|
||||
return NextResponse.json({ error: "Informe o provedor e o identificador do acesso remoto." }, { status: 400 })
|
||||
}
|
||||
const rawUrl = (parsed.url ?? "").trim()
|
||||
if (rawUrl.length > 0) {
|
||||
const candidate = /^https?:\/\//i.test(rawUrl) ? rawUrl : `https://${rawUrl}`
|
||||
try {
|
||||
new URL(candidate)
|
||||
normalizedUrl = candidate
|
||||
} catch {
|
||||
return NextResponse.json({ error: "URL inválida. Informe um endereço iniciado com http:// ou https://." }, { status: 422 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const notes = (parsed.notes ?? "").trim()
|
||||
|
||||
const result = (await (client as unknown as { mutation: (name: string, args: Record<string, unknown>) => Promise<unknown> }).mutation("machines:updateRemoteAccess", {
|
||||
const mutationArgs: Record<string, unknown> = {
|
||||
machineId: parsed.machineId as Id<"machines">,
|
||||
actorId: session.user.id as Id<"users">,
|
||||
provider,
|
||||
identifier,
|
||||
url: normalizedUrl,
|
||||
notes: notes.length ? notes : undefined,
|
||||
})) as { remoteAccess?: unknown } | null
|
||||
actorId,
|
||||
action: normalizedAction,
|
||||
}
|
||||
|
||||
if (parsed.entryId) {
|
||||
mutationArgs.entryId = parsed.entryId
|
||||
}
|
||||
|
||||
if (normalizedAction === "clear") {
|
||||
mutationArgs.clear = true
|
||||
} else {
|
||||
if (provider) mutationArgs.provider = provider
|
||||
if (identifier) mutationArgs.identifier = identifier
|
||||
if (normalizedUrl !== undefined) mutationArgs.url = normalizedUrl
|
||||
if (notes.length) mutationArgs.notes = notes
|
||||
}
|
||||
|
||||
const result = (await (client as unknown as { mutation: (name: string, args: Record<string, unknown>) => Promise<unknown> }).mutation(
|
||||
"machines:updateRemoteAccess",
|
||||
mutationArgs
|
||||
)) as { remoteAccess?: unknown } | null
|
||||
|
||||
return NextResponse.json({ ok: true, remoteAccess: result?.remoteAccess ?? null })
|
||||
} catch (error) {
|
||||
console.error("[machines.remote-access]", error)
|
||||
return NextResponse.json({ error: "Falha ao atualizar acesso remoto" }, { status: 500 })
|
||||
const detail = error instanceof Error ? error.message : null
|
||||
const isOutdatedConvex =
|
||||
typeof detail === "string" && detail.includes("extra field `action`")
|
||||
|
||||
if (isOutdatedConvex) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Backend do Convex desatualizado",
|
||||
detail: "Recompile/deploy as funções Convex (ex.: `pnpm convex:dev` em desenvolvimento ou `npx convex deploy`) para aplicar o suporte a múltiplos acessos remotos.",
|
||||
},
|
||||
{ status: 409 }
|
||||
)
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Falha ao atualizar acesso remoto",
|
||||
...(process.env.NODE_ENV !== "production" && detail ? { detail } : {}),
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue