feat: implement advanced access control system with user blocking, rate limiting, and enhanced login security; update UI components for improved user experience and documentation
This commit is contained in:
261
packages/backend/convex/templatesMensagens.ts
Normal file
261
packages/backend/convex/templatesMensagens.ts
Normal file
@@ -0,0 +1,261 @@
|
||||
import { v } from "convex/values";
|
||||
import { mutation, query } from "./_generated/server";
|
||||
import { registrarAtividade } from "./logsAtividades";
|
||||
|
||||
/**
|
||||
* Listar todos os templates
|
||||
*/
|
||||
export const listarTemplates = query({
|
||||
args: {},
|
||||
handler: async (ctx) => {
|
||||
const templates = await ctx.db.query("templatesMensagens").collect();
|
||||
return templates;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Obter template por código
|
||||
*/
|
||||
export const obterTemplatePorCodigo = query({
|
||||
args: {
|
||||
codigo: v.string(),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
const template = await ctx.db
|
||||
.query("templatesMensagens")
|
||||
.withIndex("by_codigo", (q) => q.eq("codigo", args.codigo))
|
||||
.first();
|
||||
|
||||
return template;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Criar template customizado (apenas TI_MASTER)
|
||||
*/
|
||||
export const criarTemplate = mutation({
|
||||
args: {
|
||||
codigo: v.string(),
|
||||
nome: v.string(),
|
||||
titulo: v.string(),
|
||||
corpo: v.string(),
|
||||
variaveis: v.optional(v.array(v.string())),
|
||||
criadoPorId: v.id("usuarios"),
|
||||
},
|
||||
returns: v.union(
|
||||
v.object({ sucesso: v.literal(true), templateId: v.id("templatesMensagens") }),
|
||||
v.object({ sucesso: v.literal(false), erro: v.string() })
|
||||
),
|
||||
handler: async (ctx, args) => {
|
||||
// Verificar se código já existe
|
||||
const existente = await ctx.db
|
||||
.query("templatesMensagens")
|
||||
.withIndex("by_codigo", (q) => q.eq("codigo", args.codigo))
|
||||
.first();
|
||||
|
||||
if (existente) {
|
||||
return { sucesso: false as const, erro: "Código de template já existe" };
|
||||
}
|
||||
|
||||
// Criar template
|
||||
const templateId = await ctx.db.insert("templatesMensagens", {
|
||||
codigo: args.codigo,
|
||||
nome: args.nome,
|
||||
tipo: "customizado",
|
||||
titulo: args.titulo,
|
||||
corpo: args.corpo,
|
||||
variaveis: args.variaveis,
|
||||
criadoPor: args.criadoPorId,
|
||||
criadoEm: Date.now(),
|
||||
});
|
||||
|
||||
// Log de atividade
|
||||
await registrarAtividade(
|
||||
ctx,
|
||||
args.criadoPorId,
|
||||
"criar",
|
||||
"templates",
|
||||
JSON.stringify({ templateId, codigo: args.codigo, nome: args.nome }),
|
||||
templateId
|
||||
);
|
||||
|
||||
return { sucesso: true as const, templateId };
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Editar template customizado (apenas TI_MASTER, não edita templates do sistema)
|
||||
*/
|
||||
export const editarTemplate = mutation({
|
||||
args: {
|
||||
templateId: v.id("templatesMensagens"),
|
||||
nome: v.optional(v.string()),
|
||||
titulo: v.optional(v.string()),
|
||||
corpo: v.optional(v.string()),
|
||||
variaveis: v.optional(v.array(v.string())),
|
||||
editadoPorId: v.id("usuarios"),
|
||||
},
|
||||
returns: v.union(
|
||||
v.object({ sucesso: v.literal(true) }),
|
||||
v.object({ sucesso: v.literal(false), erro: v.string() })
|
||||
),
|
||||
handler: async (ctx, args) => {
|
||||
const template = await ctx.db.get(args.templateId);
|
||||
if (!template) {
|
||||
return { sucesso: false as const, erro: "Template não encontrado" };
|
||||
}
|
||||
|
||||
// Não permite editar templates do sistema
|
||||
if (template.tipo === "sistema") {
|
||||
return { sucesso: false as const, erro: "Templates do sistema não podem ser editados" };
|
||||
}
|
||||
|
||||
// Atualizar template
|
||||
const updates: any = {};
|
||||
if (args.nome !== undefined) updates.nome = args.nome;
|
||||
if (args.titulo !== undefined) updates.titulo = args.titulo;
|
||||
if (args.corpo !== undefined) updates.corpo = args.corpo;
|
||||
if (args.variaveis !== undefined) updates.variaveis = args.variaveis;
|
||||
|
||||
await ctx.db.patch(args.templateId, updates);
|
||||
|
||||
// Log de atividade
|
||||
await registrarAtividade(
|
||||
ctx,
|
||||
args.editadoPorId,
|
||||
"editar",
|
||||
"templates",
|
||||
JSON.stringify(updates),
|
||||
args.templateId
|
||||
);
|
||||
|
||||
return { sucesso: true as const };
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Excluir template customizado (apenas TI_MASTER, não exclui templates do sistema)
|
||||
*/
|
||||
export const excluirTemplate = mutation({
|
||||
args: {
|
||||
templateId: v.id("templatesMensagens"),
|
||||
excluidoPorId: v.id("usuarios"),
|
||||
},
|
||||
returns: v.union(
|
||||
v.object({ sucesso: v.literal(true) }),
|
||||
v.object({ sucesso: v.literal(false), erro: v.string() })
|
||||
),
|
||||
handler: async (ctx, args) => {
|
||||
const template = await ctx.db.get(args.templateId);
|
||||
if (!template) {
|
||||
return { sucesso: false as const, erro: "Template não encontrado" };
|
||||
}
|
||||
|
||||
// Não permite excluir templates do sistema
|
||||
if (template.tipo === "sistema") {
|
||||
return { sucesso: false as const, erro: "Templates do sistema não podem ser excluídos" };
|
||||
}
|
||||
|
||||
// Excluir template
|
||||
await ctx.db.delete(args.templateId);
|
||||
|
||||
// Log de atividade
|
||||
await registrarAtividade(
|
||||
ctx,
|
||||
args.excluidoPorId,
|
||||
"excluir",
|
||||
"templates",
|
||||
JSON.stringify({ templateId: args.templateId, codigo: template.codigo }),
|
||||
args.templateId
|
||||
);
|
||||
|
||||
return { sucesso: true as const };
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Renderizar template com variáveis
|
||||
*/
|
||||
export function renderizarTemplate(template: string, variaveis: Record<string, string>): string {
|
||||
let resultado = template;
|
||||
|
||||
for (const [chave, valor] of Object.entries(variaveis)) {
|
||||
const placeholder = `{{${chave}}}`;
|
||||
resultado = resultado.replace(new RegExp(placeholder, "g"), valor);
|
||||
}
|
||||
|
||||
return resultado;
|
||||
}
|
||||
|
||||
/**
|
||||
* Criar templates padrão do sistema (chamado no seed)
|
||||
*/
|
||||
export const criarTemplatesPadrao = mutation({
|
||||
args: {},
|
||||
handler: async (ctx) => {
|
||||
const templatesPadrao = [
|
||||
{
|
||||
codigo: "USUARIO_BLOQUEADO",
|
||||
nome: "Usuário Bloqueado",
|
||||
titulo: "Sua conta foi bloqueada",
|
||||
corpo: "Sua conta no SGSE foi bloqueada.\n\nMotivo: {{motivo}}\n\nPara mais informações, entre em contato com a TI.",
|
||||
variaveis: ["motivo"],
|
||||
},
|
||||
{
|
||||
codigo: "USUARIO_DESBLOQUEADO",
|
||||
nome: "Usuário Desbloqueado",
|
||||
titulo: "Sua conta foi desbloqueada",
|
||||
corpo: "Sua conta no SGSE foi desbloqueada e você já pode acessar o sistema normalmente.",
|
||||
variaveis: [],
|
||||
},
|
||||
{
|
||||
codigo: "SENHA_RESETADA",
|
||||
nome: "Senha Resetada",
|
||||
titulo: "Sua senha foi resetada",
|
||||
corpo: "Sua senha foi resetada pela equipe de TI.\n\nNova senha temporária: {{senha}}\n\nPor favor, altere sua senha no próximo login.",
|
||||
variaveis: ["senha"],
|
||||
},
|
||||
{
|
||||
codigo: "PERMISSAO_ALTERADA",
|
||||
nome: "Permissão Alterada",
|
||||
titulo: "Suas permissões foram atualizadas",
|
||||
corpo: "Suas permissões de acesso ao sistema foram atualizadas.\n\nPara verificar suas novas permissões, acesse o menu de perfil.",
|
||||
variaveis: [],
|
||||
},
|
||||
{
|
||||
codigo: "AVISO_GERAL",
|
||||
nome: "Aviso Geral",
|
||||
titulo: "{{titulo}}",
|
||||
corpo: "{{mensagem}}",
|
||||
variaveis: ["titulo", "mensagem"],
|
||||
},
|
||||
{
|
||||
codigo: "BEM_VINDO",
|
||||
nome: "Boas-vindas",
|
||||
titulo: "Bem-vindo ao SGSE",
|
||||
corpo: "Olá {{nome}},\n\nSeja bem-vindo ao Sistema de Gestão da Secretaria de Esportes!\n\nSuas credenciais de acesso:\nMatrícula: {{matricula}}\nSenha temporária: {{senha}}\n\nPor favor, altere sua senha no primeiro acesso.\n\nEquipe de TI",
|
||||
variaveis: ["nome", "matricula", "senha"],
|
||||
},
|
||||
];
|
||||
|
||||
for (const template of templatesPadrao) {
|
||||
// Verificar se já existe
|
||||
const existente = await ctx.db
|
||||
.query("templatesMensagens")
|
||||
.withIndex("by_codigo", (q) => q.eq("codigo", template.codigo))
|
||||
.first();
|
||||
|
||||
if (!existente) {
|
||||
await ctx.db.insert("templatesMensagens", {
|
||||
...template,
|
||||
tipo: "sistema",
|
||||
criadoEm: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { sucesso: true };
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user