Merge branch 'master' into feat-cibersecurity
This commit is contained in:
36
packages/backend/convex/_generated/api.d.ts
vendored
36
packages/backend/convex/_generated/api.d.ts
vendored
@@ -15,9 +15,9 @@ import type * as actions_smtp from "../actions/smtp.js";
|
||||
import type * as actions_utils_nodeCrypto from "../actions/utils/nodeCrypto.js";
|
||||
import type * as atestadosLicencas from "../atestadosLicencas.js";
|
||||
import type * as ausencias from "../ausencias.js";
|
||||
import type * as auth from "../auth.js";
|
||||
import type * as auth_utils from "../auth/utils.js";
|
||||
import type * as chamados from "../chamados.js";
|
||||
import type * as auth from "../auth.js";
|
||||
import type * as chat from "../chat.js";
|
||||
import type * as configuracaoEmail from "../configuracaoEmail.js";
|
||||
import type * as crons from "../crons.js";
|
||||
@@ -29,7 +29,6 @@ import type * as ferias from "../ferias.js";
|
||||
import type * as funcionarios from "../funcionarios.js";
|
||||
import type * as healthCheck from "../healthCheck.js";
|
||||
import type * as http from "../http.js";
|
||||
import type * as limparPerfisAntigos from "../limparPerfisAntigos.js";
|
||||
import type * as logsAcesso from "../logsAcesso.js";
|
||||
import type * as logsAtividades from "../logsAtividades.js";
|
||||
import type * as logsLogin from "../logsLogin.js";
|
||||
@@ -56,6 +55,14 @@ import type {
|
||||
FunctionReference,
|
||||
} from "convex/server";
|
||||
|
||||
/**
|
||||
* A utility for referencing Convex functions in your app's API.
|
||||
*
|
||||
* Usage:
|
||||
* ```js
|
||||
* const myFunctionReference = api.myModule.myFunction;
|
||||
* ```
|
||||
*/
|
||||
declare const fullApi: ApiFromModules<{
|
||||
"actions/email": typeof actions_email;
|
||||
"actions/linkPreview": typeof actions_linkPreview;
|
||||
@@ -64,9 +71,9 @@ declare const fullApi: ApiFromModules<{
|
||||
"actions/utils/nodeCrypto": typeof actions_utils_nodeCrypto;
|
||||
atestadosLicencas: typeof atestadosLicencas;
|
||||
ausencias: typeof ausencias;
|
||||
auth: typeof auth;
|
||||
"auth/utils": typeof auth_utils;
|
||||
chamados: typeof chamados;
|
||||
auth: typeof auth;
|
||||
chat: typeof chat;
|
||||
configuracaoEmail: typeof configuracaoEmail;
|
||||
crons: typeof crons;
|
||||
@@ -78,7 +85,6 @@ declare const fullApi: ApiFromModules<{
|
||||
funcionarios: typeof funcionarios;
|
||||
healthCheck: typeof healthCheck;
|
||||
http: typeof http;
|
||||
limparPerfisAntigos: typeof limparPerfisAntigos;
|
||||
logsAcesso: typeof logsAcesso;
|
||||
logsAtividades: typeof logsAtividades;
|
||||
logsLogin: typeof logsLogin;
|
||||
@@ -99,30 +105,14 @@ declare const fullApi: ApiFromModules<{
|
||||
"utils/getClientIP": typeof utils_getClientIP;
|
||||
verificarMatriculas: typeof verificarMatriculas;
|
||||
}>;
|
||||
declare const fullApiWithMounts: typeof fullApi;
|
||||
|
||||
/**
|
||||
* A utility for referencing Convex functions in your app's public API.
|
||||
*
|
||||
* Usage:
|
||||
* ```js
|
||||
* const myFunctionReference = api.myModule.myFunction;
|
||||
* ```
|
||||
*/
|
||||
export declare const api: FilterApi<
|
||||
typeof fullApi,
|
||||
typeof fullApiWithMounts,
|
||||
FunctionReference<any, "public">
|
||||
>;
|
||||
|
||||
/**
|
||||
* A utility for referencing Convex functions in your app's internal API.
|
||||
*
|
||||
* Usage:
|
||||
* ```js
|
||||
* const myFunctionReference = internal.myModule.myFunction;
|
||||
* ```
|
||||
*/
|
||||
export declare const internal: FilterApi<
|
||||
typeof fullApi,
|
||||
typeof fullApiWithMounts,
|
||||
FunctionReference<any, "internal">
|
||||
>;
|
||||
|
||||
|
||||
16
packages/backend/convex/_generated/server.d.ts
vendored
16
packages/backend/convex/_generated/server.d.ts
vendored
@@ -10,6 +10,7 @@
|
||||
|
||||
import {
|
||||
ActionBuilder,
|
||||
AnyComponents,
|
||||
HttpActionBuilder,
|
||||
MutationBuilder,
|
||||
QueryBuilder,
|
||||
@@ -18,9 +19,15 @@ import {
|
||||
GenericQueryCtx,
|
||||
GenericDatabaseReader,
|
||||
GenericDatabaseWriter,
|
||||
FunctionReference,
|
||||
} from "convex/server";
|
||||
import type { DataModel } from "./dataModel.js";
|
||||
|
||||
type GenericCtx =
|
||||
| GenericActionCtx<DataModel>
|
||||
| GenericMutationCtx<DataModel>
|
||||
| GenericQueryCtx<DataModel>;
|
||||
|
||||
/**
|
||||
* Define a query in this Convex app's public API.
|
||||
*
|
||||
@@ -85,12 +92,11 @@ export declare const internalAction: ActionBuilder<DataModel, "internal">;
|
||||
/**
|
||||
* Define an HTTP action.
|
||||
*
|
||||
* The wrapped function will be used to respond to HTTP requests received
|
||||
* by a Convex deployment if the requests matches the path and method where
|
||||
* this action is routed. Be sure to route your httpAction in `convex/http.js`.
|
||||
* This function will be used to respond to HTTP requests received by a Convex
|
||||
* deployment if the requests matches the path and method where this action
|
||||
* is routed. Be sure to route your action in `convex/http.js`.
|
||||
*
|
||||
* @param func - The function. It receives an {@link ActionCtx} as its first argument
|
||||
* and a Fetch API `Request` object as its second.
|
||||
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
|
||||
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
||||
*/
|
||||
export declare const httpAction: HttpActionBuilder;
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
internalActionGeneric,
|
||||
internalMutationGeneric,
|
||||
internalQueryGeneric,
|
||||
componentsGeneric,
|
||||
} from "convex/server";
|
||||
|
||||
/**
|
||||
@@ -80,14 +81,10 @@ export const action = actionGeneric;
|
||||
export const internalAction = internalActionGeneric;
|
||||
|
||||
/**
|
||||
* Define an HTTP action.
|
||||
* Define a Convex HTTP action.
|
||||
*
|
||||
* The wrapped function will be used to respond to HTTP requests received
|
||||
* by a Convex deployment if the requests matches the path and method where
|
||||
* this action is routed. Be sure to route your httpAction in `convex/http.js`.
|
||||
*
|
||||
* @param func - The function. It receives an {@link ActionCtx} as its first argument
|
||||
* and a Fetch API `Request` object as its second.
|
||||
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
||||
* @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
|
||||
* as its second.
|
||||
* @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
|
||||
*/
|
||||
export const httpAction = httpActionGeneric;
|
||||
|
||||
@@ -1,285 +0,0 @@
|
||||
import { internalMutation, query } from "./_generated/server";
|
||||
import { v } from "convex/values";
|
||||
|
||||
/**
|
||||
* Listar todos os perfis (roles) do sistema
|
||||
*/
|
||||
export const listarTodosRoles = query({
|
||||
args: {},
|
||||
returns: v.array(
|
||||
v.object({
|
||||
_id: v.id("roles"),
|
||||
nome: v.string(),
|
||||
descricao: v.string(),
|
||||
nivel: v.number(),
|
||||
setor: v.optional(v.string()),
|
||||
customizado: v.optional(v.boolean()),
|
||||
editavel: v.optional(v.boolean()),
|
||||
_creationTime: v.number(),
|
||||
})
|
||||
),
|
||||
handler: async (ctx) => {
|
||||
const roles = await ctx.db.query("roles").collect();
|
||||
return roles.map((role) => ({
|
||||
_id: role._id,
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivel: role.nivel,
|
||||
setor: role.setor,
|
||||
customizado: role.customizado,
|
||||
editavel: role.editavel,
|
||||
_creationTime: role._creationTime,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Limpar perfis antigos/duplicados
|
||||
*
|
||||
* CRITÉRIOS:
|
||||
* - Manter apenas: ti_master (nível 0), admin (nível 2), ti_usuario (nível 2)
|
||||
* - Remover: admin antigo (nível 0), ti genérico (nível 1), outros duplicados
|
||||
*/
|
||||
export const limparPerfisAntigos = internalMutation({
|
||||
args: {},
|
||||
returns: v.object({
|
||||
removidos: v.array(
|
||||
v.object({
|
||||
nome: v.string(),
|
||||
descricao: v.string(),
|
||||
nivel: v.number(),
|
||||
motivo: v.string(),
|
||||
})
|
||||
),
|
||||
mantidos: v.array(
|
||||
v.object({
|
||||
nome: v.string(),
|
||||
descricao: v.string(),
|
||||
nivel: v.number(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
handler: async (ctx) => {
|
||||
const roles = await ctx.db.query("roles").collect();
|
||||
|
||||
const removidos: Array<{
|
||||
nome: string;
|
||||
descricao: string;
|
||||
nivel: number;
|
||||
motivo: string;
|
||||
}> = [];
|
||||
|
||||
const mantidos: Array<{
|
||||
nome: string;
|
||||
descricao: string;
|
||||
nivel: number;
|
||||
}> = [];
|
||||
|
||||
// Perfis que devem ser mantidos (apenas 1 de cada)
|
||||
const perfisCorretos = new Map<string, boolean>();
|
||||
perfisCorretos.set("ti_master", false);
|
||||
perfisCorretos.set("admin", false);
|
||||
perfisCorretos.set("ti_usuario", false);
|
||||
|
||||
for (const role of roles) {
|
||||
let deveManter = false;
|
||||
let motivo = "";
|
||||
|
||||
// TI_MASTER - Manter apenas o de nível 0
|
||||
if (role.nome === "ti_master") {
|
||||
if (role.nivel === 0 && !perfisCorretos.get("ti_master")) {
|
||||
deveManter = true;
|
||||
perfisCorretos.set("ti_master", true);
|
||||
} else {
|
||||
motivo =
|
||||
role.nivel !== 0
|
||||
? "TI_MASTER deve ser nível 0, este é nível " + role.nivel
|
||||
: "TI_MASTER duplicado";
|
||||
}
|
||||
}
|
||||
// ADMIN - Manter apenas o de nível 2
|
||||
else if (role.nome === "admin") {
|
||||
if (role.nivel === 2 && !perfisCorretos.get("admin")) {
|
||||
deveManter = true;
|
||||
perfisCorretos.set("admin", true);
|
||||
} else {
|
||||
motivo =
|
||||
role.nivel !== 2
|
||||
? "ADMIN deve ser nível 2, este é nível " + role.nivel
|
||||
: "ADMIN duplicado";
|
||||
}
|
||||
}
|
||||
// TI_USUARIO - Manter apenas o de nível 2
|
||||
else if (role.nome === "ti_usuario") {
|
||||
if (role.nivel === 2 && !perfisCorretos.get("ti_usuario")) {
|
||||
deveManter = true;
|
||||
perfisCorretos.set("ti_usuario", true);
|
||||
} else {
|
||||
motivo =
|
||||
role.nivel !== 2
|
||||
? "TI_USUARIO deve ser nível 2, este é nível " + role.nivel
|
||||
: "TI_USUARIO duplicado";
|
||||
}
|
||||
}
|
||||
// Perfis genéricos antigos (remover)
|
||||
else if (role.nome === "ti") {
|
||||
motivo =
|
||||
"Perfil genérico 'ti' obsoleto - usar 'ti_master' ou 'ti_usuario'";
|
||||
}
|
||||
// Outros perfis específicos de setores (manter se forem nível >= 2)
|
||||
else if (
|
||||
role.nome === "rh" ||
|
||||
role.nome === "financeiro" ||
|
||||
role.nome === "controladoria" ||
|
||||
role.nome === "licitacoes" ||
|
||||
role.nome === "compras" ||
|
||||
role.nome === "juridico" ||
|
||||
role.nome === "comunicacao" ||
|
||||
role.nome === "programas_esportivos" ||
|
||||
role.nome === "secretaria_executiva" ||
|
||||
role.nome === "gestao_pessoas" ||
|
||||
role.nome === "usuario"
|
||||
) {
|
||||
if (role.nivel >= 2) {
|
||||
deveManter = true;
|
||||
} else {
|
||||
motivo = `Perfil de setor com nível incorreto (${role.nivel}), deveria ser >= 2`;
|
||||
}
|
||||
}
|
||||
// Perfis customizados (manter sempre)
|
||||
else if (role.customizado) {
|
||||
deveManter = true;
|
||||
}
|
||||
// Outros perfis desconhecidos
|
||||
else {
|
||||
motivo = "Perfil desconhecido ou obsoleto";
|
||||
}
|
||||
|
||||
if (deveManter) {
|
||||
mantidos.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivel: role.nivel,
|
||||
});
|
||||
console.log(
|
||||
`✅ MANTIDO: ${role.nome} (${role.descricao}) - Nível ${role.nivel}`
|
||||
);
|
||||
} else {
|
||||
// Verificar se há usuários usando este perfil
|
||||
const usuariosComRole = await ctx.db
|
||||
.query("usuarios")
|
||||
.withIndex("by_role", (q) => q.eq("roleId", role._id))
|
||||
.collect();
|
||||
|
||||
if (usuariosComRole.length > 0) {
|
||||
console.log(
|
||||
`⚠️ AVISO: Não é possível remover "${role.nome}" porque ${usuariosComRole.length} usuário(s) ainda usa(m) este perfil`
|
||||
);
|
||||
mantidos.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivel: role.nivel,
|
||||
});
|
||||
} else {
|
||||
// Remover permissões associadas
|
||||
const permissoes = await ctx.db
|
||||
.query("rolePermissoes")
|
||||
.withIndex("by_role", (q) => q.eq("roleId", role._id))
|
||||
.collect();
|
||||
for (const perm of permissoes) {
|
||||
await ctx.db.delete(perm._id);
|
||||
}
|
||||
|
||||
// Remover o role
|
||||
await ctx.db.delete(role._id);
|
||||
|
||||
removidos.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivel: role.nivel,
|
||||
motivo: motivo || "Não especificado",
|
||||
});
|
||||
console.log(
|
||||
`🗑️ REMOVIDO: ${role.nome} (${role.descricao}) - Nível ${role.nivel} - Motivo: ${motivo}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { removidos, mantidos };
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Verificar se existem perfis com níveis incorretos
|
||||
*/
|
||||
export const verificarNiveisIncorretos = query({
|
||||
args: {},
|
||||
returns: v.array(
|
||||
v.object({
|
||||
nome: v.string(),
|
||||
descricao: v.string(),
|
||||
nivelAtual: v.number(),
|
||||
nivelCorreto: v.number(),
|
||||
problema: v.string(),
|
||||
})
|
||||
),
|
||||
handler: async (ctx) => {
|
||||
const roles = await ctx.db.query("roles").collect();
|
||||
const problemas: Array<{
|
||||
nome: string;
|
||||
descricao: string;
|
||||
nivelAtual: number;
|
||||
nivelCorreto: number;
|
||||
problema: string;
|
||||
}> = [];
|
||||
|
||||
for (const role of roles) {
|
||||
// TI_MASTER deve ser nível 0
|
||||
if (role.nome === "ti_master" && role.nivel !== 0) {
|
||||
problemas.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivelAtual: role.nivel,
|
||||
nivelCorreto: 0,
|
||||
problema: "TI_MASTER deve ter acesso total (nível 0)",
|
||||
});
|
||||
}
|
||||
|
||||
// ADMIN deve ser nível 2
|
||||
if (role.nome === "admin" && role.nivel !== 2) {
|
||||
problemas.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivelAtual: role.nivel,
|
||||
nivelCorreto: 2,
|
||||
problema: "ADMIN deve ser editável (nível 2)",
|
||||
});
|
||||
}
|
||||
|
||||
// TI_USUARIO deve ser nível 2
|
||||
if (role.nome === "ti_usuario" && role.nivel !== 2) {
|
||||
problemas.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivelAtual: role.nivel,
|
||||
nivelCorreto: 2,
|
||||
problema: "TI_USUARIO deve ser editável (nível 2)",
|
||||
});
|
||||
}
|
||||
|
||||
// Perfil genérico "ti" não deveria existir
|
||||
if (role.nome === "ti") {
|
||||
problemas.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivelAtual: role.nivel,
|
||||
nivelCorreto: -1, // Indica que deve ser removido
|
||||
problema: "Perfil genérico obsoleto - usar ti_master ou ti_usuario",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return problemas;
|
||||
},
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -3,27 +3,271 @@ import { v } from 'convex/values';
|
||||
import type { Doc } from './_generated/dataModel';
|
||||
import { getCurrentUserFunction } from './auth';
|
||||
|
||||
// Catálogo base de recursos e ações
|
||||
// Ajuste/expanda conforme os módulos disponíveis no sistema
|
||||
export const CATALOGO_RECURSOS = [
|
||||
{
|
||||
recurso: 'funcionarios',
|
||||
acoes: [
|
||||
'dashboard',
|
||||
'ver',
|
||||
'listar',
|
||||
'criar',
|
||||
'editar',
|
||||
'excluir',
|
||||
'aprovar_ausencias',
|
||||
'aprovar_ferias'
|
||||
]
|
||||
},
|
||||
{
|
||||
recurso: 'simbolos',
|
||||
acoes: ['dashboard', 'ver', 'listar', 'criar', 'editar', 'excluir']
|
||||
}
|
||||
] as const;
|
||||
// Catálogo de permissões base para seed controlado via mutation
|
||||
const PERMISSOES_BASE = {
|
||||
permissoes: [
|
||||
// Funcionários
|
||||
{
|
||||
nome: 'funcionarios.dashboard',
|
||||
recurso: 'funcionarios',
|
||||
acao: 'dashboard',
|
||||
descricao: 'Acessar o painel de funcionários'
|
||||
},
|
||||
{
|
||||
nome: 'funcionarios.ver',
|
||||
recurso: 'funcionarios',
|
||||
acao: 'ver',
|
||||
descricao: 'Visualizar detalhes de funcionários'
|
||||
},
|
||||
{
|
||||
nome: 'funcionarios.listar',
|
||||
recurso: 'funcionarios',
|
||||
acao: 'listar',
|
||||
descricao: 'Listar funcionários'
|
||||
},
|
||||
{
|
||||
nome: 'funcionarios.criar',
|
||||
recurso: 'funcionarios',
|
||||
acao: 'criar',
|
||||
descricao: 'Criar novos funcionários'
|
||||
},
|
||||
{
|
||||
nome: 'funcionarios.editar',
|
||||
recurso: 'funcionarios',
|
||||
acao: 'editar',
|
||||
descricao: 'Editar dados de funcionários'
|
||||
},
|
||||
{
|
||||
nome: 'funcionarios.excluir',
|
||||
recurso: 'funcionarios',
|
||||
acao: 'excluir',
|
||||
descricao: 'Excluir funcionários'
|
||||
},
|
||||
{
|
||||
nome: 'funcionarios.aprovar_ausencias',
|
||||
recurso: 'funcionarios',
|
||||
acao: 'aprovar_ausencias',
|
||||
descricao: 'Aprovar ausências de funcionários'
|
||||
},
|
||||
{
|
||||
nome: 'funcionarios.aprovar_ferias',
|
||||
recurso: 'funcionarios',
|
||||
acao: 'aprovar_ferias',
|
||||
descricao: 'Aprovar férias de funcionários'
|
||||
},
|
||||
// Símbolos
|
||||
{
|
||||
nome: 'simbolos.dashboard',
|
||||
recurso: 'simbolos',
|
||||
acao: 'dashboard',
|
||||
descricao: 'Acessar o painel de símbolos'
|
||||
},
|
||||
{
|
||||
nome: 'simbolos.ver',
|
||||
recurso: 'simbolos',
|
||||
acao: 'ver',
|
||||
descricao: 'Visualizar detalhes de símbolos'
|
||||
},
|
||||
{
|
||||
nome: 'simbolos.listar',
|
||||
recurso: 'simbolos',
|
||||
acao: 'listar',
|
||||
descricao: 'Listar símbolos'
|
||||
},
|
||||
{
|
||||
nome: 'simbolos.criar',
|
||||
recurso: 'simbolos',
|
||||
acao: 'criar',
|
||||
descricao: 'Criar novos símbolos'
|
||||
},
|
||||
{
|
||||
nome: 'simbolos.editar',
|
||||
recurso: 'simbolos',
|
||||
acao: 'editar',
|
||||
descricao: 'Editar símbolos'
|
||||
},
|
||||
{
|
||||
nome: 'simbolos.excluir',
|
||||
recurso: 'simbolos',
|
||||
acao: 'excluir',
|
||||
descricao: 'Excluir símbolos'
|
||||
},
|
||||
// TI - Usuários
|
||||
{
|
||||
nome: 'ti_usuarios.listar',
|
||||
recurso: 'ti_usuarios',
|
||||
acao: 'listar',
|
||||
descricao: 'Listar usuários do sistema'
|
||||
},
|
||||
{
|
||||
nome: 'ti_usuarios.criar',
|
||||
recurso: 'ti_usuarios',
|
||||
acao: 'criar',
|
||||
descricao: 'Criar novos usuários de acesso'
|
||||
},
|
||||
{
|
||||
nome: 'ti_usuarios.editar',
|
||||
recurso: 'ti_usuarios',
|
||||
acao: 'editar',
|
||||
descricao: 'Editar usuários de acesso'
|
||||
},
|
||||
{
|
||||
nome: 'ti_usuarios.bloquear',
|
||||
recurso: 'ti_usuarios',
|
||||
acao: 'bloquear',
|
||||
descricao: 'Bloquear ou desbloquear usuários'
|
||||
},
|
||||
// TI - Perfis
|
||||
{
|
||||
nome: 'ti_perfis.listar',
|
||||
recurso: 'ti_perfis',
|
||||
acao: 'listar',
|
||||
descricao: 'Listar perfis de acesso'
|
||||
},
|
||||
{
|
||||
nome: 'ti_perfis.criar',
|
||||
recurso: 'ti_perfis',
|
||||
acao: 'criar',
|
||||
descricao: 'Criar novos perfis de acesso'
|
||||
},
|
||||
{
|
||||
nome: 'ti_perfis.editar',
|
||||
recurso: 'ti_perfis',
|
||||
acao: 'editar',
|
||||
descricao: 'Editar perfis de acesso'
|
||||
},
|
||||
// TI - Painel de Permissões
|
||||
{
|
||||
nome: 'ti_painel_permissoes.gerenciar',
|
||||
recurso: 'ti_painel_permissoes',
|
||||
acao: 'gerenciar',
|
||||
descricao: 'Gerenciar matriz de permissões por perfil'
|
||||
},
|
||||
// TI - Solicitações de Acesso
|
||||
{
|
||||
nome: 'ti_solicitacoes_acesso.ver',
|
||||
recurso: 'ti_solicitacoes_acesso',
|
||||
acao: 'ver',
|
||||
descricao: 'Visualizar solicitações de acesso'
|
||||
},
|
||||
{
|
||||
nome: 'ti_solicitacoes_acesso.aprovar',
|
||||
recurso: 'ti_solicitacoes_acesso',
|
||||
acao: 'aprovar',
|
||||
descricao: 'Aprovar solicitações de acesso'
|
||||
},
|
||||
{
|
||||
nome: 'ti_solicitacoes_acesso.reprovar',
|
||||
recurso: 'ti_solicitacoes_acesso',
|
||||
acao: 'reprovar',
|
||||
descricao: 'Reprovar solicitações de acesso'
|
||||
},
|
||||
// TI - Configurações de E-mail
|
||||
{
|
||||
nome: 'ti_configuracoes_email.configurar',
|
||||
recurso: 'ti_configuracoes_email',
|
||||
acao: 'configurar',
|
||||
descricao: 'Configurar parâmetros de envio de e-mail'
|
||||
},
|
||||
// TI - Monitoramento
|
||||
{
|
||||
nome: 'ti_monitoramento.ver',
|
||||
recurso: 'ti_monitoramento',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar painel de monitoramento geral'
|
||||
},
|
||||
{
|
||||
nome: 'ti_monitoramento_emails.ver',
|
||||
recurso: 'ti_monitoramento_emails',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar monitoramento de envio de e-mails'
|
||||
},
|
||||
// TI - Notificações
|
||||
{
|
||||
nome: 'ti_notificacoes.configurar',
|
||||
recurso: 'ti_notificacoes',
|
||||
acao: 'configurar',
|
||||
descricao: 'Configurar notificações do sistema'
|
||||
},
|
||||
// TI - Times
|
||||
{
|
||||
nome: 'ti_times.gerenciar',
|
||||
recurso: 'ti_times',
|
||||
acao: 'gerenciar',
|
||||
descricao: 'Gerenciar times/equipes de TI'
|
||||
},
|
||||
// TI - Painel Administrativo
|
||||
{
|
||||
nome: 'ti_painel_administrativo.ver',
|
||||
recurso: 'ti_painel_administrativo',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar painel administrativo de TI'
|
||||
},
|
||||
// Financeiro
|
||||
{
|
||||
nome: 'financeiro.ver',
|
||||
recurso: 'financeiro',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar telas do módulo de financeiro'
|
||||
},
|
||||
// Controladoria
|
||||
{
|
||||
nome: 'controladoria.ver',
|
||||
recurso: 'controladoria',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar telas do módulo de controladoria'
|
||||
},
|
||||
// Licitações
|
||||
{
|
||||
nome: 'licitacoes.ver',
|
||||
recurso: 'licitacoes',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar telas do módulo de licitações'
|
||||
},
|
||||
// Compras
|
||||
{
|
||||
nome: 'compras.ver',
|
||||
recurso: 'compras',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar telas do módulo de compras'
|
||||
},
|
||||
// Jurídico
|
||||
{
|
||||
nome: 'juridico.ver',
|
||||
recurso: 'juridico',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar telas do módulo jurídico'
|
||||
},
|
||||
// Comunicação
|
||||
{
|
||||
nome: 'comunicacao.ver',
|
||||
recurso: 'comunicacao',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar telas do módulo de comunicação'
|
||||
},
|
||||
// Programas Esportivos
|
||||
{
|
||||
nome: 'programas_esportivos.ver',
|
||||
recurso: 'programas_esportivos',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar telas do módulo de programas esportivos'
|
||||
},
|
||||
// Secretaria Executiva
|
||||
{
|
||||
nome: 'secretaria_executiva.ver',
|
||||
recurso: 'secretaria_executiva',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar telas do módulo de secretaria executiva'
|
||||
},
|
||||
// Gestão de Pessoas
|
||||
{
|
||||
nome: 'gestao_pessoas.ver',
|
||||
recurso: 'gestao_pessoas',
|
||||
acao: 'ver',
|
||||
descricao: 'Acessar telas do módulo de gestão de pessoas'
|
||||
}
|
||||
]
|
||||
} as const;
|
||||
|
||||
export const listarRecursosEAcoes = query({
|
||||
args: {},
|
||||
@@ -33,10 +277,18 @@ export const listarRecursosEAcoes = query({
|
||||
acoes: v.array(v.string())
|
||||
})
|
||||
),
|
||||
handler: async () => {
|
||||
return CATALOGO_RECURSOS.map((r) => ({
|
||||
recurso: r.recurso,
|
||||
acoes: [...r.acoes]
|
||||
handler: async (ctx) => {
|
||||
const permissoes = await ctx.db.query('permissoes').collect();
|
||||
|
||||
const recursos: Record<string, Set<string>> = {};
|
||||
for (const perm of permissoes) {
|
||||
const set = (recursos[perm.recurso] ||= new Set<string>());
|
||||
set.add(perm.acao);
|
||||
}
|
||||
|
||||
return Object.entries(recursos).map(([recurso, acoes]) => ({
|
||||
recurso,
|
||||
acoes: Array.from(acoes).sort()
|
||||
}));
|
||||
}
|
||||
});
|
||||
@@ -56,7 +308,7 @@ export const listarPermissoesAcoesPorRole = query({
|
||||
.withIndex('by_role', (q) => q.eq('roleId', args.roleId))
|
||||
.collect();
|
||||
|
||||
// Carregar documentos de permissões
|
||||
// Carregar documentos de permissões vinculadas a este role
|
||||
const actionsByResource: Record<string, Set<string>> = {};
|
||||
for (const rp of rolePerms) {
|
||||
const perm = await ctx.db.get(rp.permissaoId);
|
||||
@@ -65,13 +317,10 @@ export const listarPermissoesAcoesPorRole = query({
|
||||
set.add(perm.acao);
|
||||
}
|
||||
|
||||
// Normalizar para todos os recursos do catálogo
|
||||
const result: Array<{ recurso: string; acoes: Array<string> }> = [];
|
||||
for (const item of CATALOGO_RECURSOS) {
|
||||
const granted = Array.from(actionsByResource[item.recurso] ?? new Set<string>());
|
||||
result.push({ recurso: item.recurso, acoes: granted });
|
||||
}
|
||||
return result;
|
||||
return Object.entries(actionsByResource).map(([recurso, acoes]) => ({
|
||||
recurso,
|
||||
acoes: Array.from(acoes).sort()
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -84,24 +333,12 @@ export const atualizarPermissaoAcao = mutation({
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
// Garantir documento de permissão (recurso+acao)
|
||||
let permissao = await ctx.db
|
||||
// Buscar documento de permissão (recurso+acao)
|
||||
const permissao = await ctx.db
|
||||
.query('permissoes')
|
||||
.withIndex('by_recurso_e_acao', (q) => q.eq('recurso', args.recurso).eq('acao', args.acao))
|
||||
.first();
|
||||
|
||||
if (!permissao) {
|
||||
const nome = `${args.recurso}.${args.acao}`;
|
||||
const descricao = `Permite ${args.acao} em ${args.recurso}`;
|
||||
const id = await ctx.db.insert('permissoes', {
|
||||
nome,
|
||||
descricao,
|
||||
recurso: args.recurso,
|
||||
acao: args.acao
|
||||
});
|
||||
permissao = await ctx.db.get(id);
|
||||
}
|
||||
|
||||
if (!permissao) return null;
|
||||
|
||||
// Verificar vínculo atual
|
||||
@@ -128,6 +365,36 @@ export const atualizarPermissaoAcao = mutation({
|
||||
}
|
||||
});
|
||||
|
||||
export const seedPermissoesBase = mutation({
|
||||
args: {},
|
||||
returns: v.null(),
|
||||
handler: async (ctx) => {
|
||||
console.log('🔐 Seed de permissões base...');
|
||||
|
||||
for (const perm of PERMISSOES_BASE.permissoes) {
|
||||
const existente = await ctx.db
|
||||
.query('permissoes')
|
||||
.withIndex('by_nome', (q) => q.eq('nome', perm.nome))
|
||||
.first();
|
||||
|
||||
if (existente) {
|
||||
console.log(` ℹ️ Permissão já existe: ${perm.nome}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await ctx.db.insert('permissoes', {
|
||||
nome: perm.nome,
|
||||
descricao: perm.descricao,
|
||||
recurso: perm.recurso,
|
||||
acao: perm.acao
|
||||
});
|
||||
console.log(` ✅ Permissão criada: ${perm.nome}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
export const verificarAcao = query({
|
||||
args: {
|
||||
usuarioId: v.id('usuarios'),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { v } from 'convex/values';
|
||||
import { query, mutation } from './_generated/server';
|
||||
import { internalMutation, query, mutation } from './_generated/server';
|
||||
import type { Id } from './_generated/dataModel';
|
||||
import { getCurrentUserFunction } from './auth';
|
||||
|
||||
@@ -98,13 +98,16 @@ export const criar = mutation({
|
||||
permissoesParaCopiar = permissoesOrigem.map((item) => item.permissaoId);
|
||||
}
|
||||
|
||||
const nivelAjustado = Math.min(Math.max(Math.round(args.nivel), 0), 10);
|
||||
// Agora só existem níveis 0 e 1.
|
||||
// 0 = máximo (acesso total), 1 = administrativo (também com acesso total).
|
||||
// Qualquer valor informado diferente de 0 é normalizado para 1.
|
||||
const nivelNormalizado = Math.round(args.nivel) <= 0 ? 0 : 1;
|
||||
const setor = args.setor?.trim();
|
||||
|
||||
const roleId = await ctx.db.insert('roles', {
|
||||
nome: nomeNormalizado,
|
||||
descricao: args.descricao.trim() || args.nome.trim(),
|
||||
nivel: nivelAjustado,
|
||||
nivel: nivelNormalizado,
|
||||
setor: setor && setor.length > 0 ? setor : undefined,
|
||||
customizado: true,
|
||||
criadoPor: usuarioAtual._id,
|
||||
@@ -123,3 +126,26 @@ export const criar = mutation({
|
||||
return { sucesso: true as const, roleId };
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Migração de níveis de roles para o novo modelo (apenas 0 e 1).
|
||||
* - Mantém níveis 0 e 1 como estão.
|
||||
* - Converte qualquer nível > 1 para 1.
|
||||
*/
|
||||
export const migrarNiveisRoles = internalMutation({
|
||||
args: {},
|
||||
returns: v.null(),
|
||||
handler: async (ctx) => {
|
||||
const roles = await ctx.db.query('roles').collect();
|
||||
|
||||
for (const role of roles) {
|
||||
if (role.nivel <= 1) continue;
|
||||
|
||||
await ctx.db.patch(role._id, {
|
||||
nivel: 1
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user