Browse Source

Sanitiza HTML/JavaScript nos campos TextField (stored XSS)

Os ~71 campos models.TextField do SAPL guardavam texto livre sem nenhuma
sanitização, e a renderização os tratava como HTML confiável em 142 pontos
(|safe, {% autoescape off %}). Qualquer usuário com permissão de edição
conseguia gravar <script> num campo e executá-lo no navegador de quem
abrisse a tela, inclusive nas páginas públicas (acompanhamento de matéria,
perfil público de parlamentar, resumo de sessão).

Duas camadas, ambas usando a mesma função idempotente para que não se
acumulem:

- Entrada: receiver pre_save global em sapl/base/receivers.py, cobrindo
  forms, a API do drfautoapi, o admin e o shell num único ponto.
- Saída: get_field_display() em sapl/crispy_layout_mixin.py — que monta o
  HTML de todo TextField para as telas de list/detail do CRUD — mais o
  novo filtro |sanitize nos templates. Protege as linhas gravadas antes
  desta mudança, já que não há backfill.

Políticas por campo, em sapl/sanitize.py:

- plain (padrão): remove toda a marcação e preserva o texto.
- rich: allowlist para os campos editados no TinyMCE (conteúdo de
  expediente, ocorrências, considerações finais e texto de dispositivo).
  Links continuam funcionando, com target e o alinhamento do editor
  preservados; javascript:, data:, on* e <script> são descartados.
- exempt: LexmlProvedor.xml e TipoTextoArticulado.rodape_global, que não
  são HTML.

Corrige também cinco |safe dentro de <textarea>, onde
</textarea><script> escapava do contexto, e cinco |striptags|safe — a
documentação do Django avisa que striptags não garante HTML seguro.

Sem migração de dados: as linhas existentes são neutralizadas na
renderização e limpas quando o registro for salvo de novo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
hotfix/sanitize-textfield-xss
Edward Ribeiro 1 day ago
parent
commit
f84a020c15
  1. 1
      requirements/requirements.txt
  2. 42
      sapl/base/receivers.py
  3. 12
      sapl/base/templatetags/common_tags.py
  4. 163
      sapl/base/tests/test_sanitize.py
  5. 5
      sapl/crispy_layout_mixin.py
  6. 132
      sapl/sanitize.py
  7. 2
      sapl/templates/comissoes/materias_em_tramitacao.html
  8. 2
      sapl/templates/compilacao/text_edit_bloco.html
  9. 2
      sapl/templates/compilacao/text_list_bloco.html
  10. 6
      sapl/templates/compilacao/text_list_blocoalteracao.html
  11. 2
      sapl/templates/compilacao/textoarticulado_detail.html
  12. 2
      sapl/templates/materia/acompanhamento_materia.html
  13. 2
      sapl/templates/materia/materialegislativa_filter.html
  14. 2
      sapl/templates/materia/resumo_detail_materia.html
  15. 2
      sapl/templates/norma/normajuridica_filter.html
  16. 2
      sapl/templates/parlamentares/parlamentar_perfil_publico.html
  17. 2
      sapl/templates/protocoloadm/acompanhamento_documento.html
  18. 2
      sapl/templates/protocoloadm/documentoadministrativo_filter.html
  19. 2
      sapl/templates/relatorios/RelatorioMateriasPorAutor_filter.html
  20. 2
      sapl/templates/relatorios/RelatorioNormasPorAutor_filter.html
  21. 2
      sapl/templates/relatorios/blocos_sessao_plenaria/consideracoes_finais.html
  22. 3
      sapl/templates/relatorios/blocos_sessao_plenaria/expedientes.html
  23. 2
      sapl/templates/relatorios/blocos_sessao_plenaria/ocorrencias_da_sessao.html
  24. 2
      sapl/templates/relatorios/relatorio_doc_administrativos.html
  25. 2
      sapl/templates/relatorios/relatorio_normas_por_autor.html
  26. 10
      sapl/templates/relatorios/relatorio_pauta_sessao.html
  27. 6
      sapl/templates/search/search.html
  28. 2
      sapl/templates/sessao/adicionar_varias_materias_expediente.html
  29. 2
      sapl/templates/sessao/blocos_ata/consideracoes_finais.html
  30. 2
      sapl/templates/sessao/blocos_ata/expedientes.html
  31. 2
      sapl/templates/sessao/blocos_ata/materias_expediente.html
  32. 2
      sapl/templates/sessao/blocos_ata/materias_ordem_dia.html
  33. 2
      sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html
  34. 3
      sapl/templates/sessao/blocos_resumo/consideracoes_finais.html
  35. 3
      sapl/templates/sessao/blocos_resumo/expedientes.html
  36. 3
      sapl/templates/sessao/blocos_resumo/ocorrencias_da_sessao.html
  37. 2
      sapl/templates/sessao/consideracoes_finais.html
  38. 2
      sapl/templates/sessao/leitura/leitura_bloco.html
  39. 2
      sapl/templates/sessao/ocorrencias_da_sessao.html
  40. 6
      sapl/templates/sessao/pauta_sessao_detail.html
  41. 2
      sapl/templates/sessao/votacao/nominal.html
  42. 6
      sapl/templates/sessao/votacao/nominal_detail.html
  43. 6
      sapl/templates/sessao/votacao/nominal_edit.html
  44. 2
      sapl/templates/sessao/votacao/nominal_transparencia.html
  45. 2
      sapl/templates/sessao/votacao/simbolica_transparencia.html
  46. 4
      sapl/templates/sessao/votacao/votacao.html
  47. 2
      sapl/templates/sessao/votacao/votacao_bloco.html
  48. 6
      sapl/templates/sessao/votacao/votacao_edit.html
  49. 4
      sapl/templates/sessao/votacao/votacao_nominal_bloco.html
  50. 8
      sapl/templates/sessao/votacao/votacao_simbolica_bloco.html

1
requirements/requirements.txt

@ -38,6 +38,7 @@ django-prometheus==2.2.0
asn1crypto==1.5.1 asn1crypto==1.5.1
XlsxWriter==3.2.0 XlsxWriter==3.2.0
nh3==0.2.22
setuptools==80.9.0 setuptools==80.9.0

42
sapl/base/receivers.py

