refactor: streamline chat widget and backend user management
- Removed the .editorconfig file to simplify project configuration. - Refactored the ChatWidget component to enhance readability and maintainability, including the integration of current user data and improved notification handling. - Updated backend functions to utilize the new getCurrentUserFunction for user authentication, ensuring consistent user data retrieval across various modules. - Cleaned up code in multiple backend files, enhancing clarity and performance while maintaining functionality. - Improved error handling and user feedback mechanisms in user-related operations.
This commit is contained in:
@@ -1,211 +1,184 @@
|
||||
import { query, mutation, internalQuery } from "./_generated/server";
|
||||
import { v } from "convex/values";
|
||||
import type { Doc } from "./_generated/dataModel";
|
||||
import { query, mutation, internalQuery } from './_generated/server';
|
||||
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"],
|
||||
},
|
||||
{
|
||||
recurso: "simbolos",
|
||||
acoes: ["dashboard", "ver", "listar", "criar", "editar", "excluir"],
|
||||
},
|
||||
{
|
||||
recurso: 'funcionarios',
|
||||
acoes: ['dashboard', 'ver', 'listar', 'criar', 'editar', 'excluir']
|
||||
},
|
||||
{
|
||||
recurso: 'simbolos',
|
||||
acoes: ['dashboard', 'ver', 'listar', 'criar', 'editar', 'excluir']
|
||||
}
|
||||
] as const;
|
||||
|
||||
export const listarRecursosEAcoes = query({
|
||||
args: {},
|
||||
returns: v.array(
|
||||
v.object({
|
||||
recurso: v.string(),
|
||||
acoes: v.array(v.string()),
|
||||
})
|
||||
),
|
||||
handler: async () => {
|
||||
return CATALOGO_RECURSOS.map((r) => ({
|
||||
recurso: r.recurso,
|
||||
acoes: [...r.acoes],
|
||||
}));
|
||||
},
|
||||
args: {},
|
||||
returns: v.array(
|
||||
v.object({
|
||||
recurso: v.string(),
|
||||
acoes: v.array(v.string())
|
||||
})
|
||||
),
|
||||
handler: async () => {
|
||||
return CATALOGO_RECURSOS.map((r) => ({
|
||||
recurso: r.recurso,
|
||||
acoes: [...r.acoes]
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
export const listarPermissoesAcoesPorRole = query({
|
||||
args: { roleId: v.id("roles") },
|
||||
returns: v.array(
|
||||
v.object({
|
||||
recurso: v.string(),
|
||||
acoes: v.array(v.string()),
|
||||
})
|
||||
),
|
||||
handler: async (ctx, args) => {
|
||||
// Buscar vínculos permissao<-role
|
||||
const rolePerms = await ctx.db
|
||||
.query("rolePermissoes")
|
||||
.withIndex("by_role", (q) => q.eq("roleId", args.roleId))
|
||||
.collect();
|
||||
args: { roleId: v.id('roles') },
|
||||
returns: v.array(
|
||||
v.object({
|
||||
recurso: v.string(),
|
||||
acoes: v.array(v.string())
|
||||
})
|
||||
),
|
||||
handler: async (ctx, args) => {
|
||||
// Buscar vínculos permissao<-role
|
||||
const rolePerms = await ctx.db
|
||||
.query('rolePermissoes')
|
||||
.withIndex('by_role', (q) => q.eq('roleId', args.roleId))
|
||||
.collect();
|
||||
|
||||
// Carregar documentos de permissões
|
||||
const actionsByResource: Record<string, Set<string>> = {};
|
||||
for (const rp of rolePerms) {
|
||||
const perm = await ctx.db.get(rp.permissaoId);
|
||||
if (!perm) continue;
|
||||
const set = (actionsByResource[perm.recurso] ||= new Set<string>());
|
||||
set.add(perm.acao);
|
||||
}
|
||||
// Carregar documentos de permissões
|
||||
const actionsByResource: Record<string, Set<string>> = {};
|
||||
for (const rp of rolePerms) {
|
||||
const perm = await ctx.db.get(rp.permissaoId);
|
||||
if (!perm) continue;
|
||||
const set = (actionsByResource[perm.recurso] ||= new Set<string>());
|
||||
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;
|
||||
},
|
||||
// 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;
|
||||
}
|
||||
});
|
||||
|
||||
export const atualizarPermissaoAcao = mutation({
|
||||
args: {
|
||||
roleId: v.id("roles"),
|
||||
recurso: v.string(),
|
||||
acao: v.string(),
|
||||
conceder: v.boolean(),
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
// Garantir documento de permissão (recurso+acao)
|
||||
let permissao = await ctx.db
|
||||
.query("permissoes")
|
||||
.withIndex("by_recurso_e_acao", (q) =>
|
||||
q.eq("recurso", args.recurso).eq("acao", args.acao)
|
||||
)
|
||||
.first();
|
||||
args: {
|
||||
roleId: v.id('roles'),
|
||||
recurso: v.string(),
|
||||
acao: v.string(),
|
||||
conceder: v.boolean()
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
// Garantir documento de permissão (recurso+acao)
|
||||
let 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) {
|
||||
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;
|
||||
if (!permissao) return null;
|
||||
|
||||
// Verificar vínculo atual
|
||||
const existente = await ctx.db
|
||||
.query("rolePermissoes")
|
||||
.withIndex("by_role", (q) => q.eq("roleId", args.roleId))
|
||||
.collect();
|
||||
// Verificar vínculo atual
|
||||
const existente = await ctx.db
|
||||
.query('rolePermissoes')
|
||||
.withIndex('by_role', (q) => q.eq('roleId', args.roleId))
|
||||
.collect();
|
||||
|
||||
const vinculo = existente.find((rp) => rp.permissaoId === permissao!._id);
|
||||
const vinculo = existente.find((rp) => rp.permissaoId === permissao!._id);
|
||||
|
||||
if (args.conceder) {
|
||||
if (!vinculo) {
|
||||
await ctx.db.insert("rolePermissoes", {
|
||||
roleId: args.roleId,
|
||||
permissaoId: permissao._id,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (vinculo) {
|
||||
await ctx.db.delete(vinculo._id);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
if (args.conceder) {
|
||||
if (!vinculo) {
|
||||
await ctx.db.insert('rolePermissoes', {
|
||||
roleId: args.roleId,
|
||||
permissaoId: permissao._id
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (vinculo) {
|
||||
await ctx.db.delete(vinculo._id);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
export const verificarAcao = query({
|
||||
args: {
|
||||
usuarioId: v.id("usuarios"),
|
||||
recurso: v.string(),
|
||||
acao: v.string(),
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
const usuario = await ctx.db.get(args.usuarioId);
|
||||
if (!usuario) throw new Error("acesso_negado");
|
||||
args: {
|
||||
usuarioId: v.id('usuarios'),
|
||||
recurso: v.string(),
|
||||
acao: v.string()
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
const usuario = await ctx.db.get(args.usuarioId);
|
||||
if (!usuario) throw new Error('acesso_negado');
|
||||
|
||||
const role = await ctx.db.get(usuario.roleId);
|
||||
if (!role) throw new Error("acesso_negado");
|
||||
const role = await ctx.db.get(usuario.roleId);
|
||||
if (!role) throw new Error('acesso_negado');
|
||||
|
||||
// Níveis administrativos têm acesso total
|
||||
if (role.nivel <= 1) return null;
|
||||
// Níveis administrativos têm acesso total
|
||||
if (role.nivel <= 1) return null;
|
||||
|
||||
// Encontrar permissão
|
||||
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) throw new Error("acesso_negado");
|
||||
// Encontrar permissão
|
||||
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) throw new Error('acesso_negado');
|
||||
|
||||
const hasLink = await ctx.db
|
||||
.query("rolePermissoes")
|
||||
.withIndex("by_role", (q) => q.eq("roleId", usuario.roleId))
|
||||
.collect();
|
||||
const permitido = hasLink.some((rp) => rp.permissaoId === permissao!._id);
|
||||
if (!permitido) throw new Error("acesso_negado");
|
||||
return null;
|
||||
},
|
||||
const hasLink = await ctx.db
|
||||
.query('rolePermissoes')
|
||||
.withIndex('by_role', (q) => q.eq('roleId', usuario.roleId))
|
||||
.collect();
|
||||
const permitido = hasLink.some((rp) => rp.permissaoId === permissao!._id);
|
||||
if (!permitido) throw new Error('acesso_negado');
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
export const assertPermissaoAcaoAtual = internalQuery({
|
||||
args: {
|
||||
recurso: v.string(),
|
||||
acao: v.string(),
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
const identity = await ctx.auth.getUserIdentity();
|
||||
let usuarioAtual: Doc<"usuarios"> | null = null;
|
||||
args: {
|
||||
recurso: v.string(),
|
||||
acao: v.string()
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
const usuarioAtual: Doc<'usuarios'> | null = (await getCurrentUserFunction(ctx)) ?? null;
|
||||
if (!usuarioAtual) throw new Error('acesso_negado');
|
||||
|
||||
if (identity && identity.email) {
|
||||
usuarioAtual = await ctx.db
|
||||
.query("usuarios")
|
||||
.withIndex("by_email", (q) => q.eq("email", identity.email!))
|
||||
.first();
|
||||
}
|
||||
const role = await ctx.db.get(usuarioAtual.roleId);
|
||||
if (!role) throw new Error('acesso_negado');
|
||||
if (role.nivel <= 1) return null;
|
||||
|
||||
if (!usuarioAtual) {
|
||||
const sessaoAtiva = await ctx.db
|
||||
.query("sessoes")
|
||||
.filter((q) => q.eq(q.field("ativo"), true))
|
||||
.order("desc")
|
||||
.first();
|
||||
if (sessaoAtiva) {
|
||||
usuarioAtual = await ctx.db.get(sessaoAtiva.usuarioId);
|
||||
}
|
||||
}
|
||||
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) throw new Error('acesso_negado');
|
||||
|
||||
if (!usuarioAtual) throw new Error("acesso_negado");
|
||||
|
||||
const role = await ctx.db.get(usuarioAtual.roleId);
|
||||
if (!role) throw new Error("acesso_negado");
|
||||
if (role.nivel <= 1) return null;
|
||||
|
||||
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) throw new Error("acesso_negado");
|
||||
|
||||
const links = await ctx.db
|
||||
.query("rolePermissoes")
|
||||
.withIndex("by_role", (q) => q.eq("roleId", role._id))
|
||||
.collect();
|
||||
const ok = links.some((rp) => rp.permissaoId === permissao!._id);
|
||||
if (!ok) throw new Error("acesso_negado");
|
||||
return null;
|
||||
},
|
||||
const links = await ctx.db
|
||||
.query('rolePermissoes')
|
||||
.withIndex('by_role', (q) => q.eq('roleId', role._id))
|
||||
.collect();
|
||||
const ok = links.some((rp) => rp.permissaoId === permissao!._id);
|
||||
if (!ok) throw new Error('acesso_negado');
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user