From 13071caea50bb416402b2afd811270b20690dc26 Mon Sep 17 00:00:00 2001
From: Marcio Mazza
Date: Thu, 4 Oct 2018 11:50:32 -0300
Subject: [PATCH 01/36] Corrige palavra
---
.../{ressucitar_deps.py => ressuscitar_deps.py} | 6 +++---
...ependencias.py => ressuscita_dependencias.py} | 16 ++++++++--------
2 files changed, 11 insertions(+), 11 deletions(-)
rename sapl/legacy/management/commands/{ressucitar_deps.py => ressuscitar_deps.py} (54%)
rename sapl/legacy/scripts/{ressucita_dependencias.py => ressuscita_dependencias.py} (97%)
diff --git a/sapl/legacy/management/commands/ressucitar_deps.py b/sapl/legacy/management/commands/ressuscitar_deps.py
similarity index 54%
rename from sapl/legacy/management/commands/ressucitar_deps.py
rename to sapl/legacy/management/commands/ressuscitar_deps.py
index 70900e887..ea219330c 100644
--- a/sapl/legacy/management/commands/ressucitar_deps.py
+++ b/sapl/legacy/management/commands/ressuscitar_deps.py
@@ -1,12 +1,12 @@
from django.core.management.base import BaseCommand
-from sapl.legacy.scripts.ressucita_dependencias import adiciona_ressucitar
+from sapl.legacy.scripts.ressuscita_dependencias import adiciona_ressuscitar
class Command(BaseCommand):
- help = 'Ressucita dependências apagadas ' \
+ help = 'Ressuscita dependências apagadas ' \
'que são necessárias para migrar outros registros'
def handle(self, *args, **options):
- adiciona_ressucitar()
+ adiciona_ressuscitar()
diff --git a/sapl/legacy/scripts/ressucita_dependencias.py b/sapl/legacy/scripts/ressuscita_dependencias.py
similarity index 97%
rename from sapl/legacy/scripts/ressucita_dependencias.py
rename to sapl/legacy/scripts/ressuscita_dependencias.py
index 9810924a9..ebde7c73a 100644
--- a/sapl/legacy/scripts/ressucita_dependencias.py
+++ b/sapl/legacy/scripts/ressuscita_dependencias.py
@@ -194,7 +194,7 @@ Para facilitar sua conferência, seguem os links para as proposições envolvida
'''.format(table.draw(), links, sqls)
-def get_dependencias_a_ressucitar(slug):
+def get_dependencias_a_ressuscitar(slug):
ocorrencias = yaml.load(
Path(DIR_REPO.child('ocorrencias.yaml').read_file()))
fks_faltando = ocorrencias.get('fk')
@@ -349,8 +349,8 @@ def get_sql_criar(tabela_alvo, campo, valor, slug):
return sql, links
-TEMPLATE_RESSUCITADOS = '''{}
-/* RESSUCITADOS
+TEMPLATE_RESSUSCITADOS = '''{}
+/* RESSUSCITADOS
SOBRE REGISTROS QUE ESTAVAM APAGADOS E FORAM RESTAURADOS
@@ -397,11 +397,11 @@ def get_sqls_desexcluir_criar(preambulo, desexcluir, criar, slug):
links = sem_repeticoes_mantendo_ordem(links)
sqls, links = ['\n'.join(sorted(s)) for s in [sqls, links]]
- return TEMPLATE_RESSUCITADOS.format(preambulo, links, sqls)
+ return TEMPLATE_RESSUSCITADOS.format(preambulo, links, sqls)
-def get_ressucitar(slug):
- preambulo, desexcluir, criar = get_dependencias_a_ressucitar(slug)
+def get_ressuscitar(slug):
+ preambulo, desexcluir, criar = get_dependencias_a_ressuscitar(slug)
return get_sqls_desexcluir_criar(preambulo, desexcluir, criar, slug)
@@ -413,8 +413,8 @@ def get_slug():
return siglas_para_slugs[sigla]
-def adiciona_ressucitar():
- sqls = get_ressucitar(get_slug())
+def adiciona_ressuscitar():
+ sqls = get_ressuscitar(get_slug())
if sqls.strip():
arq_ajustes_pre_migracao = get_arquivo_ajustes_pre_migracao()
conteudo = arq_ajustes_pre_migracao.read_file()
From 248683b5a543f3ed31d3af1571d8db15ac93e157 Mon Sep 17 00:00:00 2001
From: Marcio Mazza
Date: Fri, 5 Oct 2018 09:06:41 -0300
Subject: [PATCH 02/36] Apaga destino antes de mover documento ao migrar
---
sapl/legacy/migracao_documentos.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py
index 66ada19fc..2c9e00842 100644
--- a/sapl/legacy/migracao_documentos.py
+++ b/sapl/legacy/migracao_documentos.py
@@ -1,4 +1,5 @@
import os
+import shutil
import re
from glob import glob
from os.path import join
@@ -52,6 +53,12 @@ def mover_documento(repo, origem, destino, ignora_origem_ausente=False):
if ignora_origem_ausente and not os.path.exists(origem):
print('Origem ignorada ao mover documento: {}'.format(origem))
return
+ # apaga destino, se houver, e renomeia origem para destino
+ if os.path.exists(destino):
+ if os.path.isdir(destino):
+ shutil.rmtree(destino)
+ else:
+ os.remove(destino)
os.makedirs(os.path.dirname(destino), exist_ok=True)
os.rename(origem, destino)
From 419b6d18dc36ce599913e969b1b2f86dc578b4d5 Mon Sep 17 00:00:00 2001
From: Marcio Mazza
Date: Fri, 5 Oct 2018 11:31:47 -0300
Subject: [PATCH 03/36] Corrige insert de ressuscitar
---
sapl/legacy/scripts/ressuscita_dependencias.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sapl/legacy/scripts/ressuscita_dependencias.py b/sapl/legacy/scripts/ressuscita_dependencias.py
index ebde7c73a..19cb875d8 100644
--- a/sapl/legacy/scripts/ressuscita_dependencias.py
+++ b/sapl/legacy/scripts/ressuscita_dependencias.py
@@ -1,16 +1,16 @@
from collections import OrderedDict
from textwrap import dedent
-import texttable
import yaml
-from unipath import Path
+import texttable
from sapl.legacy.migracao_dados import (PROPAGACOES_DE_EXCLUSAO,
campos_novos_para_antigos, exec_legado,
get_arquivo_ajustes_pre_migracao,
models_novos_para_antigos)
from sapl.legacy_migration_settings import (DIR_DADOS_MIGRACAO, DIR_REPO,
NOME_BANCO_LEGADO)
+from unipath import Path
def stripsplit(ll):
@@ -265,7 +265,7 @@ SQLS_CRIACAO = [
('unidade_tramitacao', '''
insert into unidade_tramitacao (
cod_unid_tramitacao, cod_comissao, cod_orgao, cod_parlamentar, ind_excluido)
- values ({}, NULL, NULL, NULL, 0);
+ values ({}, NULL, NULL, 0, 0);
'''),
('autor', SQL_INSERT_TIPO_AUTOR.format(0) + '''
insert into autor (
From e49eb8fab82747a564fecfe6360526c9da070f16 Mon Sep 17 00:00:00 2001
From: Marcio Mazza
Date: Fri, 5 Oct 2018 11:32:21 -0300
Subject: [PATCH 04/36] =?UTF-8?q?Apaga=20refs=20a=20mats=20e=20docs=20inex?=
=?UTF-8?q?istentes=20em=20proposi=C3=A7=C3=B5es?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
sapl/legacy/migracao_dados.py | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py
index 1be1f6e96..1def7f9c3 100644
--- a/sapl/legacy/migracao_dados.py
+++ b/sapl/legacy/migracao_dados.py
@@ -623,6 +623,36 @@ def corrige_unidades_tramitacao_destino_vazia_como_anterior():
'''.format(tabela_tramitacao))
+def apaga_ref_a_mats_e_docs_inexistentes_em_proposicoes():
+ # as referencias a matérias e documentos apagados não aparecem no 3.1
+ # além do que, se ressuscitássemos essas matérias e docs,
+ # não seria possível apagá-los,
+ # pois é impossível para um usuário não autor acessar as proposicões
+ # para apagar a referências antes
+ exec_legado('''
+ update proposicao set cod_materia = NULL where cod_materia not in (
+ select cod_materia from materia_legislativa
+ where ind_excluido <> 1);
+ ''')
+ props_sem_mats = list(primeira_coluna(exec_legado('''
+ select cod_proposicao from proposicao p inner join tipo_proposicao t
+ on p.tip_proposicao = t.tip_proposicao
+ where t.ind_mat_ou_doc = 'M' and cod_mat_ou_doc not in (
+ select cod_materia from materia_legislativa
+ where ind_excluido <> 1)
+ ''')))
+ props_sem_docs = list(primeira_coluna(exec_legado('''
+ select cod_proposicao from proposicao p inner join tipo_proposicao t
+ on p.tip_proposicao = t.tip_proposicao
+ where t.ind_mat_ou_doc = 'D' and cod_mat_ou_doc not in (
+ select cod_documento from documento_acessorio
+ where ind_excluido <> 1);
+ ''')))
+ exec_legado_em_subconjunto('''
+ update proposicao set cod_mat_ou_doc = NULL
+ where cod_proposicao in {}''', props_sem_mats + props_sem_docs)
+
+
def uniformiza_banco():
propaga_exclusoes(PROPAGACOES_DE_EXCLUSAO)
checa_registros_votacao_ambiguos_e_remove_nao_usados()
@@ -722,6 +752,8 @@ sessao_plenaria_presenca | dat_sessao = NULL | dat_sessao = 0
select cod_materia from materia_legislativa
where ind_excluido <> 1);''')
+ apaga_ref_a_mats_e_docs_inexistentes_em_proposicoes()
+
class Record:
pass
From 4062dc842b1c23d7940f58be82ef9595c3047a29 Mon Sep 17 00:00:00 2001
From: Victor Fabre
Date: Tue, 9 Oct 2018 15:18:23 -0300
Subject: [PATCH 05/36] Fix #2281 (#2290)
* Fix #2281
* Inclui novo model em regras de acesso
---
sapl/norma/forms.py | 50 ++++++++++++++++++-
.../migrations/0014_auto_20181008_1655.py | 40 +++++++++++++++
sapl/norma/models.py | 29 +++++++++++
sapl/norma/urls.py | 5 +-
sapl/norma/views.py | 37 +++++++++++++-
sapl/rules/map_rules.py | 2 +
sapl/templates/norma/autorianorma_form.html | 47 +++++++++++++++++
sapl/templates/norma/layouts.yaml | 4 ++
sapl/templates/norma/subnav.yaml | 3 +-
9 files changed, 210 insertions(+), 7 deletions(-)
create mode 100644 sapl/norma/migrations/0014_auto_20181008_1655.py
create mode 100644 sapl/templates/norma/autorianorma_form.html
diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py
index 5fa26f0fd..818d6ba38 100644
--- a/sapl/norma/forms.py
+++ b/sapl/norma/forms.py
@@ -5,17 +5,18 @@ from crispy_forms.layout import Fieldset, Layout
from django import forms
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models
-from django.forms import ModelForm, widgets
+from django.forms import ModelForm, widgets, ModelChoiceField
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
+from sapl.base.models import Autor, TipoAutor
from sapl.crispy_layout_mixin import form_actions, to_row
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.settings import MAX_DOC_UPLOAD_SIZE
from sapl.utils import NormaPesquisaOrderingFilter, RANGE_ANOS, RangeWidgetOverride
from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada,
- TipoNormaJuridica)
+ TipoNormaJuridica, AutoriaNorma)
def ANO_CHOICES():
@@ -191,6 +192,51 @@ class NormaJuridicaForm(ModelForm):
return norma
+class AutoriaNormaForm(ModelForm):
+
+ tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
+ required=False,
+ queryset=TipoAutor.objects.all(),
+ empty_label=_('Selecione'),)
+
+ data_relativa = forms.DateField(
+ widget=forms.HiddenInput(), required=False)
+
+ def __init__(self, *args, **kwargs):
+ super(AutoriaNormaForm, self).__init__(*args, **kwargs)
+
+ row1 = to_row([('tipo_autor', 4),
+ ('autor', 4),
+ ('primeiro_autor', 4)])
+
+ self.helper = FormHelper()
+ self.helper.layout = Layout(
+ Fieldset(_('Autoria'),
+ row1, 'data_relativa', form_actions(label='Salvar')))
+
+ if not kwargs['instance']:
+ self.fields['autor'].choices = []
+
+ class Meta:
+ model = AutoriaNorma
+ fields = ['tipo_autor', 'autor', 'primeiro_autor', 'data_relativa']
+
+ def clean(self):
+ cd = super(AutoriaNormaForm, self).clean()
+
+ if not self.is_valid():
+ return self.cleaned_data
+
+ autorias = AutoriaNorma.objects.filter(
+ norma=self.instance.norma, autor=cd['autor'])
+ pk = self.instance.pk
+
+ if ((not pk and autorias.exists()) or
+ (pk and autorias.exclude(pk=pk).exists())):
+ raise ValidationError(_('Esse Autor já foi cadastrado.'))
+
+ return cd
+
class AnexoNormaJuridicaForm(ModelForm):
class Meta:
model = AnexoNormaJuridica
diff --git a/sapl/norma/migrations/0014_auto_20181008_1655.py b/sapl/norma/migrations/0014_auto_20181008_1655.py
new file mode 100644
index 000000000..da9bf4add
--- /dev/null
+++ b/sapl/norma/migrations/0014_auto_20181008_1655.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2018-10-08 19:55
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('base', '0021_appconfig_esfera_federacao'),
+ ('norma', '0013_anexonormajuridica_assunto_anexo'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='AutoriaNorma',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('primeiro_autor', models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Primeiro Autor')),
+ ('autor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='base.Autor', verbose_name='Autor')),
+ ('norma', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='norma.NormaJuridica', verbose_name='Matéria Legislativa')),
+ ],
+ options={
+ 'ordering': ('-primeiro_autor', 'autor__nome'),
+ 'verbose_name': 'Autoria',
+ 'verbose_name_plural': 'Autorias',
+ },
+ ),
+ migrations.AddField(
+ model_name='normajuridica',
+ name='autores',
+ field=models.ManyToManyField(through='norma.AutoriaNorma', to='base.Autor'),
+ ),
+ migrations.AlterUniqueTogether(
+ name='autorianorma',
+ unique_together=set([('autor', 'norma')]),
+ ),
+ ]
diff --git a/sapl/norma/models.py b/sapl/norma/models.py
index e4e3677b3..46f34a0ef 100644
--- a/sapl/norma/models.py
+++ b/sapl/norma/models.py
@@ -5,6 +5,7 @@ from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
import reversion
+from sapl.base.models import Autor
from sapl.compilacao.models import TextoArticulado
from sapl.materia.models import MateriaLegislativa
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
@@ -129,6 +130,12 @@ class NormaJuridica(models.Model):
auto_now=True,
verbose_name=_('Data'))
+ autores = models.ManyToManyField(
+ Autor,
+ through='AutoriaNorma',
+ through_fields=('norma', 'autor'),
+ symmetrical=False)
+
class Meta:
verbose_name = _('Norma Jurídica')
verbose_name_plural = _('Normas Jurídicas')
@@ -184,6 +191,28 @@ class NormaJuridica(models.Model):
update_fields=update_fields)
+@reversion.register()
+class AutoriaNorma(models.Model):
+ autor = models.ForeignKey(Autor,
+ verbose_name=_('Autor'),
+ on_delete=models.CASCADE)
+ norma = models.ForeignKey(
+ NormaJuridica, on_delete=models.CASCADE,
+ verbose_name=_('Matéria Legislativa'))
+ primeiro_autor = models.BooleanField(verbose_name=_('Primeiro Autor'),
+ choices=YES_NO_CHOICES,
+ default=False)
+
+ class Meta:
+ verbose_name = _('Autoria')
+ verbose_name_plural = _('Autorias')
+ unique_together = (('autor', 'norma'), )
+ ordering = ('-primeiro_autor', 'autor__nome')
+
+ def __str__(self):
+ return _('Autoria: %(autor)s - %(norma)s') % {
+ 'autor': self.autor, 'norma': self.norma}
+
@reversion.register()
class LegislacaoCitada(models.Model):
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
diff --git a/sapl/norma/urls.py b/sapl/norma/urls.py
index d943f71e8..800707915 100644
--- a/sapl/norma/urls.py
+++ b/sapl/norma/urls.py
@@ -3,7 +3,7 @@ from django.conf.urls import include, url
from sapl.norma.views import (AnexoNormaJuridicaCrud,AssuntoNormaCrud, NormaCrud, NormaPesquisaView,
NormaRelacionadaCrud, NormaTaView, TipoNormaCrud,
TipoVinculoNormaJuridicaCrud, recuperar_norma,
- recuperar_numero_norma)
+ recuperar_numero_norma, AutoriaNormaCrud)
from .apps import AppConfig
@@ -13,7 +13,8 @@ app_name = AppConfig.name
urlpatterns = [
url(r'^norma/', include(NormaCrud.get_urls() +
NormaRelacionadaCrud.get_urls() +
- AnexoNormaJuridicaCrud.get_urls())),
+ AnexoNormaJuridicaCrud.get_urls() +
+ AutoriaNormaCrud.get_urls())),
# Integração com Compilação
url(r'^norma/(?P[0-9]+)/ta$', NormaTaView.as_view(), name='norma_ta'),
diff --git a/sapl/norma/views.py b/sapl/norma/views.py
index beae10d4d..b91aec2a5 100644
--- a/sapl/norma/views.py
+++ b/sapl/norma/views.py
@@ -21,9 +21,9 @@ from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
from sapl.utils import show_results_filter_set
from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm,
- NormaPesquisaSimplesForm, NormaRelacionadaForm)
+ NormaPesquisaSimplesForm, NormaRelacionadaForm, AutoriaNormaForm)
from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada,
- TipoNormaJuridica, TipoVinculoNormaJuridica)
+ TipoNormaJuridica, TipoVinculoNormaJuridica, AutoriaNorma)
# LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '')
@@ -274,6 +274,39 @@ def recuperar_numero_norma(request):
return response
+class AutoriaNormaCrud(MasterDetailCrud):
+ model = AutoriaNorma
+ parent_field = 'norma'
+ help_topic = 'despacho_autoria'
+ public = [RP_LIST, RP_DETAIL]
+ list_field_names = ['autor', 'autor__tipo__descricao', 'primeiro_autor']
+
+ class LocalBaseMixin():
+ form_class = AutoriaNormaForm
+
+ @property
+ def layout_key(self):
+ return None
+
+ class CreateView(LocalBaseMixin, MasterDetailCrud.CreateView):
+
+ def get_initial(self):
+ initial = super().get_initial()
+ norma = NormaJuridica.objects.get(id=self.kwargs['pk'])
+ initial['data_relativa'] = norma.data
+ initial['autor'] = []
+ return initial
+
+ class UpdateView(LocalBaseMixin, MasterDetailCrud.UpdateView):
+
+ def get_initial(self):
+ initial = super().get_initial()
+ initial.update({
+ 'data_relativa': self.object.norma.data_apresentacao,
+ 'tipo_autor': self.object.autor.tipo.id,
+ })
+ return initial
+
class ImpressosView(PermissionRequiredMixin, TemplateView):
template_name = 'materia/impressos/impressos.html'
permission_required = ('materia.can_access_impressos', )
diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py
index bba114149..e4ea00f2c 100644
--- a/sapl/rules/map_rules.py
+++ b/sapl/rules/map_rules.py
@@ -116,6 +116,7 @@ rules_group_materia = {
(materia.Numeracao, __base__),
(materia.Tramitacao, __base__),
(norma.LegislacaoCitada, __base__),
+ (norma.AutoriaNorma, __base__),
(compilacao.Dispositivo, __base__ + [
'change_dispositivo_edicao_dinamica',
@@ -136,6 +137,7 @@ rules_group_norma = {
(norma.NormaJuridica, __base__),
(norma.NormaRelacionada, __base__),
(norma.AnexoNormaJuridica, __base__),
+ (norma.AutoriaNorma, __base__),
# Publicacao está com permissão apenas para norma e não para matéria
# e proposições apenas por análise do contexto, não é uma limitação
diff --git a/sapl/templates/norma/autorianorma_form.html b/sapl/templates/norma/autorianorma_form.html
new file mode 100644
index 000000000..35338c9de
--- /dev/null
+++ b/sapl/templates/norma/autorianorma_form.html
@@ -0,0 +1,47 @@
+{% extends "crud/form.html" %}
+{% load i18n %}
+{% load crispy_forms_tags %}
+{% load common_tags %}
+
+{% block extra_js %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/sapl/templates/norma/layouts.yaml b/sapl/templates/norma/layouts.yaml
index 0075317c1..d881ae186 100644
--- a/sapl/templates/norma/layouts.yaml
+++ b/sapl/templates/norma/layouts.yaml
@@ -70,3 +70,7 @@ NormaRelacionadaDetail:
{% trans 'Norma Relacionada' %}:
- norma_relacionada
- tipo_vinculo
+
+AutoriaNorma:
+ {% trans 'Autoria' %}:
+ - autor primeiro_autor
\ No newline at end of file
diff --git a/sapl/templates/norma/subnav.yaml b/sapl/templates/norma/subnav.yaml
index 9358787ff..f85433e72 100644
--- a/sapl/templates/norma/subnav.yaml
+++ b/sapl/templates/norma/subnav.yaml
@@ -7,7 +7,8 @@
check_permission: norma.list_normarelacionada
- title: {% trans 'Anexos da Norma' %}
url: anexonormajuridica_list
-
+- title: {% trans 'Autoria' %}
+ url: autorianorma_list
# Opção adicionada para chamar o TextoArticulado da norma.
# para integração foram necessárias apenas criar a url norma_ta em urls.py
# e a view NormaTaView(IntegracaoTaView) em views.py
From a6fc9879d3148acd41f7d3f8d24a7e6723a488c9 Mon Sep 17 00:00:00 2001
From: AndreSouto
Date: Tue, 9 Oct 2018 15:19:01 -0300
Subject: [PATCH 06/36] Fixes #2030 (#2277)
* Fixes #2030
* Fixes #2030
* Fixes #2030
---
.../templates/pdf_sessao_plenaria_gerar.py | 28 +++++++-
sapl/relatorios/views.py | 37 ++++++++--
sapl/rules/map_rules.py | 41 +++++------
sapl/sessao/forms.py | 11 ++-
.../migrations/0024_ocorrenciasessao.py | 28 ++++++++
.../migrations/0025_auto_20180919_1116.py | 21 ++++++
sapl/sessao/models.py | 15 ++++
sapl/sessao/urls.py | 6 +-
sapl/sessao/views.py | 70 +++++++++++++++++--
.../blocos_ata/ocorrencias_da_sessao.html | 6 ++
.../blocos_resumo/ocorrencias_da_sessao.html | 6 ++
sapl/templates/sessao/ocorrencia_sessao.html | 32 +++++++++
sapl/templates/sessao/resumo.html | 2 +
sapl/templates/sessao/resumo_ata.html | 1 +
sapl/templates/sessao/subnav.yaml | 2 +
15 files changed, 270 insertions(+), 36 deletions(-)
create mode 100644 sapl/sessao/migrations/0024_ocorrenciasessao.py
create mode 100644 sapl/sessao/migrations/0025_auto_20180919_1116.py
create mode 100644 sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html
create mode 100644 sapl/templates/sessao/blocos_resumo/ocorrencias_da_sessao.html
create mode 100644 sapl/templates/sessao/ocorrencia_sessao.html
diff --git a/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py b/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
index 1c01bfb08..1f0f6482c 100644
--- a/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
+++ b/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
@@ -6,6 +6,9 @@
"""
import time
+from django.template.defaultfilters import safe
+from django.utils.html import strip_tags
+
from sapl.sessao.models import ResumoOrdenacao
from trml2pdf import parseString
@@ -284,7 +287,25 @@ def oradores(lst_oradores):
return tmp
-def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_mesa, lst_presenca_sessao, lst_expedientes, lst_expediente_materia, lst_oradores_expediente, lst_presenca_ordem_dia, lst_votacao, lst_oradores):
+def ocorrencias(lst_ocorrencias):
+ """
+
+ """
+ tmp = ''
+ tmp += '\t\tOcorrências da Sessão \n'
+ tmp += '\t\t\n'
+ tmp += '\t\t\t \n'
+ tmp += '\t\t \n'
+ for idx, ocorrencia in enumerate(lst_ocorrencias):
+ tmp += '\t\t' + \
+ str(ocorrencia.conteudo) + ' \n'
+ tmp += '\t\t\n'
+ tmp += '\t\t\t \n'
+ tmp += '\t\t \n'
+ return tmp
+
+
+def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_mesa, lst_presenca_sessao, lst_expedientes, lst_expediente_materia, lst_oradores_expediente, lst_presenca_ordem_dia, lst_votacao, lst_oradores, lst_ocorrencias):
"""
"""
arquivoPdf = str(int(time.time() * 100)) + ".pdf"
@@ -316,7 +337,8 @@ def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_me
'mat_o_d': votacao(lst_votacao),
'mesa_d': mesa(lst_mesa),
'oradores_exped': oradores_expediente(lst_oradores_expediente),
- 'oradores_expli': oradores(lst_oradores)
+ 'oradores_expli': oradores(lst_oradores),
+ 'ocorr_sessao': ocorrencias(lst_ocorrencias)
}
if ordenacao:
@@ -330,6 +352,7 @@ def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_me
tmp += dict_ord_template[ordenacao.oitavo]
tmp += dict_ord_template[ordenacao.nono]
tmp += dict_ord_template[ordenacao.decimo]
+
else:
tmp += inf_basicas(inf_basicas_dic)
tmp += mesa(lst_mesa)
@@ -340,6 +363,7 @@ def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_me
tmp += presenca_ordem_dia(lst_presenca_ordem_dia)
tmp += votacao(lst_votacao)
tmp += oradores(lst_oradores)
+ tmp += ocorrencias(lst_ocorrencias)
tmp += '\t\n'
tmp += '\n'
diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py
index 4d273b6da..2f48f627f 100644
--- a/sapl/relatorios/views.py
+++ b/sapl/relatorios/views.py
@@ -17,7 +17,7 @@ from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo,
from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao,
IntegranteMesa, Orador, OradorExpediente,
OrdemDia, PresencaOrdemDia, SessaoPlenaria,
- SessaoPlenariaPresenca)
+ SessaoPlenariaPresenca, OcorrenciaSessao)
from sapl.settings import STATIC_ROOT
from sapl.utils import LISTA_DE_UFS, ExtraiTag, TrocaTag, filiacao_data
@@ -514,13 +514,13 @@ def get_sessao_plenaria(sessao, casa):
dic_presenca['sgl_partido'] = partido_sigla
lst_presenca_sessao.append(dic_presenca)
+
# Exibe os Expedientes
lst_expedientes = []
expedientes = ExpedienteSessao.objects.filter(
sessao_plenaria=sessao).order_by('tipo__nome')
for e in expedientes:
-
dic_expedientes = {}
dic_expedientes["nom_expediente"] = e.tipo.nome
conteudo = e.conteudo
@@ -539,6 +539,7 @@ def get_sessao_plenaria(sessao, casa):
if dic_expedientes:
lst_expedientes.append(dic_expedientes)
+
# Lista das matérias do Expediente, incluindo o resultado das votacoes
lst_expediente_materia = []
for expediente_materia in ExpedienteMateria.objects.filter(
@@ -727,6 +728,28 @@ def get_sessao_plenaria(sessao, casa):
dic_oradores['sgl_partido'] = sigla
lst_oradores.append(dic_oradores)
+ # Ocorrências da Sessão
+ lst_ocorrencias = []
+ ocorrencias = OcorrenciaSessao.objects.filter(
+ sessao_plenaria=sessao)
+
+ for o in ocorrencias:
+ conteudo = o.conteudo
+
+ # unescape HTML codes
+ # https://github.com/interlegis/sapl/issues/1046
+ conteudo = re.sub('style=".*?"', '', conteudo)
+ conteudo = html.unescape(conteudo)
+
+ # escape special character '&'
+ # https://github.com/interlegis/sapl/issues/1009
+ conteudo = conteudo.replace('&', '&')
+
+ o.conteudo = conteudo
+
+ lst_ocorrencias.append(o)
+
+
return (inf_basicas_dic,
lst_mesa,
lst_presenca_sessao,
@@ -735,7 +758,8 @@ def get_sessao_plenaria(sessao, casa):
lst_oradores_expediente,
lst_presenca_ordem_dia,
lst_votacao,
- lst_oradores)
+ lst_oradores,
+ lst_ocorrencias)
def get_turno(dic, materia, sessao_data_inicio):
@@ -785,7 +809,9 @@ def relatorio_sessao_plenaria(request, pk):
lst_oradores_expediente,
lst_presenca_ordem_dia,
lst_votacao,
- lst_oradores) = get_sessao_plenaria(sessao, casa)
+ lst_oradores,
+ lst_ocorrencias) = get_sessao_plenaria(sessao, casa)
+
for idx in range(len(lst_expedientes)):
txt_expedientes = lst_expedientes[idx]['txt_expediente']
@@ -806,7 +832,8 @@ def relatorio_sessao_plenaria(request, pk):
lst_oradores_expediente,
lst_presenca_ordem_dia,
lst_votacao,
- lst_oradores)
+ lst_oradores,
+ lst_ocorrencias)
response.write(pdf)
return response
diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py
index e4ea00f2c..47a43d9e1 100644
--- a/sapl/rules/map_rules.py
+++ b/sapl/rules/map_rules.py
@@ -1,23 +1,3 @@
-from sapl.base import models as base
-from sapl.comissoes import models as comissoes
-from sapl.compilacao import models as compilacao
-from sapl.lexml import models as lexml
-from sapl.materia import models as materia
-from sapl.norma import models as norma
-from sapl.painel import models as painel
-from sapl.parlamentares import models as parlamentares
-from sapl.protocoloadm import models as protocoloadm
-from sapl.audiencia import models as audiencia
-from sapl.rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL, RP_LIST,
- SAPL_GROUP_ADMINISTRATIVO, SAPL_GROUP_ANONYMOUS,
- SAPL_GROUP_AUTOR, SAPL_GROUP_COMISSOES,
- SAPL_GROUP_GERAL, SAPL_GROUP_LOGIN_SOCIAL,
- SAPL_GROUP_MATERIA, SAPL_GROUP_NORMA,
- SAPL_GROUP_PAINEL, SAPL_GROUP_PARLAMENTAR,
- SAPL_GROUP_PROTOCOLO, SAPL_GROUP_SESSAO,
- SAPL_GROUP_VOTANTE)
-from sapl.sessao import models as sessao
-
"""
Todas as permissões do django framework seguem o padrão
@@ -46,6 +26,26 @@ negócio trabalham com os cinco radiais de permissão
e com qualquer outro tipo de permissão customizada, nesta ordem de precedência.
"""
+from sapl.audiencia import models as audiencia
+from sapl.base import models as base
+from sapl.comissoes import models as comissoes
+from sapl.compilacao import models as compilacao
+from sapl.lexml import models as lexml
+from sapl.materia import models as materia
+from sapl.norma import models as norma
+from sapl.painel import models as painel
+from sapl.parlamentares import models as parlamentares
+from sapl.protocoloadm import models as protocoloadm
+from sapl.rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL, RP_LIST,
+ SAPL_GROUP_ADMINISTRATIVO, SAPL_GROUP_ANONYMOUS,
+ SAPL_GROUP_AUTOR, SAPL_GROUP_COMISSOES,
+ SAPL_GROUP_GERAL, SAPL_GROUP_LOGIN_SOCIAL,
+ SAPL_GROUP_MATERIA, SAPL_GROUP_NORMA,
+ SAPL_GROUP_PAINEL, SAPL_GROUP_PARLAMENTAR,
+ SAPL_GROUP_PROTOCOLO, SAPL_GROUP_SESSAO,
+ SAPL_GROUP_VOTANTE)
+from sapl.sessao import models as sessao
+
__base__ = [RP_LIST, RP_DETAIL, RP_ADD, RP_CHANGE, RP_DELETE]
__listdetailchange__ = [RP_LIST, RP_DETAIL, RP_CHANGE]
@@ -161,6 +161,7 @@ rules_group_sessao = {
(sessao.SessaoPlenaria, __base__),
(sessao.SessaoPlenariaPresenca, __base__),
(sessao.ExpedienteMateria, __base__),
+ (sessao.OcorrenciaSessao, __base__),
(sessao.IntegranteMesa, __base__),
(sessao.ExpedienteSessao, __base__),
(sessao.Orador, __base__),
diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py
index 5d36ba99a..96e85b9d8 100644
--- a/sapl/sessao/forms.py
+++ b/sapl/sessao/forms.py
@@ -22,7 +22,7 @@ from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES,
from .models import (Bancada, Bloco, ExpedienteMateria, Orador,
OradorExpediente, OrdemDia, SessaoPlenaria,
- SessaoPlenariaPresenca, TipoResultadoVotacao)
+ SessaoPlenariaPresenca, TipoResultadoVotacao, OcorrenciaSessao)
def recupera_anos():
@@ -54,7 +54,8 @@ ORDENACAO_RESUMO = [('cont_mult', 'Conteúdo Multimídia'),
('mat_o_d', 'Matérias da Ordem do Dia'),
('mesa_d', 'Mesa Diretora'),
('oradores_exped', 'Oradores do Expediente'),
- ('oradores_expli', 'Oradores das Explicações Pessoais')]
+ ('oradores_expli', 'Oradores das Explicações Pessoais'),
+ ('ocorrencia_sessao', 'Ocorrências da Sessão')]
class SessaoPlenariaForm(ModelForm):
@@ -412,6 +413,12 @@ class MesaForm(forms.Form):
class ExpedienteForm(forms.Form):
conteudo = forms.CharField(required=False, widget=forms.Textarea)
+class OcorrenciaSessaoForm(ModelForm):
+ class Meta:
+ model = OcorrenciaSessao
+ fields = ['conteudo']
+
+
class VotacaoForm(forms.Form):
votos_sim = forms.CharField(label='Sim')
diff --git a/sapl/sessao/migrations/0024_ocorrenciasessao.py b/sapl/sessao/migrations/0024_ocorrenciasessao.py
new file mode 100644
index 000000000..6c612363f
--- /dev/null
+++ b/sapl/sessao/migrations/0024_ocorrenciasessao.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.7 on 2018-09-18 13:44
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('sessao', '0023_auto_20180914_1315'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='OcorrenciaSessao',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('conteudo', models.TextField(blank=True, verbose_name='Ocorrências da Sessão Plenária')),
+ ('sessao_plenaria', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='sessao.SessaoPlenaria')),
+ ],
+ options={
+ 'verbose_name_plural': 'Ocorrências da Sessão Plenaria',
+ 'verbose_name': 'Ocorrência da Sessão Plenaria',
+ },
+ ),
+ ]
diff --git a/sapl/sessao/migrations/0025_auto_20180919_1116.py b/sapl/sessao/migrations/0025_auto_20180919_1116.py
new file mode 100644
index 000000000..fa4c0a435
--- /dev/null
+++ b/sapl/sessao/migrations/0025_auto_20180919_1116.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2018-09-19 14:16
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('sessao', '0024_ocorrenciasessao'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='ocorrenciasessao',
+ name='sessao_plenaria',
+ field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='sessao.SessaoPlenaria'),
+ ),
+ ]
diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py
index 11047ed9e..7f8ea0882 100644
--- a/sapl/sessao/models.py
+++ b/sapl/sessao/models.py
@@ -301,6 +301,21 @@ class ExpedienteSessao(models.Model): # ExpedienteSessaoPlenaria
return '%s - %s' % (self.tipo, self.sessao_plenaria)
+@reversion.register()
+class OcorrenciaSessao(models.Model): # OcorrenciaSessaoPlenaria
+ sessao_plenaria = models.OneToOneField(SessaoPlenaria,
+ on_delete=models.PROTECT)
+ conteudo = models.TextField(
+ blank=True, verbose_name=_('Ocorrências da Sessão Plenária'))
+
+ class Meta:
+ verbose_name = _('Ocorrência da Sessão Plenaria')
+ verbose_name_plural = _('Ocorrências da Sessão Plenaria')
+
+ def __str__(self):
+ return '%s - %s' % (self.sessao_plenaria, self.conteudo)
+
+
@reversion.register()
class IntegranteMesa(models.Model): # MesaSessaoPlenaria
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
diff --git a/sapl/sessao/urls.py b/sapl/sessao/urls.py
index 201623824..1e3e4ae43 100644
--- a/sapl/sessao/urls.py
+++ b/sapl/sessao/urls.py
@@ -3,7 +3,7 @@ from django.conf.urls import include, url
from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
AdicionarVariasMateriasOrdemDia, BancadaCrud,
BlocoCrud, CargoBancadaCrud,
- ExpedienteMateriaCrud, ExpedienteView,
+ ExpedienteMateriaCrud, ExpedienteView, OcorrenciaSessaoView,
MateriaOrdemDiaCrud, MesaView, OradorCrud,
OradorExpedienteCrud, PainelView,
PautaSessaoDetailView, PautaSessaoView,
@@ -100,6 +100,8 @@ urlpatterns = [
# Subnav sessão
url(r'^sessao/(?P\d+)/expediente$',
ExpedienteView.as_view(), name='expediente'),
+ url(r'^sessao/(?P\d+)/ocorrencia_sessao$',
+ OcorrenciaSessaoView.as_view(), name='ocorrencia_sessao'),
url(r'^sessao/(?P\d+)/presenca$',
PresencaView.as_view(), name='presenca'),
url(r'^sessao/(?P\d+)/painel$',
@@ -110,7 +112,7 @@ urlpatterns = [
url(r'^sessao/(?P\d+)/resumo$',
ResumoView.as_view(), name='resumo'),
url(r'^sessao/(?P\d+)/resumo_ata$',
- ResumoAtaView.as_view(), name='resumo_ata'),
+ ResumoAtaView.as_view(), name='resumo_ata'),
url(r'^sessao/pesquisar-sessao$',
PesquisarSessaoPlenariaView.as_view(), name='pesquisar_sessao'),
url(r'^sessao/(?P\d+)/matordemdia/votnom/(?P\d+)/(?P\d+)$',
diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py
index d64f3dba0..6cc9300fb 100644
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -37,13 +37,13 @@ from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm
from sapl.utils import show_results_filter_set, remover_acentos
from .forms import (AdicionarVariasMateriasFilterSet, BancadaForm, BlocoForm,
- ExpedienteForm, ListMateriaForm, MesaForm,
+ ExpedienteForm, OcorrenciaSessaoForm, ListMateriaForm, MesaForm,
OradorExpedienteForm, OradorForm, PautaSessaoFilterSet,
PresencaForm, ResumoOrdenacaoForm, SessaoPlenariaFilterSet,
SessaoPlenariaForm, VotacaoEditForm, VotacaoForm,
VotacaoNominalForm)
from .models import (Bancada, Bloco, CargoBancada, CargoMesa,
- ExpedienteMateria, ExpedienteSessao, IntegranteMesa,
+ ExpedienteMateria, ExpedienteSessao, OcorrenciaSessao, IntegranteMesa,
MateriaLegislativa, Orador, OradorExpediente, OrdemDia,
PresencaOrdemDia, RegistroVotacao, ResumoOrdenacao,
SessaoPlenaria, SessaoPlenariaPresenca, TipoExpediente,
@@ -1175,7 +1175,8 @@ class ResumoOrdenacaoView(PermissionRequiredMixin, FormView):
'setimo': ordenacao.setimo,
'oitavo': ordenacao.oitavo,
'nono': ordenacao.nono,
- 'decimo': ordenacao.decimo})
+ 'decimo': ordenacao.decimo,
+ 'decimo_primeiro': ordenacao.decimo_primeiro})
return initial
def form_valid(self, form):
@@ -1191,6 +1192,7 @@ class ResumoOrdenacaoView(PermissionRequiredMixin, FormView):
ordenacao.oitavo = form.cleaned_data['oitavo']
ordenacao.nono = form.cleaned_data['nono']
ordenacao.decimo = form.cleaned_data['decimo']
+ ordenacao.decimo_primeiro = form.cleaned_data['decimo_primeiro']
ordenacao.save()
@@ -1280,6 +1282,7 @@ class ResumoView(DetailView):
ex = {'tipo': tipo, 'conteudo': conteudo}
expedientes.append(ex)
context.update({'expedientes': expedientes})
+
# =====================================================================
# Matérias Expediente
materias = ExpedienteMateria.objects.filter(
@@ -1413,6 +1416,12 @@ class ResumoView(DetailView):
oradores_explicacoes.append(oradores)
context.update({'oradores_explicacoes': oradores_explicacoes})
+ # =====================================================================
+ # Ocorrẽncias da Sessão
+ ocorrencias_sessao = OcorrenciaSessao.objects.filter(sessao_plenaria_id=self.object.id)
+
+ context.update({'ocorrencias_da_sessao': ocorrencias_sessao})
+
# =====================================================================
# Indica a ordem com a qual o template será renderizado
ordenacao = ResumoOrdenacao.objects.first()
@@ -1426,7 +1435,8 @@ class ResumoView(DetailView):
'mat_o_d': 'materias_ordem_dia.html',
'mesa_d': 'mesa_diretora.html',
'oradores_exped': 'oradores_expediente.html',
- 'oradores_expli': 'oradores_explicacoes.html'
+ 'oradores_expli': 'oradores_explicacoes.html',
+ 'ocorr_sessao': 'ocorrencias_da_sessao.html'
}
if ordenacao:
@@ -1452,12 +1462,16 @@ class ResumoView(DetailView):
'setimo_ordenacao': dict_ord_template['oradores_exped'],
'oitavo_ordenacao': dict_ord_template['lista_p_o_d'],
'nono_ordenacao': dict_ord_template['mat_o_d'],
- 'decimo_ordenacao': dict_ord_template['oradores_expli']})
+ 'decimo_ordenacao': dict_ord_template['oradores_expli'],
+ 'decimo_primeiro_ordenacao': dict_ord_template['ocorr_sessao']})
return self.render_to_response(context)
+
+
class ResumoAtaView(ResumoView):
template_name = 'sessao/resumo_ata.html'
+
class ExpedienteView(FormMixin, DetailView):
template_name = 'sessao/expediente.html'
form_class = ExpedienteForm
@@ -1537,6 +1551,52 @@ class ExpedienteView(FormMixin, DetailView):
return reverse('sapl.sessao:expediente', kwargs={'pk': pk})
+
+class OcorrenciaSessaoView(FormMixin, DetailView):
+ template_name = 'sessao/ocorrencia_sessao.html'
+ form_class = OcorrenciaSessaoForm
+ model = SessaoPlenaria
+
+ def delete(self):
+ OcorrenciaSessao.objects.filter(sessao_plenaria=self.object).delete()
+
+ msg = _('Registro deletado com sucesso')
+ messages.add_message(self.request, messages.SUCCESS, msg)
+
+ def save(self,form):
+ conteudo = form.cleaned_data['conteudo']
+
+ OcorrenciaSessao.objects.filter(sessao_plenaria=self.object).delete()
+
+ ocorrencia = OcorrenciaSessao()
+ ocorrencia.sessao_plenaria_id = self.object.id
+ ocorrencia.conteudo = conteudo
+ ocorrencia.save()
+
+ msg = _('Registro salvo com sucesso')
+ messages.add_message(self.request, messages.SUCCESS, msg)
+
+ @method_decorator(permission_required('sessao.add_ocorrenciasessao'))
+ def post(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ form = OcorrenciaSessaoForm(request.POST)
+
+ if not form.is_valid():
+ return self.form_invalid(form)
+
+ if request.POST.get('delete'):
+ self.delete()
+
+ elif request.POST.get('save'):
+ self.save(form)
+
+ return self.form_valid(form)
+
+ def get_success_url(self):
+ pk = self.kwargs['pk']
+ return reverse('sapl.sessao:ocorrencia_sessao', kwargs={'pk': pk})
+
+
class VotacaoEditView(SessaoPermissionMixin):
'''
diff --git a/sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html b/sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html
new file mode 100644
index 000000000..b1385e7c2
--- /dev/null
+++ b/sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html
@@ -0,0 +1,6 @@
+
+
+ Ocorrências da Sessão:
+ {{object.ocorrenciasessao.conteudo|safe}}
+
+
diff --git a/sapl/templates/sessao/blocos_resumo/ocorrencias_da_sessao.html b/sapl/templates/sessao/blocos_resumo/ocorrencias_da_sessao.html
new file mode 100644
index 000000000..c56a1bb69
--- /dev/null
+++ b/sapl/templates/sessao/blocos_resumo/ocorrencias_da_sessao.html
@@ -0,0 +1,6 @@
+
+ Ocorrências da Sessão
+
+
{{object.ocorrenciasessao.conteudo|safe}}
+
+
\ No newline at end of file
diff --git a/sapl/templates/sessao/ocorrencia_sessao.html b/sapl/templates/sessao/ocorrencia_sessao.html
new file mode 100644
index 000000000..0daa921d8
--- /dev/null
+++ b/sapl/templates/sessao/ocorrencia_sessao.html
@@ -0,0 +1,32 @@
+{% extends "crud/detail.html" %}
+{% load i18n %}
+{% load crispy_forms_tags %}
+{% load common_tags %}
+
+{% block actions %}{% endblock %}
+
+{% block title %}Ocorrências da Sessão ({{ object }}) {% endblock %}
+
+{% block detail_content %}
+ {% if perms|get_add_perm:view %}
+
+ {% else %}
+ {{object.ocorrenciasessao.conteudo|safe}}
+ {% endif %}
+{% endblock detail_content %}
+
+
+{% block extra_js %}
+ {% if perms|get_add_perm:view %}
+
+ {% endif %}
+{% endblock %}
\ No newline at end of file
diff --git a/sapl/templates/sessao/resumo.html b/sapl/templates/sessao/resumo.html
index b5831bdca..c7c2070ce 100644
--- a/sapl/templates/sessao/resumo.html
+++ b/sapl/templates/sessao/resumo.html
@@ -50,5 +50,7 @@
{% include 'sessao/blocos_resumo/'|add:decimo_ordenacao %}
+ {% include 'sessao/blocos_resumo/'|add:decimo_primeiro_ordenacao %}
+
{% endblock detail_content %}
diff --git a/sapl/templates/sessao/resumo_ata.html b/sapl/templates/sessao/resumo_ata.html
index a842b3f40..e1c1000a9 100644
--- a/sapl/templates/sessao/resumo_ata.html
+++ b/sapl/templates/sessao/resumo_ata.html
@@ -19,5 +19,6 @@
{% include 'sessao/blocos_ata/'|add:oitavo_ordenacao %}
{% include 'sessao/blocos_ata/'|add:nono_ordenacao %}
{% include 'sessao/blocos_ata/'|add:decimo_ordenacao %}
+ {% include 'sessao/blocos_ata/'|add:decimo_primeiro_ordenacao %}
{% include 'sessao/blocos_ata/assinaturas.html' %}
{% endblock detail_content %}
\ No newline at end of file
diff --git a/sapl/templates/sessao/subnav.yaml b/sapl/templates/sessao/subnav.yaml
index 236d57c4c..0a98b8a3b 100644
--- a/sapl/templates/sessao/subnav.yaml
+++ b/sapl/templates/sessao/subnav.yaml
@@ -10,6 +10,8 @@
url: presenca
- title: {% trans 'Explicações Pessoais' %}
url: orador_list
+ - title: {% trans 'Ocorrências da Sessão' %}
+ url: ocorrencia_sessao
- title: {% trans 'Expedientes' %}
children:
From b6b3aec18841f3293789eb64523fcbe6f98be3e0 Mon Sep 17 00:00:00 2001
From: Talitha Pumar
Date: Tue, 9 Oct 2018 15:20:55 -0300
Subject: [PATCH 07/36] Fix #2252 Acompanhamento de Documento Administrativo
(#2257)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Fix #2252
* Muda mensagens de ERROR para WARNING in quando da erro no envio do email na tramitação
* Muda mensagens de ERROR para WARNING in quando da erro no envio do email na tramitação
* Fixing travis errors
* Fix tests
* Update acompanhar_documento.txt
* Update email_utils.py
* Update receivers.py
* Update test_email_templates.py
* adicionados testes de template dos email de acompanhamento
* tirar duplicidade
---
sapl/{materia => base}/email_utils.py | 134 ++++++++-----
sapl/base/receivers.py | 42 ++++
sapl/{materia => base}/signals.py | 0
sapl/materia/apps.py | 2 +-
sapl/materia/receivers.py | 29 ---
sapl/materia/tests/test_email_templates.py | 2 +-
sapl/materia/views.py | 15 +-
sapl/protocoloadm/apps.py | 3 +
sapl/protocoloadm/forms.py | 27 ++-
.../0008_acompanhamentodocumento.py | 32 +++
sapl/protocoloadm/models.py | 27 +++
.../tests/test_docadm_email_templates.py | 65 +++++++
sapl/protocoloadm/urls.py | 14 +-
sapl/protocoloadm/views.py | 184 +++++++++++++++++-
sapl/rules/map_rules.py | 1 +
sapl/rules/tests/test_rules.py | 4 +
.../templates/email/acompanhar_documento.html | 25 +++
sapl/templates/email/acompanhar_documento.txt | 16 ++
sapl/templates/email/tramitacao.html | 2 +
sapl/templates/email/tramitacao.txt | 4 +-
.../acompanhamento_documento.html | 21 ++
.../documentoadministrativo_filter.html | 3 +
22 files changed, 553 insertions(+), 99 deletions(-)
rename sapl/{materia => base}/email_utils.py (56%)
create mode 100644 sapl/base/receivers.py
rename sapl/{materia => base}/signals.py (100%)
delete mode 100644 sapl/materia/receivers.py
create mode 100644 sapl/protocoloadm/migrations/0008_acompanhamentodocumento.py
create mode 100644 sapl/protocoloadm/tests/test_docadm_email_templates.py
create mode 100644 sapl/templates/email/acompanhar_documento.html
create mode 100644 sapl/templates/email/acompanhar_documento.txt
create mode 100644 sapl/templates/protocoloadm/acompanhamento_documento.html
diff --git a/sapl/materia/email_utils.py b/sapl/base/email_utils.py
similarity index 56%
rename from sapl/materia/email_utils.py
rename to sapl/base/email_utils.py
index 3dc6b220d..737449e57 100644
--- a/sapl/materia/email_utils.py
+++ b/sapl/base/email_utils.py
@@ -8,7 +8,8 @@ from django.utils import timezone
from sapl.base.models import CasaLegislativa
from sapl.settings import EMAIL_SEND_USER
-from .models import AcompanhamentoMateria
+from sapl.materia.models import AcompanhamentoMateria
+from sapl.protocoloadm.models import AcompanhamentoDocumento
def load_email_templates(templates, context={}):
@@ -61,56 +62,73 @@ def enviar_emails(sender, recipients, messages):
fail_silently=False)
-def criar_email_confirmacao(base_url, casa_legislativa, materia, hash_txt=''):
+def criar_email_confirmacao(base_url, casa_legislativa, doc_mat, tipo, hash_txt=''):
if not casa_legislativa:
raise ValueError("Casa Legislativa é obrigatória")
- if not materia:
- raise ValueError("Matéria é obrigatória")
+ if not doc_mat:
+ if tipo == "materia":
+ msg = "Matéria é obrigatória"
+ else:
+ msg = "Documento é obrigatório"
+ raise ValueError(msg)
# FIXME i18n
- casa_nome = (casa_legislativa.nome + ' de ' +
- casa_legislativa.municipio + '-' +
- casa_legislativa.uf)
+ casa_nome = ("{} de {} - {}".format(casa_legislativa.nome,
+ casa_legislativa.municipio,
+ casa_legislativa.uf))
+
+ if tipo == "materia":
+ doc_mat_url = reverse('sapl.materia:materialegislativa_detail',
+ kwargs={'pk': doc_mat.id})
+ confirmacao_url = reverse('sapl.materia:acompanhar_confirmar',
+ kwargs={'pk': doc_mat.id})
+ ementa = doc_mat.ementa
+ autores = [autoria.autor.nome for autoria in doc_mat.autoria_set.all()]
+ else:
+ doc_mat_url = reverse('sapl.protocoloadm:documentoadministrativo_detail',
+ kwargs={'pk': doc_mat.id})
+ confirmacao_url = reverse('sapl.protocoloadm:acompanhar_confirmar',
+ kwargs={'pk': doc_mat.id})
+ ementa = doc_mat.assunto
+ autores = ""
- materia_url = reverse('sapl.materia:materialegislativa_detail',
- kwargs={'pk': materia.id})
- confirmacao_url = reverse('sapl.materia:acompanhar_confirmar',
- kwargs={'pk': materia.id})
- autores = []
- for autoria in materia.autoria_set.all():
- autores.append(autoria.autor.nome)
templates = load_email_templates(['email/acompanhar.txt',
'email/acompanhar.html'],
{"casa_legislativa": casa_nome,
"logotipo": casa_legislativa.logotipo,
- "descricao_materia": materia.ementa,
+ "descricao_materia": ementa,
"autoria": autores,
"hash_txt": hash_txt,
"base_url": base_url,
- "materia": str(materia),
- "materia_url": materia_url,
+ "materia": str(doc_mat),
+ "materia_url": doc_mat_url,
"confirmacao_url": confirmacao_url, })
return templates
-def do_envia_email_confirmacao(base_url, casa, materia, destinatario):
+def do_envia_email_confirmacao(base_url, casa, tipo, doc_mat, destinatario):
#
# Envia email de confirmacao para atualizações de tramitação
#
sender = EMAIL_SEND_USER
# FIXME i18n
- subject = "[SAPL] " + str(materia) + " - Ative o Acompanhamento da Materia"
+ if tipo == "materia":
+ msg = " - Ative o Acompanhamento da Matéria"
+ else:
+ msg = " - Ative o Acompanhamento de Documento"
+ subject = "[SAPL] {} {}".format(str(doc_mat), msg)
messages = []
recipients = []
email_texts = criar_email_confirmacao(base_url,
casa,
- materia,
+ doc_mat,
+ tipo,
destinatario.hash,)
recipients.append(destinatario.email)
messages.append({
@@ -123,30 +141,41 @@ def do_envia_email_confirmacao(base_url, casa, materia, destinatario):
enviar_emails(sender, recipients, messages)
-def criar_email_tramitacao(base_url, casa_legislativa, materia, status,
+def criar_email_tramitacao(base_url, casa_legislativa, tipo, doc_mat, status,
unidade_destino, hash_txt=''):
if not casa_legislativa:
raise ValueError("Casa Legislativa é obrigatória")
- if not materia:
- raise ValueError("Matéria é obrigatória")
+ if not doc_mat:
+ if tipo == "materia":
+ msg = "Matéria é obrigatória"
+ else:
+ msg = "Documento é obrigatório"
+ raise ValueError(msg)
# FIXME i18n
- casa_nome = (casa_legislativa.nome + ' de ' +
- casa_legislativa.municipio + '-' +
- casa_legislativa.uf)
-
- url_materia = reverse('sapl.materia:tramitacao_list',
- kwargs={'pk': materia.id})
- url_excluir = reverse('sapl.materia:acompanhar_excluir',
- kwargs={'pk': materia.id})
+ casa_nome = ("{} de {} - {}".format(casa_legislativa.nome,
+ casa_legislativa.municipio,
+ casa_legislativa.uf))
+ if tipo == "materia":
+ doc_mat_url = reverse('sapl.materia:tramitacao_list',
+ kwargs={'pk': doc_mat.id})
+ url_excluir = reverse('sapl.materia:acompanhar_excluir',
+ kwargs={'pk': doc_mat.id})
+
+ ementa = doc_mat.ementa
+ autores = [autoria.autor.nome for autoria in doc_mat.autoria_set.all()]
+ tramitacao = doc_mat.tramitacao_set.last()
- autores = []
- for autoria in materia.autoria_set.all():
- autores.append(autoria.autor.nome)
-
- tramitacao = materia.tramitacao_set.last()
+ else:
+ doc_mat_url = reverse('sapl.protocoloadm:tramitacaoadministrativo_list',
+ kwargs={'pk': doc_mat.id})
+ url_excluir = reverse('sapl.protocoloadm:acompanhar_excluir',
+ kwargs={'pk': doc_mat.id})
+ autores = ""
+ ementa = doc_mat.assunto
+ tramitacao = doc_mat.tramitacaoadministrativo_set.last()
templates = load_email_templates(['email/tramitacao.txt',
'email/tramitacao.html'],
@@ -154,34 +183,42 @@ def criar_email_tramitacao(base_url, casa_legislativa, materia, status,
"data_registro": dt.strftime(
timezone.now(),
"%d/%m/%Y"),
- "cod_materia": materia.id,
+ "cod_materia": doc_mat.id,
"logotipo": casa_legislativa.logotipo,
- "descricao_materia": materia.ementa,
+ "descricao_materia": ementa,
"autoria": autores,
"data": tramitacao.data_tramitacao,
"status": status,
"localizacao": unidade_destino,
"texto_acao": tramitacao.texto,
"hash_txt": hash_txt,
- "materia": str(materia),
+ "materia": str(doc_mat),
"base_url": base_url,
- "materia_url": url_materia,
+ "materia_url": doc_mat_url,
"excluir_url": url_excluir})
return templates
-def do_envia_email_tramitacao(base_url, materia, status, unidade_destino):
+def do_envia_email_tramitacao(base_url, tipo, doc_mat, status, unidade_destino):
#
# Envia email de tramitacao para usuarios cadastrados
#
- destinatarios = AcompanhamentoMateria.objects.filter(materia=materia,
- confirmado=True)
+ if tipo == "materia":
+ destinatarios = AcompanhamentoMateria.objects.filter(materia=doc_mat,
+ confirmado=True)
+ else:
+ destinatarios = AcompanhamentoDocumento.objects.filter(documento=doc_mat,
+ confirmado=True)
+
casa = CasaLegislativa.objects.first()
sender = EMAIL_SEND_USER
- # FIXME i18n
- subject = "[SAPL] " + str(materia) + \
- " - Acompanhamento de Materia Legislativa"
+ # FIXME i18nn
+ if tipo == "materia":
+ msg = " - Acompanhamento de Matéria Legislativa"
+ else:
+ msg = " - Acompanhamento de Documento"
+ subject = "[SAPL] {} {}".format(str(doc_mat), msg)
connection = get_connection()
connection.open()
@@ -190,10 +227,11 @@ def do_envia_email_tramitacao(base_url, materia, status, unidade_destino):
try:
email_texts = criar_email_tramitacao(base_url,
casa,
- materia,
+ tipo,
+ doc_mat,
status,
unidade_destino,
- destinatario.hash,)
+ destinatario.hash)
email = EmailMultiAlternatives(
subject,
diff --git a/sapl/base/receivers.py b/sapl/base/receivers.py
new file mode 100644
index 000000000..b2176be14
--- /dev/null
+++ b/sapl/base/receivers.py
@@ -0,0 +1,42 @@
+from django.db.models.signals import post_delete, post_save
+from django.dispatch import receiver
+
+from sapl.materia.models import Tramitacao
+from sapl.protocoloadm.models import TramitacaoAdministrativo
+from sapl.base.signals import tramitacao_signal
+from sapl.utils import get_base_url
+
+from sapl.base.email_utils import do_envia_email_tramitacao
+
+
+@receiver(tramitacao_signal)
+def handle_tramitacao_signal(sender, **kwargs):
+ tramitacao = kwargs.get("post")
+ request = kwargs.get("request")
+ if 'protocoloadm' in str(sender):
+ doc_mat = tramitacao.documento
+ tipo = "documento"
+ elif 'materia' in str(sender):
+ tipo = "materia"
+ doc_mat = tramitacao.materia
+
+ do_envia_email_tramitacao(
+ get_base_url(request),
+ tipo,
+ doc_mat,
+ tramitacao.status,
+ tramitacao.unidade_tramitacao_destino)
+
+
+@receiver(post_delete)
+def status_tramitacao_materia(sender, instance, **kwargs):
+ if isinstance(sender, TramitacaoAdministrativo):
+ if instance.status.indicador == 'F':
+ materia = instance.materia
+ materia.em_tramitacao = True
+ materia.save()
+ elif isinstance(sender, TramitacaoAdministrativo):
+ if instance.status.indicador == 'F':
+ documento = instance.documento
+ documento.tramitacao = True
+ documento.save()
diff --git a/sapl/materia/signals.py b/sapl/base/signals.py
similarity index 100%
rename from sapl/materia/signals.py
rename to sapl/base/signals.py
diff --git a/sapl/materia/apps.py b/sapl/materia/apps.py
index bb4f72f73..2cc3559ae 100644
--- a/sapl/materia/apps.py
+++ b/sapl/materia/apps.py
@@ -8,4 +8,4 @@ class AppConfig(apps.AppConfig):
verbose_name = _('Matéria')
def ready(self):
- from . import receivers
+ from sapl.base import receivers
diff --git a/sapl/materia/receivers.py b/sapl/materia/receivers.py
deleted file mode 100644
index 945c6636e..000000000
--- a/sapl/materia/receivers.py
+++ /dev/null
@@ -1,29 +0,0 @@
-from django.db.models.signals import post_delete, post_save
-from django.dispatch import receiver
-
-from sapl.materia.models import Tramitacao
-from sapl.materia.signals import tramitacao_signal
-from sapl.utils import get_base_url
-
-from .email_utils import do_envia_email_tramitacao
-
-
-@receiver(tramitacao_signal)
-def handle_tramitacao_signal(sender, **kwargs):
- tramitacao = kwargs.get("post")
- request = kwargs.get("request")
- materia = tramitacao.materia
-
- do_envia_email_tramitacao(
- get_base_url(request),
- materia,
- tramitacao.status,
- tramitacao.unidade_tramitacao_destino)
-
-
-@receiver(post_delete, sender=Tramitacao)
-def status_tramitacao_materia(sender, instance, **kwargs):
- if instance.status.indicador == 'F':
- materia = instance.materia
- materia.em_tramitacao = True
- materia.save()
diff --git a/sapl/materia/tests/test_email_templates.py b/sapl/materia/tests/test_email_templates.py
index aac13cbb7..32b2f7ec8 100644
--- a/sapl/materia/tests/test_email_templates.py
+++ b/sapl/materia/tests/test_email_templates.py
@@ -1,6 +1,6 @@
from django.core import mail
-from sapl.materia.email_utils import enviar_emails, load_email_templates
+from sapl.base.email_utils import enviar_emails, load_email_templates
def test_email_template_loading():
diff --git a/sapl/materia/views.py b/sapl/materia/views.py
index 9e738dbe9..767726a97 100644
--- a/sapl/materia/views.py
+++ b/sapl/materia/views.py
@@ -46,7 +46,7 @@ from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal,
get_mime_type_from_file_extension, montar_row_autor,
show_results_filter_set)
-from .email_utils import do_envia_email_confirmacao
+from sapl.base.email_utils import do_envia_email_confirmacao
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AdicionarVariasAutoriasFilterSet, DespachoInicialForm,
DocumentoAcessorioForm, EtiquetaPesquisaForm,
@@ -65,7 +65,7 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria,
RegimeTramitacao, Relatoria, StatusTramitacao,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa,
TipoProposicao, Tramitacao, UnidadeTramitacao)
-from .signals import tramitacao_signal
+from sapl.base.signals import tramitacao_signal
AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia')
@@ -1114,7 +1114,7 @@ class TramitacaoCrud(MasterDetailCrud):
msg = _('Tramitação criada, mas e-mail de acompanhamento '
'de matéria não enviado. Há problemas na configuração '
'do e-mail.')
- messages.add_message(self.request, messages.ERROR, msg)
+ messages.add_message(self.request, messages.WARNING, msg)
return HttpResponseRedirect(self.get_success_url())
return super().form_valid(form)
@@ -1141,7 +1141,7 @@ class TramitacaoCrud(MasterDetailCrud):
msg = _('Tramitação atualizada, mas e-mail de acompanhamento '
'de matéria não enviado. Há problemas na configuração '
'do e-mail.')
- messages.add_message(self.request, messages.ERROR, msg)
+ messages.add_message(self.request, messages.WARNING, msg)
return HttpResponseRedirect(self.get_success_url())
return super().form_valid(form)
@@ -1683,6 +1683,7 @@ class AcompanhamentoMateriaView(CreateView):
do_envia_email_confirmacao(base_url,
casa,
+ "materia",
materia,
destinatario)
@@ -1876,9 +1877,9 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
flag_error = True
if flag_error:
msg = _('Tramitação criada, mas e-mail de acompanhamento '
- 'de matéria não enviado. Há problemas na configuração '
- 'do e-mail.')
- messages.add_message(self.request, messages.ERROR, msg)
+ 'de matéria não enviado. A não configuração do servidor de e-mail '
+ 'impede o envio de aviso de tramitação')
+ messages.add_message(self.request, messages.WARNING, msg)
status = StatusTramitacao.objects.get(id=request.POST['status'])
diff --git a/sapl/protocoloadm/apps.py b/sapl/protocoloadm/apps.py
index 8697e58d9..98e28ea36 100644
--- a/sapl/protocoloadm/apps.py
+++ b/sapl/protocoloadm/apps.py
@@ -6,3 +6,6 @@ class AppConfig(apps.AppConfig):
name = 'sapl.protocoloadm'
label = 'protocoloadm'
verbose_name = _('Protocolo Administrativo')
+
+ def ready(self):
+ from sapl.base import receivers
diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py
index 9985f522f..8c441ad93 100644
--- a/sapl/protocoloadm/forms.py
+++ b/sapl/protocoloadm/forms.py
@@ -2,7 +2,7 @@
import django_filters
from crispy_forms.bootstrap import InlineRadios
from crispy_forms.helper import FormHelper
-from crispy_forms.layout import HTML, Button, Fieldset, Layout
+from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout
from django import forms
from django.core.exceptions import (MultipleObjectsReturned,
ObjectDoesNotExist, ValidationError)
@@ -19,7 +19,8 @@ from sapl.materia.models import (MateriaLegislativa, TipoMateriaLegislativa,
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter,
RangeWidgetOverride, autor_label, autor_modal)
-from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo,
+from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo,
+ DocumentoAdministrativo,
Protocolo, TipoDocumentoAdministrativo,
TramitacaoAdministrativo)
@@ -39,6 +40,28 @@ EM_TRAMITACAO = [('', '---------'),
(0, 'Sim'),
(1, 'Não')]
+class AcompanhamentoDocumentoForm(ModelForm):
+
+ class Meta:
+ model = AcompanhamentoDocumento
+ fields = ['email']
+
+ def __init__(self, *args, **kwargs):
+
+ row1 = to_row([('email', 10)])
+
+ row1.append(
+ Column(form_actions(label='Cadastrar'), css_class='col-md-2')
+ )
+
+ self.helper = FormHelper()
+ self.helper.layout = Layout(
+ Fieldset(
+ _('Acompanhamento de Documento por e-mail'), row1
+ )
+ )
+ super(AcompanhamentoDocumentoForm, self).__init__(*args, **kwargs)
+
class ProtocoloFilterSet(django_filters.FilterSet):
diff --git a/sapl/protocoloadm/migrations/0008_acompanhamentodocumento.py b/sapl/protocoloadm/migrations/0008_acompanhamentodocumento.py
new file mode 100644
index 000000000..dcc25ed45
--- /dev/null
+++ b/sapl/protocoloadm/migrations/0008_acompanhamentodocumento.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2018-09-27 15:24
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('protocoloadm', '0007_auto_20180924_1724'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='AcompanhamentoDocumento',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('usuario', models.CharField(max_length=50)),
+ ('email', models.EmailField(max_length=100, verbose_name='E-mail')),
+ ('data_cadastro', models.DateField(auto_now_add=True)),
+ ('hash', models.CharField(max_length=8)),
+ ('confirmado', models.BooleanField(default=False)),
+ ('documento', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='protocoloadm.DocumentoAdministrativo')),
+ ],
+ options={
+ 'verbose_name_plural': 'Acompanhamentos de Documento',
+ 'verbose_name': 'Acompanhamento de Documento',
+ },
+ ),
+ ]
diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py
index 52bd9ad22..908aac542 100644
--- a/sapl/protocoloadm/models.py
+++ b/sapl/protocoloadm/models.py
@@ -298,3 +298,30 @@ class TramitacaoAdministrativo(models.Model):
return _('%(documento)s - %(status)s') % {
'documento': self.documento, 'status': self.status
}
+
+@reversion.register()
+class AcompanhamentoDocumento(models.Model):
+ usuario = models.CharField(max_length=50)
+ documento = models.ForeignKey(DocumentoAdministrativo, on_delete=models.CASCADE)
+ email = models.EmailField(
+ max_length=100, verbose_name=_('E-mail'))
+ data_cadastro = models.DateField(auto_now_add=True)
+ hash = models.CharField(max_length=8)
+ confirmado = models.BooleanField(default=False)
+
+ class Meta:
+ verbose_name = _('Acompanhamento de Documento')
+ verbose_name_plural = _('Acompanhamentos de Documento')
+
+ def __str__(self):
+ if self.data_cadastro is None:
+ return _('%(documento)s - %(email)s') % {
+ 'documento': self.documento,
+ 'email': self.email
+ }
+ else:
+ return _('%(documento)s - %(email)s - Registrado em: %(data)s') % {
+ 'documento': self.documento,
+ 'email': self.email,
+ 'data': str(self.data_cadastro.strftime('%d/%m/%Y'))
+ }
diff --git a/sapl/protocoloadm/tests/test_docadm_email_templates.py b/sapl/protocoloadm/tests/test_docadm_email_templates.py
new file mode 100644
index 000000000..ec79098fa
--- /dev/null
+++ b/sapl/protocoloadm/tests/test_docadm_email_templates.py
@@ -0,0 +1,65 @@
+from django.core import mail
+
+from sapl.base.email_utils import enviar_emails, load_email_templates
+
+
+def test_email_template_loading():
+ expected = "Hello Django"
+ emails = load_email_templates(['email/test_tramitacao.html'],
+ context={"name": "Django"})
+
+ # strip \n and \r to compare with expected
+ actual = emails[0].replace('\n', '').replace('\r', '')
+
+ assert actual == expected
+
+
+def test_html_email_body_with_materia():
+ templates = load_email_templates(['email/tramitacao.txt',
+ 'email/tramitacao.html'],
+ {"image": 'img/logo.png',
+ "casa_legislativa":
+ "Assembléia Parlamentar",
+ "data_registro": "25/02/2016",
+ "cod_materia": "1",
+ "descricao_materia": "Assunto de teste",
+ "data": "25/02/2016",
+ "status": "Arquivado",
+ "texto_acao": "Deliberado",
+ "hash_txt": "abc01f",
+ "materia_id": "794",
+ "base_url": "http://localhost:8000",
+ "materia_url":
+ "/docadm/764/acompanhar-documento",
+ "excluir_url":
+ "/docadm/764/acompanhar-excluir"})
+
+ assert len(templates) == 2
+
+
+def test_enviar_email_distintos():
+ NUM_MESSAGES = 10
+ messages = [{'recipient': 'user-' + str(i) + '@test.com',
+ 'subject': 'subject: ' + str(i),
+ 'txt_message': 'txt: ' + str(i),
+ 'html_message': '',
+ } for i in range(NUM_MESSAGES)]
+
+ recipients = [m['recipient'] for m in messages]
+
+ enviar_emails('test@sapl.com', recipients, messages)
+ assert len(mail.outbox) == NUM_MESSAGES
+
+
+def test_enviar_same_email():
+ NUM_MESSAGES = 10
+ messages = [{'recipient': 'user-' + str(i) + '@test.com',
+ 'subject': 'subject: ' + str(i),
+ 'txt_message': 'txt: ' + str(i),
+ 'html_message': '',
+ } for i in range(NUM_MESSAGES)]
+
+ recipients = [m['recipient'] for m in messages]
+
+ enviar_emails('test@sapl.com', recipients, [messages[0]])
+ assert len(mail.outbox) == 1
diff --git a/sapl/protocoloadm/urls.py b/sapl/protocoloadm/urls.py
index 8ed9216f2..67d5edb65 100644
--- a/sapl/protocoloadm/urls.py
+++ b/sapl/protocoloadm/urls.py
@@ -1,6 +1,9 @@
from django.conf.urls import include, url
-from sapl.protocoloadm.views import (AnularProtocoloAdmView,
+from sapl.protocoloadm.views import (AcompanhamentoDocumentoView,
+ AcompanhamentoConfirmarView,
+ AcompanhamentoExcluirView,
+ AnularProtocoloAdmView,
ComprovanteProtocoloView,
CriarDocumentoProtocolo,
DocumentoAcessorioAdministrativoCrud,
@@ -56,6 +59,15 @@ urlpatterns_protocolo = [
url(r'^protocoloadm/(?P\d+)/protocolo-mostrar$',
ProtocoloMostrarView.as_view(), name='protocolo_mostrar'),
+ url(r'^docadm/(?P\d+)/acompanhar-documento/$',
+ AcompanhamentoDocumentoView.as_view(), name='acompanhar_documento'),
+ url(r'^docadm/(?P\d+)/acompanhar-confirmar$',
+ AcompanhamentoConfirmarView.as_view(),
+ name='acompanhar_confirmar'),
+ url(r'^docadm/(?P\d+)/acompanhar-excluir$',
+ AcompanhamentoExcluirView.as_view(),
+ name='acompanhar_excluir'),
+
url(r'^protocoloadm/(?P\d+)/continuar$',
diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py
index d58b1e11b..67ea62d5d 100644
--- a/sapl/protocoloadm/views.py
+++ b/sapl/protocoloadm/views.py
@@ -1,3 +1,6 @@
+from datetime import datetime
+from random import choice
+from string import ascii_letters, digits
from braces.views import FormValidMessageMixin
from django.contrib import messages
@@ -18,25 +21,30 @@ from django.views.generic.edit import FormView
from django_filters.views import FilterView
import sapl
-from sapl.base.models import Autor
+from sapl.base.models import Autor, CasaLegislativa
from sapl.comissoes.models import Comissao
from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.parlamentares.models import Legislatura, Parlamentar
from sapl.protocoloadm.models import Protocolo
-from sapl.utils import (create_barcode, get_client_ip,
+from sapl.utils import (create_barcode, get_base_url, get_client_ip,
get_mime_type_from_file_extension,
show_results_filter_set)
-
-from .forms import (AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm,
+from sapl.base.email_utils import do_envia_email_confirmacao
+from .forms import (AcompanhamentoDocumentoForm, AnularProcoloAdmForm,
+ DocumentoAcessorioAdministrativoForm,
DocumentoAdministrativoFilterSet,
DocumentoAdministrativoForm, ProtocoloDocumentForm,
ProtocoloFilterSet, ProtocoloMateriaForm,
- TramitacaoAdmEditForm, TramitacaoAdmForm, DesvincularDocumentoForm, DesvincularMateriaForm,
- filtra_tramitacao_adm_destino_and_status, filtra_tramitacao_adm_destino, filtra_tramitacao_adm_status)
-from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo,
- StatusTramitacaoAdministrativo,
+ TramitacaoAdmEditForm, TramitacaoAdmForm,
+ DesvincularDocumentoForm, DesvincularMateriaForm,
+ filtra_tramitacao_adm_destino_and_status,
+ filtra_tramitacao_adm_destino, filtra_tramitacao_adm_status)
+from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo,
+ DocumentoAdministrativo, StatusTramitacaoAdministrativo,
TipoDocumentoAdministrativo, TramitacaoAdministrativo)
+from sapl.base.signals import tramitacao_signal
+
TipoDocumentoAdministrativoCrud = CrudAux.build(
TipoDocumentoAdministrativo, '')
@@ -89,6 +97,136 @@ def doc_texto_integral(request, pk):
return response
raise Http404
+class AcompanhamentoConfirmarView(TemplateView):
+
+ def get_redirect_url(self, email):
+ msg = _('Este documento está sendo acompanhado pelo e-mail: %s') % (
+ email)
+ messages.add_message(self.request, messages.SUCCESS, msg)
+ return reverse('sapl.protocoloadm:documentoadministrativo_detail',
+ kwargs={'pk': self.kwargs['pk']})
+
+ def get(self, request, *args, **kwargs):
+ documento_id = kwargs['pk']
+ hash_txt = request.GET.get('hash_txt', '')
+
+ try:
+ acompanhar = AcompanhamentoDocumento.objects.get(
+ documento_id=documento_id,
+ hash=hash_txt)
+ except ObjectDoesNotExist:
+ raise Http404()
+ # except MultipleObjectsReturned:
+ # A melhor solução deve ser permitir que a exceção
+ # (MultipleObjectsReturned) seja lançada e vá para o log,
+ # pois só poderá ser causada por um erro de desenvolvimente
+
+ acompanhar.confirmado = True
+ acompanhar.save()
+
+ return HttpResponseRedirect(self.get_redirect_url(acompanhar.email))
+
+
+class AcompanhamentoExcluirView(TemplateView):
+
+ def get_success_url(self):
+ msg = _('Você parou de acompanhar este Documento.')
+ messages.add_message(self.request, messages.INFO, msg)
+ return reverse('sapl.protocoloadm:documentoadministrativo_detail',
+ kwargs={'pk': self.kwargs['pk']})
+
+ def get(self, request, *args, **kwargs):
+ materia_id = kwargs['pk']
+ hash_txt = request.GET.get('hash_txt', '')
+
+ try:
+ AcompanhamentoDocumento.objects.get(documento_id=documento_id,
+ hash=hash_txt).delete()
+ except ObjectDoesNotExist:
+ pass
+
+ return HttpResponseRedirect(self.get_success_url())
+
+
+class AcompanhamentoDocumentoView(CreateView):
+ template_name = "protocoloadm/acompanhamento_documento.html"
+
+ def get_random_chars(self):
+ s = ascii_letters + digits
+ return ''.join(choice(s) for i in range(choice([6, 7])))
+
+ def get(self, request, *args, **kwargs):
+ pk = self.kwargs['pk']
+ documento = DocumentoAdministrativo.objects.get(id=pk)
+
+ return self.render_to_response(
+ {'form': AcompanhamentoDocumentoForm(),
+ 'documento': documento})
+
+ def post(self, request, *args, **kwargs):
+ form = AcompanhamentoDocumentoForm(request.POST)
+ pk = self.kwargs['pk']
+ documento = DocumentoAdministrativo.objects.get(id=pk)
+
+ if form.is_valid():
+ email = form.cleaned_data['email']
+ usuario = request.user
+
+ hash_txt = self.get_random_chars()
+
+ acompanhar = AcompanhamentoDocumento.objects.get_or_create(
+ documento=documento,
+ email=form.data['email'])
+
+ # Se o segundo elemento do retorno do get_or_create for True
+ # quer dizer que o elemento não existia
+ if acompanhar[1]:
+ acompanhar = acompanhar[0]
+ acompanhar.hash = hash_txt
+ acompanhar.usuario = usuario.username
+ acompanhar.confirmado = False
+ acompanhar.save()
+
+ base_url = get_base_url(request)
+
+ destinatario = AcompanhamentoDocumento.objects.get(
+ documento=documento,
+ email=email,
+ confirmado=False)
+ casa = CasaLegislativa.objects.first()
+
+ do_envia_email_confirmacao(base_url,
+ casa,
+ "documento",
+ documento,
+ destinatario)
+
+ msg = _('Foi enviado um e-mail de confirmação. Confira sua caixa \
+ de mensagens e clique no link que nós enviamos para \
+ confirmar o acompanhamento deste documento.')
+ messages.add_message(request, messages.SUCCESS, msg)
+
+ # Caso esse Acompanhamento já exista
+ # avisa ao usuário que esse documento já está sendo acompanhado
+ else:
+ msg = _('Este e-mail já está acompanhando esse documento.')
+ messages.add_message(request, messages.INFO, msg)
+
+ return self.render_to_response(
+ {'form': form,
+ 'documento': documento,
+ 'error': _('Esse documento já está\
+ sendo acompanhada por este e-mail.')})
+ return HttpResponseRedirect(self.get_success_url())
+ else:
+ return self.render_to_response(
+ {'form': form,
+ 'documento': documento})
+
+ def get_success_url(self):
+ return reverse('sapl.protocoloadm:documentoadministrativo_detail',
+ kwargs={'pk': self.kwargs['pk']})
+
class DocumentoAdministrativoMixin:
@@ -686,8 +824,38 @@ class TramitacaoAdmCrud(MasterDetailCrud):
'unidade_tramitacao_local'].widget.attrs['disabled'] = True
return context
+ def form_valid(self, form):
+ self.object = form.save()
+
+ try:
+ tramitacao_signal.send(sender=TramitacaoAdministrativo,
+ post=self.object,
+ request=self.request)
+ except Exception as e:
+ # TODO log error
+ msg = _('Tramitação criada, mas e-mail de acompanhamento '
+ 'de documento não enviado. A não configuração do'
+ ' servidor de e-mail impede o envio de aviso de tramitação')
+ messages.add_message(self.request, messages.WARNING, msg)
+ return HttpResponseRedirect(self.get_success_url())
+ return super().form_valid(form)
+
class UpdateView(MasterDetailCrud.UpdateView):
form_class = TramitacaoAdmEditForm
+ def form_valid(self, form):
+ self.object = form.save()
+ try:
+ tramitacao_signal.send(sender=TramitacaoAdministrativo,
+ post=self.object,
+ request=self.request)
+ except Exception as e:
+ # TODO log error
+ msg = _('Tramitação criada, mas e-mail de acompanhamento '
+ 'de documento não enviado. A não configuração do'
+ ' servidor de e-mail impede o envio de aviso de tramitação')
+ messages.add_message(self.request, messages.WARNING, msg)
+ return HttpResponseRedirect(self.get_success_url())
+ return super().form_valid(form)
class ListView(DocumentoAdministrativoMixin, MasterDetailCrud.ListView):
diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py
index 47a43d9e1..1a2d1fe8b 100644
--- a/sapl/rules/map_rules.py
+++ b/sapl/rules/map_rules.py
@@ -302,6 +302,7 @@ rules_group_anonymous = {
'group': SAPL_GROUP_ANONYMOUS,
'rules': [
(materia.AcompanhamentoMateria, [RP_ADD, RP_DELETE]),
+ (protocoloadm.AcompanhamentoDocumento, [RP_ADD, RP_DELETE]),
]
}
diff --git a/sapl/rules/tests/test_rules.py b/sapl/rules/tests/test_rules.py
index 07302bae5..e1ed7f7e4 100644
--- a/sapl/rules/tests/test_rules.py
+++ b/sapl/rules/tests/test_rules.py
@@ -11,6 +11,7 @@ from sapl.compilacao.models import (PerfilEstruturalTextoArticulado,
TipoDispositivo,
TipoDispositivoRelationship)
from sapl.materia.models import AcompanhamentoMateria
+from sapl.protocoloadm.models import AcompanhamentoDocumento
from sapl.rules import SAPL_GROUPS, map_rules
from sapl.test_urls import create_perms_post_migrate
from scripts.lista_permissions_in_decorators import \
@@ -61,6 +62,7 @@ __fp__in__test_permission_of_models_in_rules_patterns = {
PerfilEstruturalTextoArticulado],
map_rules.RP_CHANGE: [AcompanhamentoMateria,
+ AcompanhamentoDocumento,
TipoDispositivo,
TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado],
@@ -71,11 +73,13 @@ __fp__in__test_permission_of_models_in_rules_patterns = {
PerfilEstruturalTextoArticulado],
map_rules.RP_LIST: [AcompanhamentoMateria,
+ AcompanhamentoDocumento,
TipoDispositivo,
TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado],
map_rules.RP_DETAIL: [AcompanhamentoMateria,
+ AcompanhamentoDocumento,
TipoDispositivo,
TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado]
diff --git a/sapl/templates/email/acompanhar_documento.html b/sapl/templates/email/acompanhar_documento.html
new file mode 100644
index 000000000..f90558568
--- /dev/null
+++ b/sapl/templates/email/acompanhar_documento.html
@@ -0,0 +1,25 @@
+{% load i18n %}
+{% load static %}
+
+
+{{casa_legislativa}}
+
+ Sistema de Apoio ao Processo Legislativo
+
+
+Registramos seu pedido para acompanhamento por e-mail do documento administrativo identificado a seguir:
+{{documento}} - {{descricao_documento}}
+{{assunto}}
+
+
+Para garantia de sua privacidade, solicitamos que ative o recebimento das futuras mensagens clicando no link:
+
+
+
+
+Caso não tenha realizado o cadastramento em nosso sistema, favor desconsiderar a presente mensagem
+Esta é uma mensagem automática. Por favor, não responda.
+
+
diff --git a/sapl/templates/email/acompanhar_documento.txt b/sapl/templates/email/acompanhar_documento.txt
new file mode 100644
index 000000000..eab05d7d1
--- /dev/null
+++ b/sapl/templates/email/acompanhar_documento.txt
@@ -0,0 +1,16 @@
+{{casa_legislativa}}
+
+Sistema de Apoio ao Processo Legislativo
+
+>Registramos seu pedido para acompanhamento por e-mail do documento administrativo identificado a seguir:
+
+{{base_url}}{{documento_url}} - {{documento}} - {{descricao_documento}}
+
+{{assunto}}
+
+Para garantia de sua privacidade, solicitamos que ative o recebimento das futuras mensagens acessando no link:
+
+{{base_url}}{{url_confirmar}}?hash_txt={{hash_txt}}
+
+Caso não tenha realizado o cadastramento em nosso sistema, favor desconsiderar a presente mensagem
+Esta é uma mensagem automática. Por favor, não responda.
diff --git a/sapl/templates/email/tramitacao.html b/sapl/templates/email/tramitacao.html
index 4b30a1dc5..362fc563a 100644
--- a/sapl/templates/email/tramitacao.html
+++ b/sapl/templates/email/tramitacao.html
@@ -13,10 +13,12 @@
{{materia}} - {{descricao_materia}}
+{% if autoria %}
Autoria:
{% for autor in autoria %}
{{ autor }}
{% endfor %}
+{% endif %}
diff --git a/sapl/templates/email/tramitacao.txt b/sapl/templates/email/tramitacao.txt
index f0a06687a..bb68a87a0 100644
--- a/sapl/templates/email/tramitacao.txt
+++ b/sapl/templates/email/tramitacao.txt
@@ -8,12 +8,12 @@ A seguinte matéria, de seu interesse, sofreu Tramitação registrada em {{data_
Matéria: {{materia}} - {{descricao_materia}}
{{url_materia}}
-
+{% if autoria %}
Autoria:
{% for autor in autoria %}
{{ autor }}
{% endfor %}
-
+{% endif %}
Data da ação: {{data}}
Status: {{status}}
diff --git a/sapl/templates/protocoloadm/acompanhamento_documento.html b/sapl/templates/protocoloadm/acompanhamento_documento.html
new file mode 100644
index 000000000..b6526cc52
--- /dev/null
+++ b/sapl/templates/protocoloadm/acompanhamento_documento.html
@@ -0,0 +1,21 @@
+{% extends "crud/detail.html" %}
+{% load i18n %}
+{% load crispy_forms_tags %}
+{% block actions %} {% endblock %}
+{% block detail_content %}
+
+
Acompanhamento de Documento
+
+
+
Tipo: {{documento.tipo.sigla}} - {{documento.tipo.descricao}}
+
Número: {{documento.numero}}
+
Ano: {{documento.ano}}
+
+
+
+
Assunto: {{documento.assunto|safe}}
+
+
+{% if error %} {{ error }} {% endif %}
+{% crispy form %}
+{% endblock %}
diff --git a/sapl/templates/protocoloadm/documentoadministrativo_filter.html b/sapl/templates/protocoloadm/documentoadministrativo_filter.html
index e87962273..6dbd95276 100644
--- a/sapl/templates/protocoloadm/documentoadministrativo_filter.html
+++ b/sapl/templates/protocoloadm/documentoadministrativo_filter.html
@@ -63,6 +63,9 @@
{% if d.texto_integral %}
Texto Integral
{% endif %}
+ {% if d.tramitacao %}
+ Acompanhar Documento
+ {% endif %}
From e7c8491499cbc00780d9489ef9fdb9933b309168 Mon Sep 17 00:00:00 2001
From: Edward
Date: Tue, 9 Oct 2018 17:54:49 -0300
Subject: [PATCH 08/36] HOT-FIX: conserta estouro de campo em protocolo (#2291)
---
sapl/materia/forms.py | 3 +--
.../migrations/0008_auto_20181009_1741.py | 20 +++++++++++++++++++
sapl/protocoloadm/models.py | 2 +-
3 files changed, 22 insertions(+), 3 deletions(-)
create mode 100644 sapl/protocoloadm/migrations/0008_auto_20181009_1741.py
diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py
index 6f6a544cd..b244af69a 100644
--- a/sapl/materia/forms.py
+++ b/sapl/materia/forms.py
@@ -1855,14 +1855,13 @@ class ConfirmarProposicaoForm(ProposicaoForm):
else:
# numeracao == 'U' ou não informada
nm = Protocolo.objects.all().aggregate(Max('numero'))
-
protocolo = Protocolo()
protocolo.numero = (nm['numero__max'] + 1) if nm['numero__max'] else 1
protocolo.ano = timezone.now().year
protocolo.tipo_protocolo = '1'
- protocolo.interessado = str(proposicao.autor)
+ protocolo.interessado = str(proposicao.autor)[:200] # tamanho máximo 200
protocolo.autor = proposicao.autor
protocolo.assunto_ementa = proposicao.descricao
protocolo.numero_paginas = cd['numero_de_paginas']
diff --git a/sapl/protocoloadm/migrations/0008_auto_20181009_1741.py b/sapl/protocoloadm/migrations/0008_auto_20181009_1741.py
new file mode 100644
index 000000000..0ea354a29
--- /dev/null
+++ b/sapl/protocoloadm/migrations/0008_auto_20181009_1741.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2018-10-09 20:41
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('protocoloadm', '0007_auto_20180924_1724'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='protocolo',
+ name='interessado',
+ field=models.CharField(blank=True, max_length=200, verbose_name='Interessado'),
+ ),
+ ]
diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py
index 908aac542..aa4e7c0c2 100644
--- a/sapl/protocoloadm/models.py
+++ b/sapl/protocoloadm/models.py
@@ -67,7 +67,7 @@ class Protocolo(models.Model):
blank=True, null=True, verbose_name=_('Tipo de Protocolo'))
tipo_processo = models.PositiveIntegerField()
interessado = models.CharField(
- max_length=60, blank=True, verbose_name=_('Interessado'))
+ max_length=200, blank=True, verbose_name=_('Interessado'))
autor = models.ForeignKey(Autor,
blank=True,
null=True,
From ade8dd037dae91a43a213ab43b3606934b408d46 Mon Sep 17 00:00:00 2001
From: Edward Ribeiro
Date: Tue, 9 Oct 2018 17:55:30 -0300
Subject: [PATCH 09/36] Release: 3.1.123
---
docker-compose.yml | 2 +-
setup.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docker-compose.yml b/docker-compose.yml
index 1bfcf65f5..f14200c76 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -11,7 +11,7 @@ sapldb:
ports:
- "5432:5432"
sapl:
- image: interlegis/sapl:3.1.122
+ image: interlegis/sapl:3.1.123
restart: always
environment:
ADMIN_PASSWORD: interlegis
diff --git a/setup.py b/setup.py
index fac072615..1fb1a39e9 100644
--- a/setup.py
+++ b/setup.py
@@ -49,7 +49,7 @@ install_requires = [
]
setup(
name='interlegis-sapl',
- version='3.1.122',
+ version='3.1.123',
packages=find_packages(),
include_package_data=True,
license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007',
From be9d2964960bb1fe24f4a21b956bdcb1da6b8e4c Mon Sep 17 00:00:00 2001
From: Edward Ribeiro
Date: Tue, 9 Oct 2018 17:58:18 -0300
Subject: [PATCH 10/36] Bump release version on base template
---
sapl/templates/base.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sapl/templates/base.html b/sapl/templates/base.html
index 1953032a3..7cbf02352 100644
--- a/sapl/templates/base.html
+++ b/sapl/templates/base.html
@@ -184,7 +184,7 @@
Desenvolvido pelo Interlegis em software livre e aberto.
- Release: 3.1.121
+ Release: 3.1.123
From 6c1404a1c3180b04bcbfbcb739b042f132055de7 Mon Sep 17 00:00:00 2001
From: Leandro Roberto
Date: Wed, 10 Oct 2018 08:11:58 -0300
Subject: [PATCH 11/36] HOT-FIX: error travis
---
sapl/protocoloadm/migrations/0009_merge.py | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 sapl/protocoloadm/migrations/0009_merge.py
diff --git a/sapl/protocoloadm/migrations/0009_merge.py b/sapl/protocoloadm/migrations/0009_merge.py
new file mode 100644
index 000000000..b59fca714
--- /dev/null
+++ b/sapl/protocoloadm/migrations/0009_merge.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2018-10-10 11:10
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('protocoloadm', '0008_acompanhamentodocumento'),
+ ('protocoloadm', '0008_auto_20181009_1741'),
+ ]
+
+ operations = [
+ ]
From feb2eb9397f847df7a6883b7ecd0e1079f4629fc Mon Sep 17 00:00:00 2001
From: Victor Fabre
Date: Wed, 10 Oct 2018 09:20:44 -0300
Subject: [PATCH 12/36] Bump release version on base template
---
sapl/templates/base.html | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/sapl/templates/base.html b/sapl/templates/base.html
index 7cbf02352..c7cfd8b69 100644
--- a/sapl/templates/base.html
+++ b/sapl/templates/base.html
@@ -29,7 +29,7 @@
-
+
{% if not request|has_iframe %}
{% block navigation %}
@@ -184,7 +184,7 @@
Desenvolvido pelo Interlegis em software livre e aberto.
- Release: 3.1.123
+ Release: 3.1.124
@@ -252,7 +252,7 @@
From 16cc7fd289093dff86a89cfff517ee50d89ba522 Mon Sep 17 00:00:00 2001
From: Victor Fabre
Date: Wed, 10 Oct 2018 09:22:18 -0300
Subject: [PATCH 13/36] Release: 3.1.124
---
docker-compose.yml | 2 +-
setup.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docker-compose.yml b/docker-compose.yml
index f14200c76..b9d6d10ed 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -11,7 +11,7 @@ sapldb:
ports:
- "5432:5432"
sapl:
- image: interlegis/sapl:3.1.123
+ image: interlegis/sapl:3.1.124
restart: always
environment:
ADMIN_PASSWORD: interlegis
diff --git a/setup.py b/setup.py
index 1fb1a39e9..0b7838be2 100644
--- a/setup.py
+++ b/setup.py
@@ -49,7 +49,7 @@ install_requires = [
]
setup(
name='interlegis-sapl',
- version='3.1.123',
+ version='3.1.124',
packages=find_packages(),
include_package_data=True,
license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007',
From 660810b7a4ca5a87e95fd3b32a29b9eeb06490e7 Mon Sep 17 00:00:00 2001
From: Marcio Mazza
Date: Wed, 10 Oct 2018 18:45:44 -0300
Subject: [PATCH 14/36] =?UTF-8?q?Adiciona=20url=20p=20tipo=20de=20situa?=
=?UTF-8?q?=C3=A7=C3=A3o=20militar=20ao=20ressuscitar?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
sapl/legacy/scripts/ressuscita_dependencias.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sapl/legacy/scripts/ressuscita_dependencias.py b/sapl/legacy/scripts/ressuscita_dependencias.py
index 19cb875d8..32b7986d7 100644
--- a/sapl/legacy/scripts/ressuscita_dependencias.py
+++ b/sapl/legacy/scripts/ressuscita_dependencias.py
@@ -1,16 +1,16 @@
from collections import OrderedDict
from textwrap import dedent
+import texttable
import yaml
+from unipath import Path
-import texttable
from sapl.legacy.migracao_dados import (PROPAGACOES_DE_EXCLUSAO,
campos_novos_para_antigos, exec_legado,
get_arquivo_ajustes_pre_migracao,
models_novos_para_antigos)
from sapl.legacy_migration_settings import (DIR_DADOS_MIGRACAO, DIR_REPO,
NOME_BANCO_LEGADO)
-from unipath import Path
def stripsplit(ll):
@@ -70,6 +70,7 @@ tipo_dependente /sistema/parlamentar/tipo-dependente
origem /sistema/materia/origem
documento_acessorio /materia/documentoacessorio
tipo_fim_relatoria /sistema/materia/tipo-fim-relatoria
+tipo_situacao_militar /sistema/parlamentar/tipo-militar
'''
urls = dict(stripsplit(urls))
From 6a6f98dbb44c87271dc3778c1fe88bda1c225e86 Mon Sep 17 00:00:00 2001
From: Marcio Mazza
Date: Wed, 10 Oct 2018 18:46:08 -0300
Subject: [PATCH 15/36] =?UTF-8?q?Melhora=20feedback=20ao=20fazer=20scrapin?=
=?UTF-8?q?g=20de=20proposi=C3=A7=C3=A3o=20sde?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
sapl/legacy/migracao.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py
index c4c183b84..94fd25930 100644
--- a/sapl/legacy/migracao.py
+++ b/sapl/legacy/migracao.py
@@ -70,12 +70,13 @@ def scrap_sde(url, usuario, senha=None):
{'__ac_name': usuario, '__ac_password': senha})
assert res.status_code == 200
- url_proposicao = '{}/sapl_documentos/proposicao/{}/renderXML?xsl=__default__' # noqa
+ url_proposicao_tmpl = '{}/sapl_documentos/proposicao/{}/renderXML?xsl=__default__' # noqa
total = Proposicao.objects.count()
for num, proposicao in enumerate(Proposicao.objects.all()):
pk = proposicao.pk
- res = session.get(url_proposicao.format(url, pk))
- print("pk: {} status: {} (progresso: {:.2%})".format(
- pk, res.status_code, num / total))
+ url_proposicao = url_proposicao_tmpl.format(url, pk)
+ res = session.get(url_proposicao)
+ print("pk: {} status: {} {} (progresso: {:.2%})".format(
+ pk, res.status_code, url_proposicao, num / total))
if res.status_code == 200:
salva_conteudo_do_sde(proposicao, res.content)
From 9ade9c230201fd009dff6822f8b97a9093b76f48 Mon Sep 17 00:00:00 2001
From: Marcio Mazza
Date: Wed, 10 Oct 2018 19:23:45 -0300
Subject: [PATCH 16/36] Adiciona insert a ressuscitar
---
sapl/legacy/scripts/ressuscita_dependencias.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/sapl/legacy/scripts/ressuscita_dependencias.py b/sapl/legacy/scripts/ressuscita_dependencias.py
index 32b7986d7..5e12efc01 100644
--- a/sapl/legacy/scripts/ressuscita_dependencias.py
+++ b/sapl/legacy/scripts/ressuscita_dependencias.py
@@ -308,6 +308,9 @@ SQLS_CRIACAO = [
insert into parlamentar (cod_parlamentar, nom_completo, nom_parlamentar, sex_parlamentar, cod_casa, ind_ativo, ind_unid_deliberativa, ind_excluido)
values ({}, "DESCONHECIDO", "DESCONHECIDO", "M", 0, 0, 0, 0);
'''),
+ ('tipo_sessao_plenaria', '''
+ insert into tipo_sessao_plenaria (tip_sessao, nom_sessao, ind_excluido, num_minimo) values ({}, "DESCONHECIDO", 0, 0);
+ '''),
]
SQLS_CRIACAO = {k: (dedent(sql.strip()), extras)
for k, sql, *extras in SQLS_CRIACAO}
From beddd718cdf78894e2de12d6158c5e575c909ce7 Mon Sep 17 00:00:00 2001
From: Edward
Date: Thu, 11 Oct 2018 13:29:21 -0300
Subject: [PATCH 17/36] Bump Postgres version
---
docker-compose.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docker-compose.yml b/docker-compose.yml
index b9d6d10ed..dc3c58dfd 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,5 +1,5 @@
sapldb:
- image: postgres:9.6.8-alpine
+ image: postgres:10.5-alpine
restart: always
environment:
POSTGRES_PASSWORD: sapl
From adc4246994b784b9b4367b0443aca0613ef20551 Mon Sep 17 00:00:00 2001
From: Talitha Pumar
Date: Mon, 15 Oct 2018 09:20:38 -0300
Subject: [PATCH 18/36] Paginas personalizadas de erro (Melhorar a mensagem)
(#2294)
* paginas personalizadas de erro
* Update 500.html
---
sapl/templates/404.html | 171 ++++++++++++++++++++++++++++++++++++++++
sapl/templates/500.html | 135 +++++++++++++++++++++++++++++++
2 files changed, 306 insertions(+)
create mode 100644 sapl/templates/404.html
create mode 100644 sapl/templates/500.html
diff --git a/sapl/templates/404.html b/sapl/templates/404.html
new file mode 100644
index 000000000..484a2a8f2
--- /dev/null
+++ b/sapl/templates/404.html
@@ -0,0 +1,171 @@
+{% load i18n staticfiles sass_tags menus %}
+{% load common_tags %}
+
+
+
+
+
+
+
+
+ {% block head_title %}{% trans 'SAPL - Sistema de Apoio ao Processo Legislativo' %}{% endblock %}
+
+ {% block head_content %}
+
+
+ {# Styles #}
+
+
+
+
+
+
+
+
+ {# Scripts #}
+ {# modernizr must be in head (see http://modernizr.com/docs/#installing) #}
+ {% endblock %}
+
+
+
+
+
+ {% if not request|has_iframe %}
+ {% block navigation %}
+
+
+
+ {% endblock navigation %}
+
+ {# Header #}
+ {% block main_header %}
+
+ {% endblock main_header %}
+ {% else %}
+
+
+ {% endif %}
+
+
+ {% trans 'Página não encontrada! Erro 404' %}
+
+
+ {% block base_content %}
+ {% endblock %}
+ {% if not request|has_iframe %}
+ {% block footer_container %}
+
+
+ {% endblock footer_container %}
+ {% endif %}
+
+ {% block foot_js %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% block extra_js %}{% endblock %}
+
+
+
+ {% endblock foot_js %}
+
+
diff --git a/sapl/templates/500.html b/sapl/templates/500.html
new file mode 100644
index 000000000..ab1afae4f
--- /dev/null
+++ b/sapl/templates/500.html
@@ -0,0 +1,135 @@
+{% load i18n staticfiles sass_tags menus %}
+{% load common_tags %}
+
+
+
+
+
+
+
+
+ {% block head_title %}{% trans 'SAPL - Sistema de Apoio ao Processo Legislativo' %}{% endblock %}
+
+ {% block head_content %}
+
+
+ {# Styles #}
+
+
+
+
+
+
+
+
+ {# Scripts #}
+ {# modernizr must be in head (see http://modernizr.com/docs/#installing) #}
+ {% endblock %}
+
+
+
+
+
+ {% block navigation %}
+
+
+
+ {% endblock navigation %}
+
+ {# Header #}
+ {% block main_header %}
+
+ {% endblock main_header %}
+
+
+
+ {% trans 'Ocorreu um erro inesperado! Erro 500' %}
+
+
+ {% block base_content %}
+ {% endblock %}
+ {% block footer_container %}
+
+
+ {% endblock footer_container %}
+
+ {% block foot_js %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% block extra_js %}{% endblock %}
+
+ {% endblock foot_js %}
+
+
From 3258080531a9172f200f119459b45608c1bb77af Mon Sep 17 00:00:00 2001
From: Edward
Date: Mon, 15 Oct 2018 13:46:20 -0300
Subject: [PATCH 19/36] Fixes #2133 (#2299)
---
sapl/base/templatetags/common_tags.py | 13 +++++++++++++
sapl/templates/base.html | 2 +-
sapl/templates/crud/detail.html | 16 +++++++++++++++-
3 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py
index 71f63e130..440f747a4 100644
--- a/sapl/base/templatetags/common_tags.py
+++ b/sapl/base/templatetags/common_tags.py
@@ -198,6 +198,19 @@ def url(value):
return True
return False
+@register.filter
+def audio_url(value):
+ return True if url(value) and value.endswith("mp3") else False
+
+
+@register.filter
+def video_url(value):
+ return True if url(value) and value.endswith("mp4") else False
+
+@register.filter
+def file_extension(value):
+ import pathlib
+ return pathlib.Path(value).suffix.replace('.', '')
@register.filter
def cronometro_to_seconds(value):
diff --git a/sapl/templates/base.html b/sapl/templates/base.html
index c7cfd8b69..b93260845 100644
--- a/sapl/templates/base.html
+++ b/sapl/templates/base.html
@@ -1,6 +1,6 @@
+
{% load i18n staticfiles sass_tags menus %}
{% load common_tags %}
-
diff --git a/sapl/templates/crud/detail.html b/sapl/templates/crud/detail.html
index 4a1cad276..c1b2c6445 100644
--- a/sapl/templates/crud/detail.html
+++ b/sapl/templates/crud/detail.html
@@ -65,7 +65,21 @@