@ -8,6 +8,7 @@ from django.conf import settings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core import serializers from django.core import serializers
from django.core.files.uploadedfile import InMemoryUploadedFile, UploadedFile from django.core.files.uploadedfile import InMemoryUploadedFile, UploadedFile
from django.db.models import TextField
from django.db.models.fields.files import FileField from django.db.models.fields.files import FileField
from django.db.models.signals import post_delete, post_save, \ from django.db.models.signals import post_delete, post_save, \
post_migrate, pre_save, pre_migrate post_migrate, pre_save, pre_migrate
@ -22,11 +23,15 @@ from sapl.decorators import receiver_multi_senders
from sapl.materia.models import Tramitacao from sapl.materia.models import Tramitacao
from sapl.parlamentares.models import Parlamentar from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import TramitacaoAdministrativo from sapl.protocoloadm.models import TramitacaoAdministrativo
from sapl.sanitize import sanitize_field
from sapl.utils import get_base_url, models_with_gr_for_model from sapl.utils import get_base_url, models_with_gr_for_model
models_with_gr_for_autor = models_with_gr_for_model(Autor) models_with_gr_for_autor = models_with_gr_for_model(Autor)
SAPL_APP_LABELS = frozenset(
app.rsplit('.', 1)[-1] for app in settings.SAPL_APPS)
@receiver_multi_senders(post_save, senders=models_with_gr_for_autor) @receiver_multi_senders(post_save, senders=models_with_gr_for_autor)
def handle_update_autor_related(sender, **kwargs): def handle_update_autor_related(sender, **kwargs):
@ -477,6 +482,43 @@ def signed_files_extraction_pre_save_signal(sender, instance, **kwargs):
signed_files_extraction_function(sender, instance, **kwargs) signed_files_extraction_function(sender, instance, **kwargs)
# Cache dos TextField por modelo: a introspecção de _meta.fields a cada save
# pesa mais que a própria sanitização, e compilacao salva Dispositivo em laço.
_text_fields_cache = {}
def get_text_fields(model):
try:
return _text_fields_cache[model]
except KeyError:
fields = [f.name for f in model._meta.fields
if isinstance(f, TextField)]
_text_fields_cache[model] = fields
return fields
@receiver(pre_save, dispatch_uid='sanitize_textfields_pre_save_signal')
def sanitize_textfields_pre_save_signal(sender, instance, **kwargs):
"""Remove HTML/JavaScript perigoso de todo TextField dos modelos do SAPL.
Cobre forms, a API do drfautoapi, o admin e o shell num único ponto.
Ver sapl.sanitize para as políticas por campo.
"""
if sender._meta.app_label not in SAPL_APP_LABELS:
return
for fieldname in get_text_fields(sender):
value = getattr(instance, fieldname, None)
if not value:
continue
sanitized = sanitize_field(sender, fieldname, value)
if sanitized != value:
setattr(instance, fieldname, sanitized)
@receiver(pre_migrate, dispatch_uid='disconnect_signals_pre_migrate') @receiver(pre_migrate, dispatch_uid='disconnect_signals_pre_migrate')
def disconnect_signals_pre_migrate(*args, **kwargs): def disconnect_signals_pre_migrate(*args, **kwargs):
# sanitize_textfields_pre_save_signal não é desconectado aqui de propósito:
# é barato e idempotente, e desconectá-lo deixaria sem proteção qualquer
# migrate rodado no mesmo processo (é o caso da suíte de testes).
pre_save.disconnect(dispatch_uid='signed_files_extraction_pre_save_signal') pre_save.disconnect(dispatch_uid='signed_files_extraction_pre_save_signal')

12
sapl/base/templatetags/common_tags.py

@ -10,6 +10,7 @@ from sapl.base.models import AppConfig
from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa, Proposicao from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa, Proposicao
from sapl.norma.models import NormaJuridica from sapl.norma.models import NormaJuridica
from sapl.parlamentares.models import Filiacao from sapl.parlamentares.models import Filiacao
from sapl.sanitize import sanitize_html
from sapl.sessao.models import SessaoPlenaria from sapl.sessao.models import SessaoPlenaria
from sapl.utils import filiacao_data, SEPARADOR_HASH_PROPOSICAO, is_report_allowed from sapl.utils import filiacao_data, SEPARADOR_HASH_PROPOSICAO, is_report_allowed
@ -396,6 +397,17 @@ def render_chunk_vendors(extension=None):
return '' return ''
@register.filter(is_safe=True)
@stringfilter
def sanitize(value):
"""Renderiza HTML de campo rico (TinyMCE) sem script nem URL perigosa.
Substitui o |safe nos campos que legitimamente guardam HTML. Protege
também as linhas gravadas antes da sanitização no pre_save.
"""
return mark_safe(sanitize_html(value, rich=True))
@register.filter(is_safe=True) @register.filter(is_safe=True)
@stringfilter @stringfilter
def dont_break_out(value): def dont_break_out(value):

163
sapl/base/tests/test_sanitize.py

@ -0,0 +1,163 @@
import pytest
from model_bakery import baker
from sapl.crispy_layout_mixin import get_field_display
from sapl.lexml.models import LexmlProvedor
from sapl.protocoloadm.models import TramitacaoAdministrativo
from sapl.sanitize import sanitize_field, sanitize_html, sanitize_scope
from sapl.sessao.models import ExpedienteSessao
def test_plain_remove_marcacao_e_preserva_texto():
assert sanitize_html('<script>alert(1)</script>Ciente') == 'Ciente'
assert sanitize_html('Encaminhado <b>ao</b> setor') == \
'Encaminhado ao setor'
assert sanitize_html('<img src=x onerror=alert(1)>') == ''
assert sanitize_html('<div>a</div><div>b</div>') == 'ab'
def test_plain_escapa_caracteres_especiais():
assert sanitize_html('Valor < 10 & prazo > 5') == \
'Valor &lt; 10 &amp; prazo &gt; 5'
def test_plain_preserva_quebras_de_linha():
# get_field_display converte \n em <br/> depois de sanitizar
assert sanitize_html('linha1\nlinha2') == 'linha1\nlinha2'
def test_valores_vazios_atravessam():
assert sanitize_html('') == ''
assert sanitize_html(None) is None
assert sanitize_html('', rich=True) == ''
@pytest.mark.parametrize('valor', [
'<script>alert(1)</script>Ciente',
'Valor < 10 & prazo > 5',
'Encaminhado <b>ao</b> <a href="https://x">setor</a>',
'texto &amp; cia',
])
def test_plain_e_idempotente(valor):
"""Propriedade da qual dependem as duas camadas (pre_save + renderização).
Se sanitizar duas vezes não fosse estável, o valor gravado seria
re-escapado a cada exibição.
"""
uma_vez = sanitize_html(valor)
assert sanitize_html(uma_vez) == uma_vez
@pytest.mark.parametrize('valor', [
'<a href="https://camara.gov.br" target="_blank">Portal</a>',
'<p style="text-align: center;">centro</p>',
'<table><tr><td colspan="2">c</td></tr></table>',
'<script>alert(1)</script><b>ok</b>',
])
def test_rich_e_idempotente(valor):
uma_vez = sanitize_html(valor, rich=True)
assert sanitize_html(uma_vez, rich=True) == uma_vez
def test_rich_preserva_links():
saida = sanitize_html(
'<a href="https://camara.gov.br" target="_blank">Portal</a>',
rich=True)
assert 'href="https://camara.gov.br"' in saida
assert 'target="_blank"' in saida
assert 'rel="noopener noreferrer"' in saida
assert '>Portal</a>' in saida
assert 'href="/materia/123"' in sanitize_html(
'<a href="/materia/123">Matéria</a>', rich=True)
assert 'href="mailto:a@b.c"' in sanitize_html(
'<a href="mailto:a@b.c">mail</a>', rich=True)
def test_rich_remove_href_perigosa_mas_mantem_o_texto():
saida = sanitize_html(
'<a href="javascript:alert(1)">clique</a>', rich=True)
assert 'javascript' not in saida
assert 'clique' in saida
def test_rich_remove_script_e_manipuladores_de_evento():
saida = sanitize_html('<script>alert(1)</script><b>ok</b>', rich=True)
assert saida == '<b>ok</b>'
assert 'onclick' not in sanitize_html(
'<a href="#" onclick="steal()">x</a>', rich=True)
assert 'onerror' not in sanitize_html(
'<img src="x" onerror="alert(1)">', rich=True)
def test_rich_preserva_formatacao_do_tinymce():
"""Protege contra regressão visual no conteúdo já cadastrado."""
assert 'style="text-align: center;"' in sanitize_html(
'<p style="text-align: center;">centro</p>', rich=True)
saida = sanitize_html(
'<table><tr><td colspan="2">c</td></tr></table>', rich=True)
assert '<table>' in saida and 'colspan="2"' in saida
assert sanitize_html('<ul><li>a</li><li>b</li></ul>', rich=True) == \
'<ul><li>a</li><li>b</li></ul>'
def test_sanitize_scope():
assert sanitize_scope(TramitacaoAdministrativo, 'texto') == 'plain'
assert sanitize_scope(ExpedienteSessao, 'conteudo') == 'rich'
assert sanitize_scope(LexmlProvedor, 'xml') == 'exempt'
def test_sanitize_field_respeita_isencao():
xml = '<xml><a href="javascript:x">y</a></xml>'
assert sanitize_field(LexmlProvedor, 'xml', xml) == xml
@pytest.mark.django_db
def test_pre_save_sanitiza_campo_simples():
t = baker.make(TramitacaoAdministrativo,
texto='<script>alert(1)</script>Ciente <b>ok</b>')
t.refresh_from_db()
assert t.texto == 'Ciente ok'
@pytest.mark.django_db
def test_pre_save_sanitiza_campo_rico_preservando_html():
e = baker.make(ExpedienteSessao,
conteudo='<b>x</b><script>alert(1)</script>'
'<a href="https://a.b" target="_blank">l</a>')
e.refresh_from_db()
assert '<script>' not in e.conteudo
assert '<b>x</b>' in e.conteudo
assert 'href="https://a.b"' in e.conteudo
@pytest.mark.django_db
def test_pre_save_nao_toca_modelo_isento():
xml = '<xml>a &amp; b <script>x</script></xml>'
p = baker.make(LexmlProvedor, xml=xml)
p.refresh_from_db()
assert p.xml == xml
@pytest.mark.django_db
def test_get_field_display_nao_devolve_script():
t = TramitacaoAdministrativo(texto='<script>alert(1)</script>Ciente')
__, display = get_field_display(t, 'texto')
assert '<script>' not in display
assert 'Ciente' in display
@pytest.mark.django_db
def test_get_field_display_protege_linha_legada():
"""Linhas gravadas antes do pre_save não passam pela camada de entrada."""
t = baker.make(TramitacaoAdministrativo, texto='ok')
TramitacaoAdministrativo.objects.filter(pk=t.pk).update(
texto='<script>alert(1)</script>legado')
t.refresh_from_db()
assert t.texto == '<script>alert(1)</script>legado'
__, display = get_field_display(t, 'texto')
assert '<script>' not in display

