import { v } from "convex/values"; import { mutation, query } from "./_generated/server"; import { hashPassword } from "./auth/utils"; /** * Criar novo usuário (apenas TI) */ export const criar = mutation({ args: { matricula: v.string(), nome: v.string(), email: v.string(), roleId: v.id("roles"), funcionarioId: v.optional(v.id("funcionarios")), senhaInicial: v.string(), }, returns: v.union( v.object({ sucesso: v.literal(true), usuarioId: v.id("usuarios") }), v.object({ sucesso: v.literal(false), erro: v.string() }) ), handler: async (ctx, args) => { // Verificar se matrícula já existe const existente = await ctx.db .query("usuarios") .withIndex("by_matricula", (q) => q.eq("matricula", args.matricula)) .first(); if (existente) { return { sucesso: false as const, erro: "Matrícula já cadastrada" }; } // Verificar se email já existe const emailExistente = await ctx.db .query("usuarios") .withIndex("by_email", (q) => q.eq("email", args.email)) .first(); if (emailExistente) { return { sucesso: false as const, erro: "E-mail já cadastrado" }; } // Gerar hash da senha inicial const senhaHash = await hashPassword(args.senhaInicial); // Criar usuário const usuarioId = await ctx.db.insert("usuarios", { matricula: args.matricula, senhaHash, nome: args.nome, email: args.email, funcionarioId: args.funcionarioId, roleId: args.roleId, ativo: true, primeiroAcesso: true, criadoEm: Date.now(), atualizadoEm: Date.now(), }); return { sucesso: true as const, usuarioId }; }, }); /** * Listar todos os usuários com filtros */ export const listar = query({ args: { setor: v.optional(v.string()), matricula: v.optional(v.string()), ativo: v.optional(v.boolean()), }, returns: v.array( v.object({ _id: v.id("usuarios"), matricula: v.string(), nome: v.string(), email: v.string(), ativo: v.boolean(), primeiroAcesso: v.boolean(), ultimoAcesso: v.optional(v.number()), criadoEm: v.number(), role: v.object({ _id: v.id("roles"), nome: v.string(), nivel: v.number(), setor: v.optional(v.string()), }), funcionario: v.optional( v.object({ _id: v.id("funcionarios"), nome: v.string(), simboloTipo: v.union( v.literal("cargo_comissionado"), v.literal("funcao_gratificada") ), }) ), }) ), handler: async (ctx, args) => { let usuarios = await ctx.db.query("usuarios").collect(); // Filtrar por matrícula if (args.matricula) { usuarios = usuarios.filter((u) => u.matricula.includes(args.matricula!) ); } // Filtrar por ativo if (args.ativo !== undefined) { usuarios = usuarios.filter((u) => u.ativo === args.ativo); } // Buscar roles e funcionários const resultado = []; for (const usuario of usuarios) { const role = await ctx.db.get(usuario.roleId); if (!role) continue; // Filtrar por setor if (args.setor && role.setor !== args.setor) { continue; } let funcionario = undefined; if (usuario.funcionarioId) { const func = await ctx.db.get(usuario.funcionarioId); if (func) { funcionario = { _id: func._id, nome: func.nome, simboloTipo: func.simboloTipo, }; } } resultado.push({ _id: usuario._id, matricula: usuario.matricula, nome: usuario.nome, email: usuario.email, ativo: usuario.ativo, primeiroAcesso: usuario.primeiroAcesso, ultimoAcesso: usuario.ultimoAcesso, criadoEm: usuario.criadoEm, role: { _id: role._id, nome: role.nome, nivel: role.nivel, setor: role.setor, }, funcionario, }); } return resultado; }, }); /** * Ativar/Desativar usuário */ export const alterarStatus = mutation({ args: { usuarioId: v.id("usuarios"), ativo: v.boolean(), }, returns: v.null(), handler: async (ctx, args) => { await ctx.db.patch(args.usuarioId, { ativo: args.ativo, atualizadoEm: Date.now(), }); // Se desativar, desativar todas as sessões if (!args.ativo) { const sessoes = await ctx.db .query("sessoes") .withIndex("by_usuario", (q) => q.eq("usuarioId", args.usuarioId)) .collect(); for (const sessao of sessoes) { await ctx.db.patch(sessao._id, { ativo: false }); } } return null; }, }); /** * Resetar senha do usuário */ export const resetarSenha = mutation({ args: { usuarioId: v.id("usuarios"), novaSenha: v.string(), }, returns: v.null(), handler: async (ctx, args) => { const senhaHash = await hashPassword(args.novaSenha); await ctx.db.patch(args.usuarioId, { senhaHash, primeiroAcesso: true, atualizadoEm: Date.now(), }); // Desativar todas as sessões const sessoes = await ctx.db .query("sessoes") .withIndex("by_usuario", (q) => q.eq("usuarioId", args.usuarioId)) .collect(); for (const sessao of sessoes) { await ctx.db.patch(sessao._id, { ativo: false }); } return null; }, }); /** * Excluir usuário */ export const excluir = mutation({ args: { usuarioId: v.id("usuarios"), }, returns: v.null(), handler: async (ctx, args) => { // Excluir sessões const sessoes = await ctx.db .query("sessoes") .withIndex("by_usuario", (q) => q.eq("usuarioId", args.usuarioId)) .collect(); for (const sessao of sessoes) { await ctx.db.delete(sessao._id); } // Excluir usuário await ctx.db.delete(args.usuarioId); return null; }, }); /** * Ativar usuário */ export const ativar = mutation({ args: { id: v.id("usuarios"), }, returns: v.null(), handler: async (ctx, args) => { await ctx.db.patch(args.id, { ativo: true, atualizadoEm: Date.now(), }); return null; }, }); /** * Desativar usuário */ export const desativar = mutation({ args: { id: v.id("usuarios"), }, returns: v.null(), handler: async (ctx, args) => { await ctx.db.patch(args.id, { ativo: false, atualizadoEm: Date.now(), }); // Desativar todas as sessões const sessoes = await ctx.db .query("sessoes") .withIndex("by_usuario", (q) => q.eq("usuarioId", args.id)) .collect(); for (const sessao of sessoes) { await ctx.db.patch(sessao._id, { ativo: false }); } return null; }, }); /** * Alterar role de um usuário */ export const alterarRole = mutation({ args: { usuarioId: v.id("usuarios"), novaRoleId: v.id("roles"), }, returns: v.null(), handler: async (ctx, args) => { // Verificar se a role existe const role = await ctx.db.get(args.novaRoleId); if (!role) { throw new Error("Role não encontrada"); } // Atualizar usuário await ctx.db.patch(args.usuarioId, { roleId: args.novaRoleId, atualizadoEm: Date.now(), }); return null; }, });