Files
sgse-app/packages/backend/convex/usuarios.ts

321 lines
7.2 KiB
TypeScript

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;
},
});