5
sapl/crispy_layout_mixin.py

@ -11,6 +11,8 @@ from django.utils.encoding import force_text
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
import yaml import yaml
from sapl.sanitize import sanitize_field
def heads_and_tails(list_of_lists): def heads_and_tails(list_of_lists):
for alist in list_of_lists: for alist in list_of_lists:
@ -167,7 +169,8 @@ def get_field_display(obj, fieldname):
args=(value.id,)), args=(value.id,)),
value) value)
elif 'TextField' in str_type_from_field: elif 'TextField' in str_type_from_field:
display = value.replace('\n', '<br/>') display = sanitize_field(obj._meta.model, fieldname, value)
display = display.replace('\n', '<br/>')
display = '<div class="dont-break-out">{}</div>'.format(display) display = '<div class="dont-break-out">{}</div>'.format(display)
else: else:
display = str(value) display = str(value)

132
sapl/sanitize.py

@ -0,0 +1,132 @@
"""Sanitização de HTML/JavaScript nos campos de texto livre do SAPL.
Módulo sem dependências internas do SAPL de propósito: é importado por
``sapl.crispy_layout_mixin``, ``sapl.base.receivers`` e pelos templatetags,
e ``sapl.utils`` importa ``sapl.crispy_layout_mixin``.
Duas políticas:
* ``plain`` remove toda a marcação e preserva o texto. É o padrão para
qualquer ``TextField``.
* ``rich`` allowlist para os campos editados via TinyMCE, que contêm HTML
legítimo (negrito, listas, tabelas e links).
Ambas são idempotentes: aplicar duas vezes produz o mesmo resultado. É essa
propriedade que permite sanitizar tanto no ``pre_save`` quanto na renderização
sem que os efeitos se acumulem.
"""
import nh3
SANITIZE_RICH_TAGS = {
'p', 'br', 'hr', 'div', 'span',
'b', 'strong', 'i', 'em', 'u', 's', 'strike', 'sub', 'sup',
'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'blockquote', 'pre', 'code',
'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'caption',
'col', 'colgroup',
'a', 'img',
}
# 'style' mantém o alinhamento produzido pelos botões do TinyMCE;
# 'target' mantém o "abrir em nova aba" dos links já cadastrados.
# 'rel' não pode entrar aqui: o nh3 aborta se a tag 'a' declarar 'rel'
# ao mesmo tempo em que link_rel está definido — ele mesmo escreve o atributo.
SANITIZE_RICH_ATTRS = {
'*': {'style', 'class', 'align', 'title', 'dir', 'lang'},
'a': {'href', 'target', 'name'},
'img': {'src', 'alt', 'width', 'height'},
'td': {'colspan', 'rowspan', 'headers'},
'th': {'colspan', 'rowspan', 'scope', 'headers'},
'col': {'span'},
'colgroup': {'span'},
'table': {'border', 'cellpadding', 'cellspacing', 'summary'},
}
SANITIZE_URL_SCHEMES = {'http', 'https', 'mailto', 'tel'}
# O conteúdo destas tags é descartado junto com a tag. Sem isso o texto de
# dentro de um <script> sobreviveria como texto solto.
SANITIZE_CLEAN_CONTENT_TAGS = {'script', 'style'}
# Campos que guardam HTML legítimo, indexados por '<app_label>.<Model>'.
# Os de sessao e compilacao.Dispositivo são editados no TinyMCE; os de
# compilacao.TipoDispositivo são fragmentos de template configurados por
# administradores.
RICH_TEXT_FIELDS = {
'sessao.ExpedienteSessao': {'conteudo'},
'sessao.OcorrenciaSessao': {'conteudo'},
'sessao.ConsideracoesFinais': {'conteudo'},
'compilacao.Dispositivo': {'texto', 'texto_atualizador'},
'compilacao.TipoDispositivo': {
'rotulo_prefixo_html', 'rotulo_sufixo_html',
'texto_prefixo_html', 'texto_sufixo_html',
'nota_automatica_prefixo_html', 'nota_automatica_sufixo_html',
},
}
# Modelos cujos TextField não devem ser tocados em hipótese alguma.
SANITIZE_EXEMPT_MODELS = {
# xml é XML fornecido pela equipe do LexML; já é escapado em pretty_xml
'lexml.LexmlProvedor',
# rodape_global é interpolado dentro de um content: de CSS
'compilacao.TipoTextoArticulado',
}
def model_key(model):
return '{}.{}'.format(model._meta.app_label, model.__name__)
def sanitize_scope(model, fieldname):
"""Retorna 'exempt', 'rich' ou 'plain' para um campo de um modelo."""
key = model_key(model)
if key in SANITIZE_EXEMPT_MODELS:
return 'exempt'
if fieldname in RICH_TEXT_FIELDS.get(key, ()):
return 'rich'
return 'plain'
def sanitize_html(value, rich=False):
"""Remove HTML/JavaScript perigoso de ``value``.
Com ``rich=False`` toda a marcação é removida e apenas o texto sobra.
Com ``rich=True`` aplica-se a allowlist: links são preservados, mas
esquemas de URL fora de SANITIZE_URL_SCHEMES (javascript:, data:) e
manipuladores de evento (onclick, onerror) são descartados.
"""
if not value:
return value
if not isinstance(value, str):
value = str(value)
if rich:
return nh3.clean(
value,
tags=SANITIZE_RICH_TAGS,
attributes=SANITIZE_RICH_ATTRS,
url_schemes=SANITIZE_URL_SCHEMES,
clean_content_tags=SANITIZE_CLEAN_CONTENT_TAGS,
link_rel='noopener noreferrer',
strip_comments=True)
return nh3.clean(
value,
tags=set(),
attributes={},
clean_content_tags=SANITIZE_CLEAN_CONTENT_TAGS,
link_rel=None,
strip_comments=True)
def sanitize_field(model, fieldname, value):
"""Sanitiza ``value`` conforme a política do campo.
Campos de modelos isentos atravessam sem modificação.
"""
scope = sanitize_scope(model, fieldname)
if scope == 'exempt':
return value
return sanitize_html(value, rich=(scope == 'rich'))

