sistema-de-chamados/convex/ticketFormSettings.ts

149 lines
4.5 KiB
TypeScript

import { mutation, query } from "./_generated/server"
import type { MutationCtx, QueryCtx } from "./_generated/server"
import { ConvexError, v } from "convex/values"
import type { Id } from "./_generated/dataModel"
import { requireAdmin } from "./rbac"
const KNOWN_TEMPLATES = new Set(["admissao", "desligamento"])
const VALID_SCOPES = new Set(["tenant", "company", "user"])
function normalizeTemplate(input: string) {
const normalized = input.trim().toLowerCase()
if (!KNOWN_TEMPLATES.has(normalized)) {
throw new ConvexError("Template desconhecido")
}
return normalized
}
function normalizeScope(input: string) {
const normalized = input.trim().toLowerCase()
if (!VALID_SCOPES.has(normalized)) {
throw new ConvexError("Escopo inválido")
}
return normalized
}
export const list = query({
args: {
tenantId: v.string(),
viewerId: v.id("users"),
template: v.optional(v.string()),
},
handler: async (ctx, { tenantId, viewerId, template }) => {
await requireAdmin(ctx, viewerId, tenantId)
const normalizedTemplate = template ? normalizeTemplate(template) : null
const settings = await ctx.db
.query("ticketFormSettings")
.withIndex("by_tenant", (q) => q.eq("tenantId", tenantId))
.collect()
return settings
.filter((setting) => !normalizedTemplate || setting.template === normalizedTemplate)
.map((setting) => ({
id: setting._id,
template: setting.template,
scope: setting.scope,
companyId: setting.companyId ?? null,
userId: setting.userId ?? null,
enabled: setting.enabled,
createdAt: setting.createdAt,
updatedAt: setting.updatedAt,
actorId: setting.actorId ?? null,
}))
},
})
export const upsert = mutation({
args: {
tenantId: v.string(),
actorId: v.id("users"),
template: v.string(),
scope: v.string(),
companyId: v.optional(v.id("companies")),
userId: v.optional(v.id("users")),
enabled: v.boolean(),
},
handler: async (ctx, { tenantId, actorId, template, scope, companyId, userId, enabled }) => {
await requireAdmin(ctx, actorId, tenantId)
const normalizedTemplate = normalizeTemplate(template)
const normalizedScope = normalizeScope(scope)
if (normalizedScope === "company" && !companyId) {
throw new ConvexError("Informe a empresa para configurar o template")
}
if (normalizedScope === "user" && !userId) {
throw new ConvexError("Informe o usuário para configurar o template")
}
if (normalizedScope === "tenant") {
if (companyId || userId) {
throw new ConvexError("Escopo global não aceita empresa ou usuário")
}
}
const existing = await findExisting(ctx, tenantId, normalizedTemplate, normalizedScope, companyId, userId)
const now = Date.now()
if (existing) {
await ctx.db.patch(existing._id, {
enabled,
updatedAt: now,
actorId,
})
return existing._id
}
const id = await ctx.db.insert("ticketFormSettings", {
tenantId,
template: normalizedTemplate,
scope: normalizedScope,
companyId: normalizedScope === "company" ? (companyId as Id<"companies">) : undefined,
userId: normalizedScope === "user" ? (userId as Id<"users">) : undefined,
enabled,
createdAt: now,
updatedAt: now,
actorId,
})
return id
},
})
export const remove = mutation({
args: {
tenantId: v.string(),
actorId: v.id("users"),
settingId: v.id("ticketFormSettings"),
},
handler: async (ctx, { tenantId, actorId, settingId }) => {
await requireAdmin(ctx, actorId, tenantId)
const setting = await ctx.db.get(settingId)
if (!setting || setting.tenantId !== tenantId) {
throw new ConvexError("Configuração não encontrada")
}
await ctx.db.delete(settingId)
return { ok: true }
},
})
async function findExisting(
ctx: MutationCtx | QueryCtx,
tenantId: string,
template: string,
scope: string,
companyId?: Id<"companies">,
userId?: Id<"users">,
) {
const candidates = await ctx.db
.query("ticketFormSettings")
.withIndex("by_tenant_template_scope", (q) => q.eq("tenantId", tenantId).eq("template", template).eq("scope", scope))
.collect()
return candidates.find((setting) => {
if (scope === "tenant") return true
if (scope === "company") {
return setting.companyId && companyId && String(setting.companyId) === String(companyId)
}
if (scope === "user") {
return setting.userId && userId && String(setting.userId) === String(userId)
}
return false
}) ?? null
}