- Updated user-related queries and mutations to retrieve the matricula from associated funcionario records, improving data accuracy. - Refactored user creation and listing functionalities to ensure matricula is correctly handled and displayed. - Enhanced error handling and validation for user operations, ensuring a more robust user management experience. - Improved the overall structure of user-related code for better maintainability and clarity.
233 lines
5.8 KiB
TypeScript
233 lines
5.8 KiB
TypeScript
import { v } from "convex/values";
|
|
import { mutation, query } from "./_generated/server";
|
|
|
|
/**
|
|
* Listar logs de acesso com filtros
|
|
*/
|
|
export const listar = query({
|
|
args: {
|
|
usuarioId: v.optional(v.id("usuarios")),
|
|
tipo: v.optional(
|
|
v.union(
|
|
v.literal("login"),
|
|
v.literal("logout"),
|
|
v.literal("acesso_negado"),
|
|
v.literal("senha_alterada"),
|
|
v.literal("sessao_expirada")
|
|
)
|
|
),
|
|
dataInicio: v.optional(v.number()),
|
|
dataFim: v.optional(v.number()),
|
|
limite: v.optional(v.number()),
|
|
},
|
|
returns: v.array(
|
|
v.object({
|
|
_id: v.id("logsAcesso"),
|
|
tipo: v.union(
|
|
v.literal("login"),
|
|
v.literal("logout"),
|
|
v.literal("acesso_negado"),
|
|
v.literal("senha_alterada"),
|
|
v.literal("sessao_expirada")
|
|
),
|
|
ipAddress: v.optional(v.string()),
|
|
userAgent: v.optional(v.string()),
|
|
detalhes: v.optional(v.string()),
|
|
timestamp: v.number(),
|
|
usuario: v.optional(
|
|
v.object({
|
|
_id: v.id("usuarios"),
|
|
matricula: v.string(),
|
|
nome: v.string(),
|
|
})
|
|
),
|
|
})
|
|
),
|
|
handler: async (ctx, args) => {
|
|
let logs;
|
|
|
|
// Filtrar por usuário
|
|
if (args.usuarioId !== undefined) {
|
|
const usuarioId = args.usuarioId; // TypeScript agora sabe que não é undefined
|
|
logs = await ctx.db
|
|
.query("logsAcesso")
|
|
.withIndex("by_usuario", (q) => q.eq("usuarioId", usuarioId))
|
|
.collect();
|
|
} else {
|
|
logs = await ctx.db
|
|
.query("logsAcesso")
|
|
.withIndex("by_timestamp")
|
|
.collect();
|
|
}
|
|
|
|
// Filtrar por tipo
|
|
if (args.tipo) {
|
|
logs = logs.filter((log) => log.tipo === args.tipo);
|
|
}
|
|
|
|
// Filtrar por data
|
|
if (args.dataInicio) {
|
|
logs = logs.filter((log) => log.timestamp >= args.dataInicio!);
|
|
}
|
|
if (args.dataFim) {
|
|
logs = logs.filter((log) => log.timestamp <= args.dataFim!);
|
|
}
|
|
|
|
// Ordenar por timestamp decrescente
|
|
logs.sort((a, b) => b.timestamp - a.timestamp);
|
|
|
|
// Limitar resultados
|
|
if (args.limite) {
|
|
logs = logs.slice(0, args.limite);
|
|
}
|
|
|
|
// Buscar informações dos usuários
|
|
const resultado = [];
|
|
for (const log of logs) {
|
|
let usuario = undefined;
|
|
if (log.usuarioId) {
|
|
const user = await ctx.db.get(log.usuarioId);
|
|
if (user) {
|
|
let matricula: string | undefined = undefined;
|
|
if (user.funcionarioId) {
|
|
const funcionario = await ctx.db.get(user.funcionarioId);
|
|
matricula = funcionario?.matricula;
|
|
}
|
|
usuario = {
|
|
_id: user._id,
|
|
matricula: matricula || "",
|
|
nome: user.nome,
|
|
};
|
|
}
|
|
}
|
|
|
|
resultado.push({
|
|
_id: log._id,
|
|
tipo: log.tipo,
|
|
ipAddress: log.ipAddress,
|
|
userAgent: log.userAgent,
|
|
detalhes: log.detalhes,
|
|
timestamp: log.timestamp,
|
|
usuario,
|
|
});
|
|
}
|
|
|
|
return resultado;
|
|
},
|
|
});
|
|
|
|
/**
|
|
* Obter estatísticas de acessos
|
|
*/
|
|
export const estatisticas = query({
|
|
args: {
|
|
dataInicio: v.optional(v.number()),
|
|
dataFim: v.optional(v.number()),
|
|
},
|
|
returns: v.object({
|
|
totalLogins: v.number(),
|
|
totalLogouts: v.number(),
|
|
totalAcessosNegados: v.number(),
|
|
totalSenhasAlteradas: v.number(),
|
|
totalSessoesExpiradas: v.number(),
|
|
loginsPorDia: v.array(
|
|
v.object({
|
|
data: v.string(),
|
|
quantidade: v.number(),
|
|
})
|
|
),
|
|
}),
|
|
handler: async (ctx, args) => {
|
|
let logs = await ctx.db.query("logsAcesso").collect();
|
|
|
|
// Filtrar por data
|
|
if (args.dataInicio) {
|
|
logs = logs.filter((log) => log.timestamp >= args.dataInicio!);
|
|
}
|
|
if (args.dataFim) {
|
|
logs = logs.filter((log) => log.timestamp <= args.dataFim!);
|
|
}
|
|
|
|
// Contar por tipo
|
|
const totalLogins = logs.filter((log) => log.tipo === "login").length;
|
|
const totalLogouts = logs.filter((log) => log.tipo === "logout").length;
|
|
const totalAcessosNegados = logs.filter(
|
|
(log) => log.tipo === "acesso_negado"
|
|
).length;
|
|
const totalSenhasAlteradas = logs.filter(
|
|
(log) => log.tipo === "senha_alterada"
|
|
).length;
|
|
const totalSessoesExpiradas = logs.filter(
|
|
(log) => log.tipo === "sessao_expirada"
|
|
).length;
|
|
|
|
// Agrupar logins por dia
|
|
const loginsPorDiaMap = new Map<string, number>();
|
|
const loginsOnly = logs.filter((log) => log.tipo === "login");
|
|
|
|
for (const log of loginsOnly) {
|
|
const data = new Date(log.timestamp).toISOString().split("T")[0];
|
|
loginsPorDiaMap.set(data, (loginsPorDiaMap.get(data) || 0) + 1);
|
|
}
|
|
|
|
const loginsPorDia = Array.from(loginsPorDiaMap.entries())
|
|
.map(([data, quantidade]) => ({ data, quantidade }))
|
|
.sort((a, b) => a.data.localeCompare(b.data));
|
|
|
|
return {
|
|
totalLogins,
|
|
totalLogouts,
|
|
totalAcessosNegados,
|
|
totalSenhasAlteradas,
|
|
totalSessoesExpiradas,
|
|
loginsPorDia,
|
|
};
|
|
},
|
|
});
|
|
|
|
/**
|
|
* Limpar logs antigos (apenas TI)
|
|
*/
|
|
export const limpar = mutation({
|
|
args: {
|
|
dataLimite: v.number(), // Excluir logs anteriores a esta data
|
|
},
|
|
returns: v.object({
|
|
excluidos: v.number(),
|
|
}),
|
|
handler: async (ctx, args) => {
|
|
const logs = await ctx.db
|
|
.query("logsAcesso")
|
|
.withIndex("by_timestamp")
|
|
.collect();
|
|
|
|
const logsAntigos = logs.filter((log) => log.timestamp < args.dataLimite);
|
|
|
|
for (const log of logsAntigos) {
|
|
await ctx.db.delete(log._id);
|
|
}
|
|
|
|
return { excluidos: logsAntigos.length };
|
|
},
|
|
});
|
|
|
|
/**
|
|
* Limpar todos os logs (apenas TI)
|
|
*/
|
|
export const limparTodos = mutation({
|
|
args: {},
|
|
returns: v.object({
|
|
excluidos: v.number(),
|
|
}),
|
|
handler: async (ctx) => {
|
|
const logs = await ctx.db.query("logsAcesso").collect();
|
|
|
|
for (const log of logs) {
|
|
await ctx.db.delete(log._id);
|
|
}
|
|
|
|
return { excluidos: logs.length };
|
|
},
|
|
});
|
|
|