2
sapl/templates/comissoes/materias_em_tramitacao.html

@ -38,7 +38,7 @@
{{ materia_em_tramitacao.materia.ementa|dont_break_out }} {{ materia_em_tramitacao.materia.ementa|dont_break_out }}
</td> </td>
<td> <td>
{{ materia_em_tramitacao.tramitacao.status.descricao|linebreaksbr|safe }} {{ materia_em_tramitacao.tramitacao.status.descricao|linebreaksbr }}
</td> </td>
<td> <td>
{% if materia_em_tramitacao.tramitacao.data_fim_prazo %} {% if materia_em_tramitacao.tramitacao.data_fim_prazo %}

2
sapl/templates/compilacao/text_edit_bloco.html

@ -43,7 +43,7 @@
{% if not node.dpt.texto and not node.td.dispositivo_de_articulacao %} {% if not node.dpt.texto and not node.td.dispositivo_de_articulacao %}
<span class="semtexto">({{node.td}} sem texto)</span> <span class="semtexto">({{node.td}} sem texto)</span>
{%else%} {%else%}
{% if node.da and node.dpt.texto_atualizador and node in node.da.alts%}{{ node.dpt.texto_atualizador|safe }}{% else %}{{ node.dpt.texto|safe }}{% endif %} {% if node.da and node.dpt.texto_atualizador and node in node.da.alts%}{{ node.dpt.texto_atualizador|sanitize }}{% else %}{{ node.dpt.texto|sanitize }}{% endif %}
{%endif%} {%endif%}
{% if node.na %} {% if node.na %}
<a class="dpt-link nota-alteracao" href="{% url 'sapl.compilacao:ta_text_edit' node.da.dpt.ta_id %}#{{node.da.dpt.pk}}" title="{% trans 'Abrir Edição do Dispositivo Alterador'%}"> <a class="dpt-link nota-alteracao" href="{% url 'sapl.compilacao:ta_text_edit' node.da.dpt.ta_id %}#{{node.da.dpt.pk}}" title="{% trans 'Abrir Edição do Dispositivo Alterador'%}">

2
sapl/templates/compilacao/text_list_bloco.html

@ -32,7 +32,7 @@
{% endif %} {% endif %}
<div class="dtxt" id="d{% if not dpt.dispositivo_subsequente_id and dpt.dispositivo_substituido_id %}a{% endif %}{{dpt.pk}}" pks="{{dpt.dispositivo_substituido_id|default:''}}" pk="{{dpt.pk}}">{{ dpt.tipo_dispositivo.texto_prefixo_html|safe }}{%if dpt.texto %}{{ dpt.texto|safe }}{%else%}{%if not dpt.tipo_dispositivo.dispositivo_de_articulacao %}&nbsp;{% endif %}{% endif %}</div> <div class="dtxt" id="d{% if not dpt.dispositivo_subsequente_id and dpt.dispositivo_substituido_id %}a{% endif %}{{dpt.pk}}" pks="{{dpt.dispositivo_substituido_id|default:''}}" pk="{{dpt.pk}}">{{ dpt.tipo_dispositivo.texto_prefixo_html|safe }}{%if dpt.texto %}{{ dpt.texto|sanitize }}{%else%}{%if not dpt.tipo_dispositivo.dispositivo_de_articulacao %}&nbsp;{% endif %}{% endif %}</div>
{% if dpt.ta_publicado_id %} {% if dpt.ta_publicado_id %}
<a class="nota-alteracao" href="{%url 'sapl.compilacao:ta_text' dpt.ta_publicado.pk %}#{{dpt.dispositivo_atualizador_id}}"> <a class="nota-alteracao" href="{%url 'sapl.compilacao:ta_text' dpt.ta_publicado.pk %}#{{dpt.dispositivo_atualizador_id}}">
{{ dpt.tipo_dispositivo.nota_automatica_prefixo_html|safe }} {{ dpt.tipo_dispositivo.nota_automatica_prefixo_html|safe }}

6
sapl/templates/compilacao/text_list_blocoalteracao.html

