86 lines
2.6 KiB
Ruby
86 lines
2.6 KiB
Ruby
# app/models/mensagem_template.rb
|
|
#
|
|
# Corpo de um evento em UM canal, montado com blocos no editor.
|
|
#
|
|
# `blocos` vem de um campo hidden preenchido por JavaScript — ou seja, de fora.
|
|
# Por isso #normalizar_blocos DESCARTA o que não está no catálogo: tipo
|
|
# desconhecido, campo que aquele tipo não tem, e qualquer coisa que não seja
|
|
# Hash. Sem isso, um JSON adulterado no form viraria conteúdo renderizado sem
|
|
# passar por validação nenhuma.
|
|
class MensagemTemplate < ApplicationRecord
|
|
CANAIS = %w[whatsapp email].freeze
|
|
# Teto de segurança: um template com milhares de blocos só serviria para
|
|
# travar o render do e-mail.
|
|
MAX_BLOCOS = 40
|
|
MAX_LINHAS_TABELA = 20
|
|
|
|
belongs_to :evento_notificacao
|
|
|
|
validates :canal, inclusion: { in: CANAIS }
|
|
validates :canal, uniqueness: { scope: :evento_notificacao_id }
|
|
validate :assunto_no_email
|
|
|
|
before_validation :normalizar_blocos
|
|
|
|
scope :ativos, -> { where(ativo: true) }
|
|
scope :do_canal, ->(canal) { where(canal: canal.to_s) }
|
|
|
|
def email? = canal == 'email'
|
|
def whatsapp? = canal == 'whatsapp'
|
|
|
|
# Um template só entra em uso quando tem conteúdo — template ativo e vazio
|
|
# mandaria mensagem em branco, o que é pior do que cair no texto padrão.
|
|
def utilizavel?
|
|
ativo? && blocos.present?
|
|
end
|
|
|
|
def renderizador(dados = {})
|
|
Notificacao::Renderizador.new(blocos, dados)
|
|
end
|
|
|
|
def preview(dados = nil)
|
|
dados ||= Notificacao::CatalogoVariaveis.amostra(evento_notificacao&.gatilho)
|
|
r = renderizador(dados)
|
|
email? ? r.html : r.texto
|
|
end
|
|
|
|
private
|
|
|
|
def normalizar_blocos
|
|
lista = blocos.is_a?(Array) ? blocos : []
|
|
self.blocos = lista.filter_map { |bruto| limpar(bruto) }.first(MAX_BLOCOS)
|
|
end
|
|
|
|
def limpar(bruto)
|
|
return nil unless bruto.is_a?(Hash)
|
|
|
|
tipo = bruto['tipo'] || bruto[:tipo]
|
|
return nil unless Notificacao::Blocos.valido?(tipo)
|
|
|
|
limpo = { 'tipo' => tipo.to_s }
|
|
Notificacao::Blocos.campos(tipo).each do |campo, especie|
|
|
valor = bruto[campo] || bruto[campo.to_sym]
|
|
limpo[campo] = especie == :lista ? limpar_linhas(valor) : valor.to_s
|
|
end
|
|
limpo
|
|
end
|
|
|
|
def limpar_linhas(valor)
|
|
Array(valor).filter_map do |linha|
|
|
next unless linha.is_a?(Hash)
|
|
|
|
rotulo = (linha['rotulo'] || linha[:rotulo]).to_s
|
|
conteudo = (linha['valor'] || linha[:valor]).to_s
|
|
next if rotulo.blank? && conteudo.blank?
|
|
|
|
{ 'rotulo' => rotulo, 'valor' => conteudo }
|
|
end.first(MAX_LINHAS_TABELA)
|
|
end
|
|
|
|
def assunto_no_email
|
|
return unless email? && ativo? && blocos.present? && assunto.to_s.strip.blank?
|
|
|
|
errors.add(:assunto, 'é obrigatório no e-mail')
|
|
end
|
|
end
|