@ -19,15 +19,15 @@
{% if ch.rotulo %} {% if ch.rotulo %}
<a name="{{ch.pk}}" href="{% url 'sapl.compilacao:ta_text' ch.ta.pk %}#{{ch.pk}}">{{ ch.rotulo }}</a> <a name="{{ch.pk}}" href="{% url 'sapl.compilacao:ta_text' ch.ta.pk %}#{{ch.pk}}">{{ ch.rotulo }}</a>
{{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }} {{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }}
{{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{% if ch.texto_atualizador %}{{ ch.texto_atualizador|safe }}{%else%}{{ ch.texto|safe }}{% endif %} {{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{% if ch.texto_atualizador %}{{ ch.texto_atualizador|sanitize }}{%else%}{{ ch.texto|sanitize }}{% endif %}
{% elif not ch.rotulo and not ch.auto_inserido %} {% elif not ch.rotulo and not ch.auto_inserido %}
<a name="{{ch.pk}}" href="{% url 'sapl.compilacao:ta_text' ch.ta.pk %}#{{ch.pk}}"> <a name="{{ch.pk}}" href="{% url 'sapl.compilacao:ta_text' ch.ta.pk %}#{{ch.pk}}">
{{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }} {{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }}
{{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{% if ch.texto_atualizador %}{{ ch.texto_atualizador|safe }}{%else%}{{ ch.texto|safe }}{% endif %} {{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{% if ch.texto_atualizador %}{{ ch.texto_atualizador|sanitize }}{%else%}{{ ch.texto|sanitize }}{% endif %}
</a> </a>
{% else %} {% else %}
{{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }} {{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }}
{{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{% if ch.texto_atualizador %}{{ ch.texto_atualizador|safe }}{%else%}{{ ch.texto|safe }}{% endif %} {{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{% if ch.texto_atualizador %}{{ ch.texto_atualizador|sanitize }}{%else%}{{ ch.texto|sanitize }}{% endif %}
{% endif %} {% endif %}
{% if ch.imagem %} {% if ch.imagem %}

2
sapl/templates/compilacao/textoarticulado_detail.html

@ -75,7 +75,7 @@
<div class="col-md-12"> <div class="col-md-12">
<div id="div_id_ementa" class="holder"> <div id="div_id_ementa" class="holder">
<label>{% field_verbose_name object 'ementa' %}</label> <label>{% field_verbose_name object 'ementa' %}</label>
<p>{{ object.ementa|safe}}</p> <p>{{ object.ementa}}</p>
</div> </div>
</div> </div>
</div> </div>

2
sapl/templates/materia/acompanhamento_materia.html

@ -19,7 +19,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-12"><b>Ementa:</b> {{materia.ementa|safe}}</div> <div class="col-md-12"><b>Ementa:</b> {{materia.ementa}}</div>
</div> </div>
{% crispy form %} {% crispy form %}

2
sapl/templates/materia/materialegislativa_filter.html

@ -153,7 +153,7 @@
{% if m.tramitacao_set.first.data_tramitacao %} {% if m.tramitacao_set.first.data_tramitacao %}
<strong>Data da última Tramitação:</strong> &nbsp;{{m.tramitacao_set.first.data_tramitacao}}</br> <strong>Data da última Tramitação:</strong> &nbsp;{{m.tramitacao_set.first.data_tramitacao}}</br>
{% if m.tramitacao_set.first.texto %} {% if m.tramitacao_set.first.texto %}
<strong>Última Ação:</strong> &nbsp; {{m.tramitacao_set.first.texto|safe}}</br> <strong>Última Ação:</strong> &nbsp; {{m.tramitacao_set.first.texto}}</br>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if m.anexo_de.exists %} {% if m.anexo_de.exists %}

2
sapl/templates/materia/resumo_detail_materia.html

@ -3,5 +3,5 @@
<div class="col-md-4"><b>Número: </b>{{object.numero}}</div> <div class="col-md-4"><b>Número: </b>{{object.numero}}</div>
<div class="col-md-4"><b>Ano: </b>{{object.ano}}</div> <div class="col-md-4"><b>Ano: </b>{{object.ano}}</div>
</div> </div>
<b>Ementa:</b> {{object.ementa|safe}} <b>Ementa:</b> {{object.ementa}}
<br /><br /> <br /><br />

2
sapl/templates/norma/normajuridica_filter.html

@ -62,7 +62,7 @@
{% endif %} {% endif %}
<strong>Ementa:</strong><br> <strong>Ementa:</strong><br>
{{n.ementa|safe}}<br> {{n.ementa}}<br>
{% if n.texto_articulado.exists and not n.texto_articulado.first.privacidade %} {% if n.texto_articulado.exists and not n.texto_articulado.first.privacidade %}
<a href="{% url 'sapl.norma:normajuridica_detail' n.id %}"> <a href="{% url 'sapl.norma:normajuridica_detail' n.id %}">

2
sapl/templates/parlamentares/parlamentar_perfil_publico.html

@ -61,7 +61,7 @@
<div class="col-sm-8"> <div class="col-sm-8">
<div id="div_biografia" class="form-group"> <div id="div_biografia" class="form-group">
<p><b>Biografia: </b> &nbsp {{object.biografia|safe}}</p> <p><b>Biografia: </b> &nbsp {{object.biografia|linebreaksbr}}</p>
</div> </div>
</div> </div>
</div> </div>

2
sapl/templates/protocoloadm/acompanhamento_documento.html

@ -19,7 +19,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-12"><b>Assunto:</b> {{documento.assunto|safe}}</div> <div class="col-md-12"><b>Assunto:</b> {{documento.assunto}}</div>
</div> </div>
{% crispy form %} {% crispy form %}

2
sapl/templates/protocoloadm/documentoadministrativo_filter.html

@ -48,7 +48,7 @@
<a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' d.id %}"><strong>{{d}}</strong></a></br> <a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' d.id %}"><strong>{{d}}</strong></a></br>
<strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não informado"}} <strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não informado"}}
</br> </br>
<strong>Assunto:</strong>&nbsp;{{ d.assunto|safe }} <strong>Assunto:</strong>&nbsp;{{ d.assunto }}
</br> </br>
{% if d.protocolo %} {% if d.protocolo %}
<strong>Protocolo:</strong>&nbsp;<a href="{% url 'sapl.protocoloadm:protocolo_mostrar' d.protocolo.id %}">{{ d.protocolo}}</a></br> <strong>Protocolo:</strong>&nbsp;<a href="{% url 'sapl.protocoloadm:protocolo_mostrar' d.protocolo.id %}">{{ d.protocolo}}</a></br>

2
sapl/templates/relatorios/RelatorioMateriasPorAutor_filter.html

@ -54,7 +54,7 @@
{{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
</a> </a>
</td> </td>
<td>{% autoescape off %}{{materia.ementa}}<br>{{materia.observacao}}{% endautoescape %}</td> <td>{{materia.ementa}}<br>{{materia.observacao}}</td>
<td> <td>
{% for autoria in materia.autoria_set.all %} {% for autoria in materia.autoria_set.all %}
{% if autoria.autor != autor %} {% if autoria.autor != autor %}

2
sapl/templates/relatorios/RelatorioNormasPorAutor_filter.html

@ -52,7 +52,7 @@
<td><a href="{% url 'sapl.norma:normajuridica_detail' norma.pk %}"> <td><a href="{% url 'sapl.norma:normajuridica_detail' norma.pk %}">
{{norma.tipo.sigla}} {{norma.numero}}/{{norma.ano}} {{norma.tipo.sigla}} {{norma.numero}}/{{norma.ano}}
</a></td> </a></td>
<td>{% autoescape off %}{{norma.ementa}}<br>{{norma.observacao}}{% endautoescape %}</td> <td>{{norma.ementa}}<br>{{norma.observacao}}</td>
<td> <td>
{% for autoria in norma.autorianorma_set.all %} {% for autoria in norma.autorianorma_set.all %}
{% if autoria.autor != autor %} {% if autoria.autor != autor %}

2
sapl/templates/relatorios/blocos_sessao_plenaria/consideracoes_finais.html

@ -1,4 +1,4 @@
<h2 class="gray-title">Considerações Finais</h2> <h2 class="gray-title">Considerações Finais</h2>
{% for c in lst_consideracoes%} {% for c in lst_consideracoes%}
<p>{{c|striptags|safe}}</p> <p>{{c|striptags}}</p>
{% endfor %} {% endfor %}

3
sapl/templates/relatorios/blocos_sessao_plenaria/expedientes.html

@ -1,5 +1,6 @@
{% load common_tags %}
<h2 class="gray-title">Expedientes</h2> <h2 class="gray-title">Expedientes</h2>
{% for expediente in lst_expedientes%} {% for expediente in lst_expedientes%}
<h3>{{expediente.nom_expediente}}</h3> <h3>{{expediente.nom_expediente}}</h3>
<div style="margin-bottom: 1cm">{{expediente.txt_expediente|safe}}</div> <div style="margin-bottom: 1cm">{{expediente.txt_expediente|sanitize}}</div>
{% endfor%} {% endfor%}

2
sapl/templates/relatorios/blocos_sessao_plenaria/ocorrencias_da_sessao.html

@ -1,4 +1,4 @@
<h2 class="gray-title">Ocorrências da Sessão</h2> <h2 class="gray-title">Ocorrências da Sessão</h2>
{% for o in lst_ocorrencias%} {% for o in lst_ocorrencias%}
<p>{{o.conteudo|striptags|safe}}</p> <p>{{o.conteudo|striptags}}</p>
{% endfor %} {% endfor %}

2
sapl/templates/relatorios/relatorio_doc_administrativos.html

@ -13,7 +13,7 @@
<strong><a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' d.id %}">{{d.tipo.sigla}} {{d.numero}}/{{d.ano}} - {{d.tipo}}</strong></a></br> <strong><a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' d.id %}">{{d.tipo.sigla}} {{d.numero}}/{{d.ano}} - {{d.tipo}}</strong></a></br>
<strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não informado"}} <strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não informado"}}
</br> </br>
<strong>Assunto:</strong>&nbsp;<a>{{ d.assunto|safe}}</a> <strong>Assunto:</strong>&nbsp;<a>{{ d.assunto}}</a>
</br> </br>
{% if d.protocolo %} {% if d.protocolo %}
<strong>Protocolo:</strong>&nbsp;<a href="{% url 'sapl.protocoloadm:protocolo_mostrar' d.protocolo.id %}">{{ d.protocolo}}</a></br> <strong>Protocolo:</strong>&nbsp;<a href="{% url 'sapl.protocoloadm:protocolo_mostrar' d.protocolo.id %}">{{ d.protocolo}}</a></br>

2
sapl/templates/relatorios/relatorio_normas_por_autor.html

@ -47,7 +47,7 @@
<td> <td>
{{norma.tipo.sigla}} {{norma.numero}}/{{norma.ano}} {{norma.tipo.sigla}} {{norma.numero}}/{{norma.ano}}
</td> </td>
<td>{% autoescape off %}{{norma.ementa}}<br>{{norma.observacao}}{% endautoescape %}</td> <td>{{norma.ementa}}<br>{{norma.observacao}}</td>
<td> <td>
{% if norma.autorianorma_set.first != norma.autorianorma_set.last %} {% if norma.autorianorma_set.first != norma.autorianorma_set.last %}
{% for autor in norma.autorianorma_set.all %} {% for autor in norma.autorianorma_set.all %}

10
sapl/templates/relatorios/relatorio_pauta_sessao.html

@ -39,7 +39,7 @@
</table> </table>
<h2 class="gray-title">Expedientes</h2> <h2 class="gray-title">Expedientes</h2>
{% for e in expedientes %} {% for e in expedientes %}
<b>{{ e.tipo }}: </b><br/><p>{{ e.conteudo|safe }}</p> <b>{{ e.tipo }}: </b><br/><p>{{ e.conteudo|sanitize }}</p>
{% endfor %} {% endfor %}
<h2 class="gray-title">Matérias do Expediente</h2> <h2 class="gray-title">Matérias do Expediente</h2>
{% if materia_expediente %} {% if materia_expediente %}
@ -53,10 +53,10 @@
<b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }} <b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }}
</td> </td>
<td style="width:60%;"> <td style="width:60%;">
{{ m.ementa|safe }} {{ m.ementa }}
{% if m.observacao %}<br><br>Obs.: {{m.observacao}} {% endif %} {% if m.observacao %}<br><br>Obs.: {{m.observacao}} {% endif %}
</td> </td>
<td style="width:20%;">{{m.situacao|linebreaksbr|safe}}</td> <td style="width:20%;">{{m.situacao|linebreaksbr}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
@ -75,10 +75,10 @@
<b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }} <b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }}
</td> </td>
<td style="width:60%;"> <td style="width:60%;">
{{m.ementa|safe}} {{m.ementa}}
{% if m.observacao %}<br><br>Obs.: {{m.observacao}} {% endif %} {% if m.observacao %}<br><br>Obs.: {{m.observacao}} {% endif %}
</td> </td>
<td style="width:20%;">{{m.situacao|linebreaksbr|safe}}</td> <td style="width:20%;">{{m.situacao|linebreaksbr}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

6
sapl/templates/search/search.html

@ -51,7 +51,7 @@
{% if result.object|search_get_model == 'm' %} {% if result.object|search_get_model == 'm' %}
<p> <p>
<strong>Matéria Legislativa: </strong> <a href="{% url 'sapl.materia:materialegislativa_detail' result.object.pk %}">{{ result.object }}</a></br> <strong>Matéria Legislativa: </strong> <a href="{% url 'sapl.materia:materialegislativa_detail' result.object.pk %}">{{ result.object }}</a></br>
{{result.object.ementa|safe}}<br> {{result.object.ementa}}<br>
{% if result.object.texto_original %} {% if result.object.texto_original %}
<strong>Texto Original:</strong> <a href="{{result.object.texto_original.url}}"> Clique aqui </a></br> <strong>Texto Original:</strong> <a href="{{result.object.texto_original.url}}"> Clique aqui </a></br>
@ -64,7 +64,7 @@
{% elif result.object|search_get_model == 'd' %} {% elif result.object|search_get_model == 'd' %}
<p> <p>
<strong> Documento Acessório: </strong><a href="{% url 'sapl.materia:documentoacessorio_detail' result.object.pk %}">{{ result.object }}</a></br> <strong> Documento Acessório: </strong><a href="{% url 'sapl.materia:documentoacessorio_detail' result.object.pk %}">{{ result.object }}</a></br>
{{result.object.ementa|safe}}<br> {{result.object.ementa}}<br>
{% if result.object.arquivo %} {% if result.object.arquivo %}
<strong>Texto Original:</strong> <a href="{{result.object.arquivo.url}}"> Clique aqui </a></br> <strong>Texto Original:</strong> <a href="{{result.object.arquivo.url}}"> Clique aqui </a></br>
{% endif %} {% endif %}
@ -73,7 +73,7 @@
{% elif result.object|search_get_model == 'n' %} {% elif result.object|search_get_model == 'n' %}
<p> <p>
<strong> Norma Jurídica: </strong><a href="{% url 'sapl.norma:normajuridica_detail' result.object.pk %}">{{ result.object }}</a></br> <strong> Norma Jurídica: </strong><a href="{% url 'sapl.norma:normajuridica_detail' result.object.pk %}">{{ result.object }}</a></br>
{{ result.object.ementa|safe }}<br> {{ result.object.ementa }}<br>
{% if result.object.texto_integral %} {% if result.object.texto_integral %}
<strong>Texto Original:</strong> <a href="{{result.object.texto_integral.url}}"> Clique aqui </a></br> <strong>Texto Original:</strong> <a href="{{result.object.texto_integral.url}}"> Clique aqui </a></br>
{% endif %} {% endif %}

2
sapl/templates/sessao/adicionar_varias_materias_expediente.html

@ -65,7 +65,7 @@
<strong>Localização Atual:</strong> &nbsp;{{ m.tramitacao_set.first.unidade_tramitacao_destino|default_if_none:"Não informado" }}</br> <strong>Localização Atual:</strong> &nbsp;{{ m.tramitacao_set.first.unidade_tramitacao_destino|default_if_none:"Não informado" }}</br>
<strong>Status:</strong> &nbsp;{{ m.tramitacao_set.first.status|default_if_none:"Não informado" }}</br> <strong>Status:</strong> &nbsp;{{ m.tramitacao_set.first.status|default_if_none:"Não informado" }}</br>
<strong>Data da última Tramitação:</strong> &nbsp;{{ m.tramitacao_set.first.data_tramitacao|default_if_none:"Não informado" }}</br> <strong>Data da última Tramitação:</strong> &nbsp;{{ m.tramitacao_set.first.data_tramitacao|default_if_none:"Não informado" }}</br>
<strong>Ementa:</strong>&nbsp;{{ m.ementa|safe }}</br> <strong>Ementa:</strong>&nbsp;{{ m.ementa }}</br>
<p></p> <p></p>
<td width="20%%"> <td width="20%%">
<input type="radio" name="tipo_votacao_{{ m.id }}" id="tipo_votacao_{{ m.id }}_1" value="1"> <label for="tipo_votacao_{{ m.id }}_1">Simbólica</label> <input type="radio" name="tipo_votacao_{{ m.id }}" id="tipo_votacao_{{ m.id }}_1" value="1"> <label for="tipo_votacao_{{ m.id }}_1">Simbólica</label>

2
sapl/templates/sessao/blocos_ata/consideracoes_finais.html

@ -2,7 +2,7 @@
<fieldset> <fieldset>
<p style="text-align: justify;margin-top: 0"> <p style="text-align: justify;margin-top: 0">
<strong>Considerações Finais: </strong> <strong>Considerações Finais: </strong>
{{object.consideracoesfinais.conteudo|striptags|safe}} {{object.consideracoesfinais.conteudo|striptags}}
</p> </p>
</fieldset> </fieldset>
{% endif %} {% endif %}

2
sapl/templates/sessao/blocos_ata/expedientes.html

@ -5,7 +5,7 @@
{% for e in expedientes %} {% for e in expedientes %}
{% if e.conteudo %} {% if e.conteudo %}
<b>{{ e.tipo }}</b>: <b>{{ e.tipo }}</b>:
{{ e.conteudo|striptags|safe }} {{ e.conteudo|striptags }}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</p> </p>

2
sapl/templates/sessao/blocos_ata/materias_expediente.html

@ -4,7 +4,7 @@
<strong>Matérias do Expediente: </strong> <strong>Matérias do Expediente: </strong>
{% for m in materia_expediente %} {% for m in materia_expediente %}
<b>{{ m.numero }} - {{ m.titulo }}</b>, <b>{{ m.numero }} - {{ m.titulo }}</b>,
{{ m.ementa|safe }} {{ m.ementa }}
{% if m.observacao %} - Obs.: {{ m.observacao }} {% endif %} {% if m.observacao %} - Obs.: {{ m.observacao }} {% endif %}
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }}, Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }},
{% if m.numero_protocolo %} {% if m.numero_protocolo %}

2
sapl/templates/sessao/blocos_ata/materias_ordem_dia.html

@ -5,7 +5,7 @@
<strong>Matérias da Ordem do Dia: </strong> <strong>Matérias da Ordem do Dia: </strong>
{% for m in materias_ordem %} {% for m in materias_ordem %}
<b>{{ m.numero }} - {{ m.titulo }}</b>, <b>{{ m.numero }} - {{ m.titulo }}</b>,
{{ m.ementa|safe }} {{ m.ementa }}
{% if m.observacao %} - Obs.: {{ m.observacao }} {% endif %} {% if m.observacao %} - Obs.: {{ m.observacao }} {% endif %}
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }}, Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }},
{% if m.numero_protocolo %} {% if m.numero_protocolo %}

2
sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html

@ -2,7 +2,7 @@
<fieldset> <fieldset>
<p style="text-align: justify;margin-top: 0"> <p style="text-align: justify;margin-top: 0">
<strong>Ocorrências da Sessão: </strong> <strong>Ocorrências da Sessão: </strong>
{{ object.ocorrenciasessao.conteudo|striptags|safe }} {{ object.ocorrenciasessao.conteudo|striptags }}
</p> </p>
</fieldset> </fieldset>
{% endif %} {% endif %}

3
sapl/templates/sessao/blocos_resumo/consideracoes_finais.html

@ -1,8 +1,9 @@
{% load common_tags %}
{% if object.consideracoesfinais.conteudo %} {% if object.consideracoesfinais.conteudo %}
<fieldset> <fieldset>
<legend>Considerações Finais</legend> <legend>Considerações Finais</legend>
<div style="border:0.5px solid #BAB4B1; border-radius: 10px; background-color: rgba(225, 225, 225, .8);"> <div style="border:0.5px solid #BAB4B1; border-radius: 10px; background-color: rgba(225, 225, 225, .8);">
<p>{{object.consideracoesfinais.conteudo|safe}}</p> <p>{{object.consideracoesfinais.conteudo|sanitize}}</p>
</div> </div>
</fieldset> </fieldset>
<br /><br /><br /> <br /><br /><br />

3
sapl/templates/sessao/blocos_resumo/expedientes.html

@ -1,3 +1,4 @@
{% load common_tags %}
{% if expedientes %} {% if expedientes %}
<fieldset> <fieldset>
<legend>Expedientes</legend> <legend>Expedientes</legend>
@ -9,7 +10,7 @@
<td> <td>
<b>{{e.tipo}}: </b> <br /><br /> <b>{{e.tipo}}: </b> <br /><br />
<div style="border:0.5px solid #BAB4B1; border-radius: 10px; background-color: rgba(225, 225, 225, .8);"> <div style="border:0.5px solid #BAB4B1; border-radius: 10px; background-color: rgba(225, 225, 225, .8);">
<p>{{e.conteudo|safe}}</p> <p>{{e.conteudo|sanitize}}</p>
</div> </div>
</td> </td>
</tr> </tr>

3
sapl/templates/sessao/blocos_resumo/ocorrencias_da_sessao.html

@ -1,8 +1,9 @@
{% load common_tags %}
{% if object.ocorrenciasessao.conteudo %} {% if object.ocorrenciasessao.conteudo %}
<fieldset> <fieldset>
<legend>Ocorrências da Sessão</legend> <legend>Ocorrências da Sessão</legend>
<div style="border:0.5px solid #BAB4B1; border-radius: 10px; background-color: rgba(225, 225, 225, .8);"> <div style="border:0.5px solid #BAB4B1; border-radius: 10px; background-color: rgba(225, 225, 225, .8);">
<p>{{object.ocorrenciasessao.conteudo|safe}}</p> <p>{{object.ocorrenciasessao.conteudo|sanitize}}</p>
</div> </div>
</fieldset> </fieldset>
<br /><br /><br /> <br /><br /><br />

2
sapl/templates/sessao/consideracoes_finais.html

@ -15,7 +15,7 @@
<input type="submit" name="delete" value="Apagar" class="btn btn-danger" /> <input type="submit" name="delete" value="Apagar" class="btn btn-danger" />
</form> </form>
{% else %} {% else %}
{{object.consideracoesfinais.conteudo|safe}} {{object.consideracoesfinais.conteudo|sanitize}}
{% endif %} {% endif %}
{% endblock detail_content %} {% endblock detail_content %}

2
sapl/templates/sessao/leitura/leitura_bloco.html

@ -72,7 +72,7 @@
{% endfor %}<br> {% endfor %}<br>
{% endif %} {% endif %}
{% endif %} {% endif %}
<strong>Ementa:</strong>&nbsp;{{ o.materia.ementa|safe }}<br> <strong>Ementa:</strong>&nbsp;{{ o.materia.ementa }}<br>
<p></p> <p></p>
</td> </td>
</tr> </tr>

2
sapl/templates/sessao/ocorrencias_da_sessao.html

@ -15,7 +15,7 @@
<input type="submit" name="delete" value="Apagar" class="btn btn-danger" /> <input type="submit" name="delete" value="Apagar" class="btn btn-danger" />
</form> </form>
{% else %} {% else %}
{{object.ocorrenciasessao.conteudo|safe}} {{object.ocorrenciasessao.conteudo|sanitize}}
{% endif %} {% endif %}
{% endblock detail_content %} {% endblock detail_content %}

6
sapl/templates/sessao/pauta_sessao_detail.html

@ -54,7 +54,7 @@
<b>{{e.tipo}}: </b> <br><br> <b>{{e.tipo}}: </b> <br><br>
<div style="border:0.5px solid #BAB4B1; border-radius: 10px; <div style="border:0.5px solid #BAB4B1; border-radius: 10px;
background-color: rgba(225, 225, 225, .8);"> background-color: rgba(225, 225, 225, .8);">
<p>{{e.conteudo|safe}}</p> <p>{{e.conteudo|sanitize}}</p>
</div> </div>
</td> </td>
</tr> </tr>
@ -82,7 +82,7 @@
{{m.ementa|dont_break_out}} {{m.ementa|dont_break_out}}
{% if m.observacao %}<br><br>Obs.: {{m.observacao}} {% endif %} {% if m.observacao %}<br><br>Obs.: {{m.observacao}} {% endif %}
</td> </td>
<td style="width:20%;">{{m.situacao|linebreaksbr|safe}}</td> <td style="width:20%;">{{m.situacao|linebreaksbr}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
@ -108,7 +108,7 @@
{{m.ementa|dont_break_out}} {{m.ementa|dont_break_out}}
{% if m.observacao %}<br><br>Obs.: {{m.observacao}} {% endif %} {% if m.observacao %}<br><br>Obs.: {{m.observacao}} {% endif %}
</td> </td>
<td style="width:20%;">{{m.situacao|linebreaksbr|safe}}</td> <td style="width:20%;">{{m.situacao|linebreaksbr}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

2
sapl/templates/sessao/votacao/nominal.html

@ -10,7 +10,7 @@
<div> <div>
Matéria: {{materia.materia}} Matéria: {{materia.materia}}
<br /> <br />
Ementa: {{materia.ementa|safe}} Ementa: {{materia.ementa}}
</div> </div>
<br /> <br />
{% if total == 0 %} {% if total == 0 %}

6
sapl/templates/sessao/votacao/nominal_detail.html

@ -8,9 +8,9 @@
<fieldset> <fieldset>
<legend>Votação Nominal</legend> <legend>Votação Nominal</legend>
<div> <div>
Matéria: {{materia.materia|safe}} Matéria: {{materia.materia}}
<br /> <br />
Ementa: {{materia.ementa|safe}} Ementa: {{materia.ementa}}
</div> </div>
<br /> <br />
@ -45,7 +45,7 @@
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
Observações Observações
<textarea id="observacao" name="observacao" style="width:100%;" rows="7" class="form-control">{{votacao.observacao|safe}}</textarea> <textarea id="observacao" name="observacao" style="width:100%;" rows="7" class="form-control">{{votacao.observacao}}</textarea>
</div> </div>
</div> </div>
</fieldset> </fieldset>

6
sapl/templates/sessao/votacao/nominal_edit.html

@ -8,9 +8,9 @@
<fieldset> <fieldset>
<legend>Votação Nominal</legend> <legend>Votação Nominal</legend>
<div> <div>
Matéria: {{materia.materia|safe}} Matéria: {{materia.materia}}
<br /> <br />
Ementa: {{materia.ementa|safe}} Ementa: {{materia.ementa}}
</div> </div>
<br /> <br />
@ -73,7 +73,7 @@
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
Observações Observações
<textarea id="observacao" name="observacao" style="width:100%;" rows="7" class="form-control">{{votacao.observacao|safe}}</textarea> <textarea id="observacao" name="observacao" style="width:100%;" rows="7" class="form-control">{{votacao.observacao}}</textarea>
</div> </div>
</div> </div>

2
sapl/templates/sessao/votacao/nominal_transparencia.html

@ -49,7 +49,7 @@
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
Observações Observações
<textarea id="observacao" name="observacao" style="width:100%;" rows="7" class="form-control">{{votacao.observacao|safe}}</textarea> <textarea id="observacao" name="observacao" style="width:100%;" rows="7" class="form-control">{{votacao.observacao}}</textarea>
</div> </div>
</div> </div>

2
sapl/templates/sessao/votacao/simbolica_transparencia.html

@ -40,7 +40,7 @@
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
Observações Observações
<textarea id="observacao" name="observacao" style="width:100%;" rows="7" class="form-control">{{votacao.observacao|safe}}</textarea> <textarea id="observacao" name="observacao" style="width:100%;" rows="7" class="form-control">{{votacao.observacao}}</textarea>
</div> </div>
</div> </div>

4
sapl/templates/sessao/votacao/votacao.html

@ -26,9 +26,9 @@
{% endif %} {% endif %}
<div> <div>
<b>Matéria:</b> {{materia.materia|safe}} <b>Matéria:</b> {{materia.materia}}
<br /> <br />
<b>Ementa:</b> {{materia.ementa|safe}} <b>Ementa:</b> {{materia.ementa}}
<br /> <br />
<br /> <br />
<b>Total presentes:</b> {{total_presentes}} (com presidente) <b>Total presentes:</b> {{total_presentes}} (com presidente)

2
sapl/templates/sessao/votacao/votacao_bloco.html

@ -73,7 +73,7 @@
{% endfor %}</br> {% endfor %}</br>
{% endif %} {% endif %}
{% endif %} {% endif %}
<strong>Ementa:</strong>&nbsp;{{ o.materia.ementa|safe }}</br> <strong>Ementa:</strong>&nbsp;{{ o.materia.ementa }}</br>
<p></p> <p></p>
</td> </td>
</tr> </tr>

6
sapl/templates/sessao/votacao/votacao_edit.html

@ -8,9 +8,9 @@
<fieldset class="form-group"> <fieldset class="form-group">
<legend>{{votacao_titulo}}</legend> <legend>{{votacao_titulo}}</legend>
<div> <div>
Matéria: {{materia.materia|safe}} Matéria: {{materia.materia}}
<br /> <br />
Ementa: {{materia.ementa|safe}} Ementa: {{materia.ementa}}
</div> </div>
<br /> <br />
@ -36,7 +36,7 @@
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
Observações Observações
<textarea id="observacao" name="observacao" cols="10" rows="10" class="form-control">{{votacao.observacao|safe}}</textarea> <textarea id="observacao" name="observacao" cols="10" rows="10" class="form-control">{{votacao.observacao}}</textarea>
</div> </div>
</div> </div>

4
sapl/templates/sessao/votacao/votacao_nominal_bloco.html

@ -24,7 +24,7 @@
<div> <div>
Matéria: {{o.materia}} Matéria: {{o.materia}}
<br /> <br />
Ementa: {{o.materia.ementa|safe}} Ementa: {{o.materia.ementa}}
</div> </div>
<br /> <br />
{% endfor %} {% endfor %}
@ -34,7 +34,7 @@
<div> <div>
Matéria: {{e.materia}} Matéria: {{e.materia}}
<br /> <br />
Ementa: {{e.materia.ementa|safe}} Ementa: {{e.materia.ementa}}
</div> </div>
<br /> <br />
{% endfor %} {% endfor %}

8
sapl/templates/sessao/votacao/votacao_simbolica_bloco.html

@ -21,17 +21,17 @@
{% if ordens %} {% if ordens %}
{% for o in ordens %} {% for o in ordens %}
<input type="hidden" id="ordens" name="ordens" value="{{o.id}}"> <input type="hidden" id="ordens" name="ordens" value="{{o.id}}">
<b>Matéria:</b> {{o.materia|safe}} <b>Matéria:</b> {{o.materia}}
<br /> <br />
<b>Ementa:</b> {{o.materia.ementa|safe}} <b>Ementa:</b> {{o.materia.ementa}}
<br /> <br /> <br /> <br />
{% endfor %} {% endfor %}
{% else %} {% else %}
{% for e in expedientes %} {% for e in expedientes %}
<input type="hidden" id="expedientes" name="expedientes" value="{{e.id}}"> <input type="hidden" id="expedientes" name="expedientes" value="{{e.id}}">
<b>Matéria:</b> {{e.materia|safe}} <b>Matéria:</b> {{e.materia}}
<br /> <br />
<b>Ementa:</b> {{e.materia.ementa|safe}} <b>Ementa:</b> {{e.materia.ementa}}
<br /> <br /> <br /> <br />
{% endfor %} {% endfor %}
{% endif %} {% endif %}

Loading…
Cancel
Save