From 11c8d9283aa3e5e8414e2a4f5ddc256b491b7c60 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Silva Date: Tue, 26 Mar 2019 16:34:40 -0300 Subject: [PATCH 01/18] =?UTF-8?q?Cria=20Rodap=C3=A9=20Global=20por=20tipos?= =?UTF-8?q?=20de=20textos=20articulados=20(#2659)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add field rodape_global * add o field rodape_global ao formulário de edição e a renderização do texto --- sapl/compilacao/forms.py | 24 +++++++++++++++---- .../0011_tipotextoarticulado_rodape_global.py | 20 ++++++++++++++++ sapl/compilacao/models.py | 7 ++++++ sapl/templates/compilacao/layouts.yaml | 1 + sapl/templates/compilacao/text_list.html | 3 +++ 5 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 sapl/compilacao/migrations/0011_tipotextoarticulado_rodape_global.py diff --git a/sapl/compilacao/forms.py b/sapl/compilacao/forms.py index 71d6ad7e5..222a86aed 100644 --- a/sapl/compilacao/forms.py +++ b/sapl/compilacao/forms.py @@ -3,7 +3,6 @@ from datetime import timedelta from crispy_forms.bootstrap import (Alert, FieldWithButtons, FormActions, InlineCheckboxes, InlineRadios, StrictButton) -from sapl.crispy_layout_mixin import SaplFormHelper from crispy_forms.layout import (HTML, Button, Column, Div, Field, Fieldset, Layout, Row, Submit) from django import forms @@ -23,10 +22,12 @@ from sapl.compilacao.models import (NOTAS_PUBLICIDADE_CHOICES, TipoTextoArticulado, TipoVide, VeiculoPublicacao, Vide) from sapl.compilacao.utils import DISPOSITIVO_SELECT_RELATED +from sapl.crispy_layout_mixin import SaplFormHelper from sapl.crispy_layout_mixin import SaplFormLayout, to_column, to_row,\ form_actions from sapl.utils import YES_NO_CHOICES + error_messages = { 'required': _('Este campo é obrigatório'), 'invalid': _('URL inválida.') @@ -59,6 +60,13 @@ class TipoTaForm(ModelForm): widget=forms.RadioSelect(), required=True) + rodape_global = forms.CharField( + label=TipoTextoArticulado._meta.get_field( + 'rodape_global').verbose_name, + widget=forms.Textarea(attrs={'id': 'texto-rico'}), + required=False + ) + class Meta: model = TipoTextoArticulado fields = ['sigla', @@ -66,10 +74,12 @@ class TipoTaForm(ModelForm): 'content_type', 'participacao_social', 'publicacao_func', - 'perfis' + 'perfis', + 'rodape_global' ] - widgets = {'perfis': widgets.CheckboxSelectMultiple()} + widgets = {'perfis': widgets.CheckboxSelectMultiple(), + 'rodape_global': forms.Textarea} def __init__(self, *args, **kwargs): @@ -84,12 +94,18 @@ class TipoTaForm(ModelForm): ('perfis', 12), ]) + row3 = to_row([ + ('rodape_global', 12), + ]) + self.helper = SaplFormHelper() self.helper.layout = SaplFormLayout( Fieldset(_('Identificação Básica'), row1, css_class="col-md-12"), Fieldset(_('Funcionalidades'), - row2, css_class="col-md-12")) + row2, css_class="col-md-12"), + Fieldset(_('Nota de Rodapé Global'), + row3, css_class="col-md-12")) super(TipoTaForm, self).__init__(*args, **kwargs) diff --git a/sapl/compilacao/migrations/0011_tipotextoarticulado_rodape_global.py b/sapl/compilacao/migrations/0011_tipotextoarticulado_rodape_global.py new file mode 100644 index 000000000..f3b0e323b --- /dev/null +++ b/sapl/compilacao/migrations/0011_tipotextoarticulado_rodape_global.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-03-26 18:59 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('compilacao', '0010_auto_20181004_1939'), + ] + + operations = [ + migrations.AddField( + model_name='tipotextoarticulado', + name='rodape_global', + field=models.TextField(default='', help_text='A cada Tipo de Texto Articulado pode ser adicionado uma nota global de rodapé!', verbose_name='Rodapé Global'), + ), + ] diff --git a/sapl/compilacao/models.py b/sapl/compilacao/models.py index f36e406f9..f64285aee 100644 --- a/sapl/compilacao/models.py +++ b/sapl/compilacao/models.py @@ -149,6 +149,13 @@ class TipoTextoArticulado(models.Model): em edição. """)) + rodape_global = models.TextField( + verbose_name=_('Rodapé Global'), + help_text=_('A cada Tipo de Texto Articulado pode ser adicionado ' + 'uma nota global de rodapé!'), + default='' + ) + class Meta: verbose_name = _('Tipo de Texto Articulado') verbose_name_plural = _('Tipos de Texto Articulados') diff --git a/sapl/templates/compilacao/layouts.yaml b/sapl/templates/compilacao/layouts.yaml index 20446ba19..a92c8627b 100644 --- a/sapl/templates/compilacao/layouts.yaml +++ b/sapl/templates/compilacao/layouts.yaml @@ -45,3 +45,4 @@ TipoTextoArticulado: {% trans 'Funcionalidaes' %}: - participacao_social publicacao_func - perfis + - rodape_global diff --git a/sapl/templates/compilacao/text_list.html b/sapl/templates/compilacao/text_list.html index 3e9468e24..4efd992a9 100644 --- a/sapl/templates/compilacao/text_list.html +++ b/sapl/templates/compilacao/text_list.html @@ -18,4 +18,7 @@ {% endblock %} {% include 'compilacao/text_list__embedded.html'%} + {{object.tipo_ta.rodape_global|dont_break_out}} + + {% endblock base_content %} From c618d6781e19f1bc698fefc1463afb989e66e808 Mon Sep 17 00:00:00 2001 From: Edward Date: Wed, 27 Mar 2019 13:48:07 -0300 Subject: [PATCH 02/18] Fixes #2657 (#2661) --- sapl/sessao/views.py | 74 ++++++++----------- .../sessao/blocos_ata/materias_ordem_dia.html | 4 +- 2 files changed, 34 insertions(+), 44 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 4a080d155..236c9320d 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -1033,9 +1033,6 @@ class ListMateriaOrdemDiaView(FormMixin, DetailView): return self.get(self, request, args, kwargs) -def ordenar_integrantes_por_cargo(integrantes): - return sorted(integrantes, key=lambda k: k['cargo'].id) - class MesaView(FormMixin, DetailView): template_name = 'sessao/mesa.html' @@ -1338,24 +1335,17 @@ def get_conteudo_multimidia(sessao_plenaria): def get_mesa_diretora(sessao_plenaria): - mesa = IntegranteMesa.objects.filter(sessao_plenaria=sessao_plenaria) - integrantes = [] - for m in mesa: - parlamentar = Parlamentar.objects.get( - id=m.parlamentar_id) - cargo = CargoMesa.objects.get( - id=m.cargo_id) - integrante = {'parlamentar': parlamentar, 'cargo': cargo} - integrantes.append(integrante) - return ({'mesa': ordenar_integrantes_por_cargo(integrantes)}) + mesa = IntegranteMesa.objects.filter(sessao_plenaria=sessao_plenaria).order_by('cargo_id') + integrantes = [{'parlamentar': m.parlamentar, + 'cargo': m.cargo} for m in mesa] + return {'mesa': integrantes} def get_presenca_sessao(sessao_plenaria): - presencas = SessaoPlenariaPresenca.objects.filter( - sessao_plenaria_id=sessao_plenaria.id - ).order_by('parlamentar__nome_parlamentar') - parlamentares_sessao = [p.parlamentar for p in presencas] + parlamentares_sessao = [p.parlamentar for p in SessaoPlenariaPresenca.objects.filter( + sessao_plenaria_id=sessao_plenaria.id + ).order_by('parlamentar__nome_parlamentar')] ausentes_sessao = JustificativaAusencia.objects.filter( sessao_plenaria_id=sessao_plenaria.id @@ -1440,48 +1430,45 @@ def get_oradores_expediente(sessao_plenaria): 'observacao': observacao } oradores.append(ora) - context = {'oradores': oradores} - return context + return {'oradores': oradores} def get_presenca_ordem_do_dia(sessao_plenaria): - mesa_aux = get_mesa_diretora(sessao_plenaria) - presencas = PresencaOrdemDia.objects.filter( - sessao_plenaria_id=sessao_plenaria.id - ).order_by('parlamentar__nome_parlamentar') + parlamentares_ordem = [p.parlamentar for p in PresencaOrdemDia.objects.filter( + sessao_plenaria_id=sessao_plenaria.id + ).order_by('parlamentar__nome_parlamentar')] - parlamentares_mesa_dia = [m for m in mesa_aux['mesa']] + return {'presenca_ordem': parlamentares_ordem} - presidente_dia = '' - for m in mesa_aux['mesa']: - if m['cargo'].descricao == 'Presidente': - presidente_dia = [m['parlamentar']] - break - parlamentares_ordem = [p.parlamentar for p in presencas] +def get_assinaturas(sessao_plenaria): + mesa_dia = get_mesa_diretora(sessao_plenaria)['mesa'] - cont = 0 - for index, parlamentar in enumerate(parlamentares_ordem): - try: - if parlamentar == parlamentares_mesa_dia[cont]["parlamentar"]: - del(parlamentares_ordem[index]) - cont += 1 - except IndexError: - pass + presidente_dia = next(iter( + [m['parlamentar'] for m in mesa_dia if m['cargo'].descricao == 'Presidente']), + '') + + parlamentares_ordem = [p.parlamentar for p in PresencaOrdemDia.objects.filter( + sessao_plenaria_id=sessao_plenaria.id + ).order_by('parlamentar__nome_parlamentar')] + + parlamentares_mesa = [m['parlamentar'] for m in mesa_dia] + + # filtra parlamentares retirando os que sao da mesa + parlamentares_ordem = [p for p in parlamentares_ordem if p not in parlamentares_mesa] context = {} - context.update({'presenca_ordem': parlamentares_ordem}) config_assinatura_ata = AppsAppConfig.objects.first().assinatura_ata if config_assinatura_ata == 'T' and parlamentares_ordem: context.update( {'texto_assinatura': 'Assinatura de Todos os Parlamentares Presentes na Sessão'}) - context.update({'assinatura_mesa': parlamentares_mesa_dia, + context.update({'assinatura_mesa': mesa_dia, 'assinatura_presentes': parlamentares_ordem}) - elif config_assinatura_ata == 'M' and parlamentares_mesa_dia: + elif config_assinatura_ata == 'M' and mesa_dia: context.update( {'texto_assinatura': 'Assinatura da Mesa Diretora da Sessão'}) - context.update({'assinatura_presentes': parlamentares_mesa_dia}) + context.update({'assinatura_presentes': mesa_dia}) elif config_assinatura_ata == 'P' and presidente_dia: context.update( {'texto_assinatura': 'Assinatura do Presidente da Sessão'}) @@ -1649,6 +1636,9 @@ class ResumoView(DetailView): # Presença Ordem do Dia context.update(get_presenca_ordem_do_dia(self.object)) # ===================================================================== + # Assinaturas + context.update(get_assinaturas(self.object)) + # ===================================================================== # Matérias Ordem do Dia # Votos de Votação Nominal de Matérias Ordem do Dia materias_ordem_dia_votacao_nominal = OrdemDia.objects.filter( diff --git a/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html b/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html index 40c4e718a..ae1d494e2 100644 --- a/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html +++ b/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html @@ -4,9 +4,9 @@

{% for m in materias_ordem %}

- Materia do Expediente: {{m.numero}} - {{m.titulo}} + {{m.numero}} - {{m.titulo}} Descrição: {{m.ementa|safe}} - Autor: {{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }} + Autor {{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }} {% if m.numero_protocolo %} Número de Protocolo: {{ m.numero_protocolo }} {% endif %} From 973ff973250b53aa748340e288012fbc66ccf925 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 27 Mar 2019 15:48:18 -0300 Subject: [PATCH 03/18] Fixes #2663 --- sapl/sessao/views.py | 3 ++- sapl/templates/relatorios/header_ata.html | 2 +- sapl/templates/relatorios/relatorio_ata.html | 3 ++- .../sessao/blocos_ata/materias_ordem_dia.html | 10 +++++----- .../sessao/blocos_ata/ocorrencias_da_sessao.html | 8 ++++---- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 236c9320d..ae786377e 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -1316,7 +1316,8 @@ def get_identificação_basica(sessao_plenaria): 'abertura': abertura, 'hora_inicio': sessao_plenaria.hora_inicio}, _('Encerramento: %(encerramento)s %(hora_fim)s') % { 'encerramento': encerramento, 'hora_fim': sessao_plenaria.hora_fim} - ]}) + ], + 'sessaoplenaria': sessao_plenaria}) def get_conteudo_multimidia(sessao_plenaria): diff --git a/sapl/templates/relatorios/header_ata.html b/sapl/templates/relatorios/header_ata.html index 494d2c60b..4cc43efe6 100644 --- a/sapl/templates/relatorios/header_ata.html +++ b/sapl/templates/relatorios/header_ata.html @@ -19,7 +19,7 @@

    -
  • {{casa}}

  • +
  • {{casa.nome}}

  • Sistema de Apoio ao Processo Legislativo

diff --git a/sapl/templates/relatorios/relatorio_ata.html b/sapl/templates/relatorios/relatorio_ata.html index df927ba7f..743e13c82 100644 --- a/sapl/templates/relatorios/relatorio_ata.html +++ b/sapl/templates/relatorios/relatorio_ata.html @@ -37,7 +37,7 @@ -

Extrato Reunião

+

Extrato Eletrônico da {{sessaoplenaria}}

{% include 'sessao/blocos_ata/identificacao_basica.html' %} {% include 'sessao/blocos_ata/mesa_diretora.html' %} {% include 'sessao/blocos_ata/lista_presenca.html' %} @@ -47,6 +47,7 @@ {% include 'sessao/blocos_ata/lista_presenca_ordem_dia.html' %} {% include 'sessao/blocos_ata/materias_ordem_dia.html' %} {% include 'sessao/blocos_ata/oradores_explicacoes.html' %} + {% include 'sessao/blocos_ata/ocorrencias_da_sessao.html' %} {% if assinatura_mesa or assinatura_presentes %} diff --git a/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html b/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html index ae1d494e2..d894e8a06 100644 --- a/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html +++ b/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html @@ -1,19 +1,19 @@
-
+

Matérias da Ordem do Dia: -

{% for m in materias_ordem %} -

{{m.numero}} - {{m.titulo}} Descrição: {{m.ementa|safe}} - Autor {{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }} + Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }} {% if m.numero_protocolo %} Número de Protocolo: {{ m.numero_protocolo }} {% endif %} {% if m.numero_processo %} Processo:{{ m.numero_processo }} {% endif %} + {%if m.turno %} Turno: {{m.turno}} + {%endif %} Tipo: {{m.tipo_votacao}} Sim:{{m.voto_sim}} Não:{{m.voto_nao}} @@ -25,6 +25,6 @@ / {{voto.0}} - {{voto.1}} {% endfor %}; {% endif %} -

{% endfor %} +

\ No newline at end of file diff --git a/sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html b/sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html index 0896cd9b0..3b3092d89 100644 --- a/sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html +++ b/sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html @@ -1,8 +1,8 @@
-

- {% if object.ocorrenciasessao.conteudo %} - Ocorrências da Sessão: - {{object.ocorrenciasessao.conteudo|striptags|safe}} +

+ {% if object.ocorrenciasessao.conteudo %} + Ocorrências da Sessão: + {{object.ocorrenciasessao.conteudo|striptags|safe}} {% endif %}

From f64a4e8d791bdac20ec958a74b9e4807dd92a71b Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Wed, 27 Mar 2019 17:27:53 -0300 Subject: [PATCH 04/18] Fix #2663 (#2667) --- sapl/sessao/views.py | 8 ++++---- sapl/templates/sessao/blocos_ata/assinaturas.html | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index ae786377e..4e4ad02fa 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -1445,9 +1445,9 @@ def get_presenca_ordem_do_dia(sessao_plenaria): def get_assinaturas(sessao_plenaria): mesa_dia = get_mesa_diretora(sessao_plenaria)['mesa'] - presidente_dia = next(iter( + presidente_dia = [next(iter( [m['parlamentar'] for m in mesa_dia if m['cargo'].descricao == 'Presidente']), - '') + '')] parlamentares_ordem = [p.parlamentar for p in PresencaOrdemDia.objects.filter( sessao_plenaria_id=sessao_plenaria.id @@ -1469,11 +1469,11 @@ def get_assinaturas(sessao_plenaria): elif config_assinatura_ata == 'M' and mesa_dia: context.update( {'texto_assinatura': 'Assinatura da Mesa Diretora da Sessão'}) - context.update({'assinatura_presentes': mesa_dia}) + context.update({'assinatura_mesa': mesa_dia}) elif config_assinatura_ata == 'P' and presidente_dia: context.update( {'texto_assinatura': 'Assinatura do Presidente da Sessão'}) - context.update({'assinatura_presentes': presidente_dia}) + context.update({'assinatura_mesa': presidente_dia}) return context diff --git a/sapl/templates/sessao/blocos_ata/assinaturas.html b/sapl/templates/sessao/blocos_ata/assinaturas.html index 990b3f8a8..9eba4ce9b 100644 --- a/sapl/templates/sessao/blocos_ata/assinaturas.html +++ b/sapl/templates/sessao/blocos_ata/assinaturas.html @@ -11,7 +11,7 @@ {% endfor %} {% for p in assinatura_presentes %}
___________________________________________
- {{p.parlamentar.nome_completo}} / {{ p.parlamentar|filiacao_data_filter:object.data_inicio }} + {{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}


{% endfor %} From b912b03e9a0d27dc96988196be5df95dcd4c8546 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 28 Mar 2019 13:51:52 -0300 Subject: [PATCH 05/18] Release: 3.1.150 --- docker-compose.yml | 2 +- sapl/settings.py | 2 +- sapl/templates/base.html | 2 +- setup.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index cb498a26d..5ef3b240e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.149 + image: interlegis/sapl:3.1.150 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/sapl/settings.py b/sapl/settings.py index 517b76921..8bad6c92e 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -41,7 +41,7 @@ ALLOWED_HOSTS = ['*'] LOGIN_REDIRECT_URL = '/' LOGIN_URL = '/login/?next=' -SAPL_VERSION = '3.1.149' +SAPL_VERSION = '3.1.150' if DEBUG: EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' diff --git a/sapl/templates/base.html b/sapl/templates/base.html index a2de10343..2fa19c1cd 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -179,7 +179,7 @@ Desenvolvido pelo Interlegis em software livre e aberto. - Release: 3.1.149 + Release: 3.1.150

diff --git a/setup.py b/setup.py index dbfa7fe8f..1edc89a91 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.149', + version='3.1.150', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 0585bd7130efaa95b5718c3bebdadd3da8a51bea Mon Sep 17 00:00:00 2001 From: Edward Date: Thu, 28 Mar 2019 17:29:13 -0300 Subject: [PATCH 06/18] =?UTF-8?q?HOT-FIX:=20remove=20refer=C3=AAncia=20dup?= =?UTF-8?q?la=20a=20openssh-client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d970a4e4c..cc8d62e22 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM alpine:3.8 ENV BUILD_PACKAGES postgresql-dev graphviz-dev graphviz build-base git pkgconfig \ python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev \ nodejs py3-lxml py3-magic postgresql-client poppler-utils antiword \ - curl jq openssh-client vim openssh-client bash + curl jq openssh-client vim bash RUN apk update --update-cache && apk upgrade From 7e37308042141836943cd9744275855a5c1f004a Mon Sep 17 00:00:00 2001 From: Edward Date: Thu, 28 Mar 2019 17:48:37 -0300 Subject: [PATCH 07/18] =?UTF-8?q?HOT-FIX:=20Remove=20coment=C3=A1rio=20de?= =?UTF-8?q?=20Dockerfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index cc8d62e22..015357a40 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,9 +32,6 @@ RUN pip install -r /var/interlegis/sapl/requirements/dev-requirements.txt --upgr COPY config/env_dockerfile /var/interlegis/sapl/sapl/.env -# Configura timezone para BRT -# RUN cp /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime && echo "America/Sao_Paulo" > /etc/timezone - RUN python3 manage.py collectstatic --noinput --clear # Remove .env(fake) e sapl.db da imagem From c9d2295033cc70ad20f49185307ce3076f8c36ed Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Fri, 29 Mar 2019 15:33:01 -0300 Subject: [PATCH 08/18] =?UTF-8?q?Fix=20Documento=20Acess=C3=B3rio=20em=20L?= =?UTF-8?q?ote=20para=20Arquivos=20Grandes=20(#2664)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0044_auto_20190327_1409.py | 22 +++++++++++++ sapl/materia/models.py | 1 + sapl/materia/views.py | 32 ++++++++++++++++--- 3 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 sapl/materia/migrations/0044_auto_20190327_1409.py diff --git a/sapl/materia/migrations/0044_auto_20190327_1409.py b/sapl/materia/migrations/0044_auto_20190327_1409.py new file mode 100644 index 000000000..5322d7833 --- /dev/null +++ b/sapl/materia/migrations/0044_auto_20190327_1409.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-03-27 17:09 +from __future__ import unicode_literals + +from django.db import migrations, models +import sapl.materia.models +import sapl.utils + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0043_auto_20190320_1749'), + ] + + operations = [ + migrations.AlterField( + model_name='documentoacessorio', + name='arquivo', + field=models.FileField(blank=True, max_length=255, null=True, upload_to=sapl.materia.models.anexo_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Texto Integral'), + ), + ] diff --git a/sapl/materia/models.py b/sapl/materia/models.py index af4cb1231..c7aaaed15 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -497,6 +497,7 @@ class DocumentoAcessorio(models.Model): arquivo = models.FileField( blank=True, null=True, + max_length=255, upload_to=anexo_upload_path, verbose_name=_('Texto Integral'), validators=[restringe_tipos_de_arquivo_txt]) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 696b1235a..846f367fa 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -1,5 +1,10 @@ -from datetime import datetime import logging +import os +import shutil +import tempfile +import weasyprint + +from datetime import datetime from random import choice from string import ascii_letters, digits @@ -45,6 +50,7 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm, from sapl.norma.models import LegislacaoCitada from sapl.parlamentares.models import Legislatura from sapl.protocoloadm.models import Protocolo +from sapl.settings import MEDIA_ROOT from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH_PROPOSICAO, gerar_hash_arquivo, get_base_url, get_mime_type_from_file_extension, montar_row_autor, @@ -2035,17 +2041,35 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView): messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) + tmp_name = os.path.join(tempfile.gettempdir(), request.FILES['arquivo'].name) + with open(tmp_name, 'wb') as destination: + for chunk in request.FILES['arquivo'].chunks(): + destination.write(chunk) + + doc_data = tz.localize(datetime.strptime( + request.POST['data'], "%d/%m/%Y")) for materia_id in marcadas: doc = DocumentoAcessorio() doc.materia_id = materia_id doc.tipo = tipo - doc.arquivo = request.FILES['arquivo'] doc.nome = request.POST['nome'] - doc.data = tz.localize(datetime.strptime( - request.POST['data'], "%d/%m/%Y")) + doc.data = doc_data doc.autor = request.POST['autor'] doc.ementa = request.POST['ementa'] doc.save() + diretorio = os.path.join(MEDIA_ROOT, + 'sapl/public/documentoacessorio', + str(doc_data.year), + str(doc.id)) + if not os.path.exists(diretorio): + os.makedirs(diretorio) + file_path = os.path.join(diretorio, + request.FILES['arquivo'].name) + shutil.copy2(tmp_name, file_path) + doc.arquivo.name = file_path.split(MEDIA_ROOT)[1] # Retira MEDIA_ROOT do nome + doc.save() + os.remove(tmp_name) + msg = _('Documento(s) criado(s).') messages.add_message(request, messages.SUCCESS, msg) return self.get(request, self.kwargs) From fb6832e7fb38bab0a9938fd8ef4ff9caaa7cfdc0 Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Mon, 1 Apr 2019 14:29:06 -0300 Subject: [PATCH 09/18] =?UTF-8?q?Fix=20#2665=20-=20Tramitar=20mat=C3=A9ria?= =?UTF-8?q?s=20anexadas=20junto=20com=20as=20mat=C3=A9rias=20anexadoras=20?= =?UTF-8?q?(#2674)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/materia/views.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 846f367fa..a2366c8d9 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -3,6 +3,7 @@ import os import shutil import tempfile import weasyprint +import itertools from datetime import datetime from random import choice @@ -2249,8 +2250,18 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): # issue https://github.com/interlegis/sapl/issues/1123 # TODO: usar Form urgente = request.POST['urgente'] == 'True' - flag_error = False - for materia_id in marcadas: + flag_error = False + + materias_principais = [m for m in MateriaLegislativa.objects.filter(id__in=marcadas)] + materias_anexadas = [m.anexadas.all() for m in MateriaLegislativa.objects.filter(id__in=marcadas) if m.anexadas.all()] + materias_anexadas = list(itertools.chain.from_iterable(materias_anexadas)) + tramitacao_local = int(request.POST['unidade_tramitacao_local']) + materias_anexadas = list(filter(lambda ma : not ma.tramitacao_set.all() or \ + ma.tramitacao_set.last().unidade_tramitacao_destino.id == tramitacao_local, + materias_anexadas)) + materias = set(materias_principais + materias_anexadas) + + for materia in materias: try: data_tramitacao = tz.localize(datetime.strptime( request.POST['data_tramitacao'], "%d/%m/%Y")) @@ -2260,7 +2271,7 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): return self.get(request, self.kwargs) t = Tramitacao( - materia_id=materia_id, + materia=materia, data_tramitacao=data_tramitacao, data_encaminhamento=data_encaminhamento, data_fim_prazo=data_fim_prazo, @@ -2294,7 +2305,7 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): status = StatusTramitacao.objects.get(id=request.POST['status']) - for materia in MateriaLegislativa.objects.filter(id__in=marcadas): + for materia in materias: if status.indicador == 'F': materia.em_tramitacao = False elif self.primeira_tramitacao: From 2bcaedda76a8a99e4febac0595d2d4e565b2da22 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 1 Apr 2019 14:48:45 -0300 Subject: [PATCH 10/18] =?UTF-8?q?Retira=20atributos=20class=20e=20espa?= =?UTF-8?q?=C3=A7os=20de=20tags=20

?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/relatorios/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py index dec1d50b7..9439b1578 100755 --- a/sapl/relatorios/views.py +++ b/sapl/relatorios/views.py @@ -578,6 +578,8 @@ def get_sessao_plenaria(sessao, casa): # unescape HTML codes # https://github.com/interlegis/sapl/issues/1046 conteudo = re.sub('style=".*?"', '', conteudo) + conteudo = re.sub('class=".*?"', '', conteudo) + conteudo = re.sub('', '

', conteudo) conteudo = html.unescape(conteudo) # escape special character '&' From 4b35e6a4fe37ba10d6ac95ae02cc220a14c61e80 Mon Sep 17 00:00:00 2001 From: Ulysses Lara Date: Mon, 1 Apr 2019 15:09:50 -0300 Subject: [PATCH 11/18] Fix #2663 parte relacionada a turno (#2675) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #2663 parte relacionada a turno * Retira parênteses desnecessários --- sapl/sessao/views.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 4e4ad02fa..9300ab9e1 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -1378,9 +1378,15 @@ def get_materias_expediente(sessao_plenaria): ementa = m.materia.ementa titulo = m.materia numero = m.numero_ordem - tramitacao = m.materia.tramitacao_set.last() - turno = None + tramitacao = '' + tramitacoes = Tramitacao.objects.filter(materia=m.materia).order_by('-pk') + for aux_tramitacao in tramitacoes: + if aux_tramitacao.turno: + tramitacao = aux_tramitacao + break + + turno = None if tramitacao: turno = get_turno(tramitacao.turno) @@ -1486,7 +1492,14 @@ def get_materias_ordem_do_dia(sessao_plenaria): ementa_observacao = o.observacao titulo = o.materia numero = o.numero_ordem - tramitacao = o.materia.tramitacao_set.last() + + tramitacao = '' + tramitacoes = Tramitacao.objects.filter(materia=o.materia).order_by('-pk') + for aux_tramitacao in tramitacoes: + if aux_tramitacao.turno: + tramitacao = aux_tramitacao + break + turno = None if tramitacao: turno = get_turno(tramitacao.turno) From 52de1510019bdfbc77a6bcb962868bdf9356686e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Rodrigues?= Date: Mon, 1 Apr 2019 15:11:33 -0300 Subject: [PATCH 12/18] Fix #2671 (#2673) * Fix #2671 * Atualizar sessao/forms.py * Atualizar sessao/forms.py --- sapl/sessao/forms.py | 22 ++++++++++++++++++++++ sapl/sessao/views.py | 1 + 2 files changed, 23 insertions(+) diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index c2532b4a1..172b37be5 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -692,7 +692,29 @@ class OradorForm(ModelForm): self.fields['parlamentar'].queryset = Parlamentar.objects.filter( id__in=ids).order_by('nome_parlamentar') + + def clean(self): + super(OradorForm, self).clean() + cleaned_data = self.cleaned_data + + if not self.is_valid(): + return self.cleaned_data + sessao_id = self.initial['id_sessao'] + numero = self.initial.get('numero') + numero_ordem = cleaned_data['numero_ordem'] + ordem = Orador.objects.filter( + sessao_plenaria_id=sessao_id, + numero_ordem=numero_ordem + ).exists() + + if ordem and numero_ordem != numero: + raise ValidationError(_( + "Já existe orador nesta posição de ordem de pronunciamento" + )) + + return self.cleaned_data + class Meta: model = Orador exclude = ['sessao_plenaria'] diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 9300ab9e1..c5a6620c4 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -620,6 +620,7 @@ class OradorCrud(OradorCrud): def get_initial(self): initial = super(UpdateView, self).get_initial() initial.update({'id_sessao': self.object.sessao_plenaria.id}) + initial.update({'numero':self.object.numero_ordem}) return initial From 31e3cd7b4474c2273a8a8606110ec78bd772dc45 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 1 Apr 2019 17:29:10 -0300 Subject: [PATCH 13/18] Fix #2679 (#2680) --- sapl/materia/forms.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 4b75e134a..cf200447e 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -727,7 +727,7 @@ class AnexadaForm(ModelForm): empty_label='Selecione', ) - numero = forms.CharField(label='Número', required=True) + numero = forms.IntegerField(label='Número', required=True) ano = forms.CharField(label='Ano', required=True) @@ -751,8 +751,8 @@ class AnexadaForm(ModelForm): ano=cleaned_data['ano'], tipo=cleaned_data['tipo']) except ObjectDoesNotExist: - msg = _('A MateriaLegislativa a ser anexada (numero={}, ano={}, tipo={}) não existe no cadastro' - ' de matérias legislativas.'.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) + msg = _('A {} {}/{} não existe no cadastro de matérias legislativas.' + .format(cleaned_data['tipo'], cleaned_data['numero'], cleaned_data['ano'])) self.logger.error("A matéria a ser anexada não existe no cadastro" " de matérias legislativas.") raise ValidationError(msg) From 0b7ab48218e76a8cfb69e48499ab7b2779391e18 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 1 Apr 2019 17:29:17 -0300 Subject: [PATCH 14/18] Fix #2678 (#2681) --- sapl/sessao/urls.py | 6 ++++++ sapl/sessao/views.py | 19 +++++++++++++++++++ .../sessao/expedientemateria_list.html | 5 ++++- sapl/templates/sessao/ordemdia_list.html | 5 ++++- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/sapl/sessao/urls.py b/sapl/sessao/urls.py index 4da3a761a..ba0735ec6 100644 --- a/sapl/sessao/urls.py +++ b/sapl/sessao/urls.py @@ -28,6 +28,8 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente, remove_parlamentar_composicao, reordernar_materias_expediente, reordernar_materias_ordem, + renumerar_materias_ordem, + renumerar_materias_expediente, sessao_legislativa_legislatura_ajax, VotacaoEmBlocoOrdemDia, VotacaoEmBlocoExpediente, VotacaoEmBlocoSimbolicaView, VotacaoEmBlocoNominalView) @@ -75,6 +77,10 @@ urlpatterns = [ name="reordenar_expediente"), url(r'^sessao/(?P\d+)/reordenar-ordem$', reordernar_materias_ordem, name="reordenar_ordem"), + url(r'^sessao/(?P\d+)/renumerar-ordem$', renumerar_materias_ordem, + name="renumerar_ordem"), + url(r'^sessao/(?P\d+)/renumerar-materias-expediente$', renumerar_materias_expediente, + name="renumerar_materias_expediente"), url(r'^sistema/sessao-plenaria/tipo/', include(TipoSessaoCrud.get_urls())), url(r'^sistema/sessao-plenaria/tipo-resultado-votacao/', diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index c5a6620c4..550b231be 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -93,6 +93,25 @@ def reordernar_materias_ordem(request, pk): return HttpResponseRedirect( reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk})) +def renumerar_materias_ordem(request, pk): + ordens = OrdemDia.objects.filter(sessao_plenaria_id=pk) + + for ordem_num, o in enumerate(ordens, 1): + o.numero_ordem = ordem_num + o.save() + + return HttpResponseRedirect( + reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk})) + +def renumerar_materias_expediente(request, pk): + expedientes = ExpedienteMateria.objects.filter(sessao_plenaria_id=pk) + + for exp_num, e in enumerate(expedientes, 1): + e.numero_ordem = exp_num + e.save() + + return HttpResponseRedirect( + reverse('sapl.sessao:expedientemateria_list', kwargs={'pk': pk})) def verifica_presenca(request, model, spk): logger = logging.getLogger(__name__) diff --git a/sapl/templates/sessao/expedientemateria_list.html b/sapl/templates/sessao/expedientemateria_list.html index a2ce5e2ab..e1bd0f781 100644 --- a/sapl/templates/sessao/expedientemateria_list.html +++ b/sapl/templates/sessao/expedientemateria_list.html @@ -7,7 +7,10 @@ {% if perms|get_add_perm:view %} - {% blocktrans with verbose_name=view.verbose_name %} Ajustar Ordenação {% endblocktrans %} + {% blocktrans with verbose_name=view.verbose_name %} Reordenar pela precedência {% endblocktrans %} + + + {% blocktrans with verbose_name=view.verbose_name %} Renumerar Expediente {% endblocktrans %} {% blocktrans with verbose_name=view.verbose_name %} Adicionar Várias Matérias {% endblocktrans %} diff --git a/sapl/templates/sessao/ordemdia_list.html b/sapl/templates/sessao/ordemdia_list.html index d12e3f356..bc95cf1f1 100644 --- a/sapl/templates/sessao/ordemdia_list.html +++ b/sapl/templates/sessao/ordemdia_list.html @@ -7,7 +7,10 @@ {% if perms|get_add_perm:view %} - {% blocktrans with verbose_name=view.verbose_name %} Ajustar Ordenação {% endblocktrans %} + {% blocktrans with verbose_name=view.verbose_name %} Reordenar pela precedência {% endblocktrans %} + + + {% blocktrans with verbose_name=view.verbose_name %} Renumerar Ordem {% endblocktrans %} {% blocktrans with verbose_name=view.verbose_name %} Adicionar Várias Matérias {% endblocktrans %} From a64e7dbb093d7beb9f617746fa3b403457500b7f Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 1 Apr 2019 17:30:17 -0300 Subject: [PATCH 15/18] HOT-FIX: adiciona assinaturas no extrato do PDF --- sapl/relatorios/views.py | 17 +++++++++-------- sapl/templates/relatorios/relatorio_ata.html | 5 +++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py index 9439b1578..deb1e885f 100755 --- a/sapl/relatorios/views.py +++ b/sapl/relatorios/views.py @@ -28,10 +28,10 @@ from sapl.settings import STATIC_ROOT from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data from sapl.sessao.views import (get_identificação_basica, get_mesa_diretora, - get_presenca_sessao,get_expedientes, - get_materias_expediente,get_oradores_expediente, - get_presenca_ordem_do_dia,get_materias_ordem_do_dia, - get_oradores_explicações_pessoais, get_ocorrencias_da_sessão) + get_presenca_sessao, get_expedientes, + get_materias_expediente, get_oradores_expediente, + get_presenca_ordem_do_dia, get_materias_ordem_do_dia, + get_oradores_explicações_pessoais, get_ocorrencias_da_sessão, get_assinaturas) from .templates import (pdf_capa_processo_gerar, pdf_documento_administrativo_gerar, pdf_espelho_gerar, @@ -1258,12 +1258,13 @@ def resumo_ata_pdf(request,pk): context.update(get_materias_ordem_do_dia(sessao_plenaria)) context.update(get_oradores_explicações_pessoais(sessao_plenaria)) context.update(get_ocorrencias_da_sessão(sessao_plenaria)) - context.update({'object':sessao_plenaria}) + context.update(get_assinaturas(sessao_plenaria)) + context.update({'object': sessao_plenaria}) context.update({'data': dt.today().strftime('%d/%m/%Y')}) - context.update({'rodape':rodape}) - header_context = {"casa":casa, 'logotipo':casa.logotipo, 'MEDIA_URL': MEDIA_URL} + context.update({'rodape': rodape}) + header_context = {"casa": casa, 'logotipo':casa.logotipo, 'MEDIA_URL': MEDIA_URL} - html_template = render_to_string('relatorios/relatorio_ata.html',context) + html_template = render_to_string('relatorios/relatorio_ata.html', context) html_header = render_to_string('relatorios/header_ata.html', header_context) pdf_file = make_pdf(base_url=base_url,main_template=html_template,header_template=html_header) diff --git a/sapl/templates/relatorios/relatorio_ata.html b/sapl/templates/relatorios/relatorio_ata.html index 743e13c82..7d6c45d7b 100644 --- a/sapl/templates/relatorios/relatorio_ata.html +++ b/sapl/templates/relatorios/relatorio_ata.html @@ -82,12 +82,13 @@

{% else %}
_____________________
-

{{p.parlamentar.nome_completo}} / {{ p.parlamentar|filiacao_data_filter:object.data_inicio }}

+

{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}




From 8068e64be4275300c57fdf9f357350198d9a1e1c Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Tue, 2 Apr 2019 00:07:18 -0300 Subject: [PATCH 16/18] add endpoint get ultima_tramitacao --- sapl/api/views.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sapl/api/views.py b/sapl/api/views.py index f2f146e24..f15232871 100644 --- a/sapl/api/views.py +++ b/sapl/api/views.py @@ -349,6 +349,23 @@ class _ProposicaoViewSet(SaplSetViews['materia']['proposicao']): return qs +class _MateriaLegislativaViewSet(SaplSetViews['materia']['materialegislativa']): + + @action(detail=True, methods=['GET']) + def ultima_tramitacao(self, request, *args, **kwargs): + + materia = self.get_object() + if not materia.tramitacao_set.exists(): + return Response({}) + + ultima_tramitacao = materia.tramitacao_set.last() + + serializer_class = SaplSetViews[ + 'materia']['tramitacao'].serializer_class(ultima_tramitacao) + + return Response(serializer_class.data) + + class _TipoMateriaLegislativaViewSet(SaplSetViews['materia']['tipomaterialegislativa']): @action(detail=True, methods=['POST']) @@ -443,6 +460,8 @@ class _SessaoPlenariaViewSet( SaplSetViews['base']['autor'] = _AutorViewSet.build_class_with_actions() + +SaplSetViews['materia']['materialegislativa'] = _MateriaLegislativaViewSet SaplSetViews['materia']['proposicao'] = _ProposicaoViewSet SaplSetViews['materia']['tipomaterialegislativa'] = _TipoMateriaLegislativaViewSet From e523e9b23cc0b29b1e9c74312d5c1dd1a87fbc19 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Tue, 2 Apr 2019 00:18:05 -0300 Subject: [PATCH 17/18] corrige classe BusinessRulesNotImplementedMixin --- sapl/api/views.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sapl/api/views.py b/sapl/api/views.py index f15232871..5d2ca37eb 100644 --- a/sapl/api/views.py +++ b/sapl/api/views.py @@ -31,11 +31,8 @@ class BusinessRulesNotImplementedMixin: def create(self, request, *args, **kwargs): raise Exception(_("POST Create não implementado")) - def put(self, request, *args, **kwargs): - raise Exception(_("PUT Update não implementado")) - - def patch(self, request, *args, **kwargs): - raise Exception(_("PATCH Partial Update não implementado")) + def update(self, request, *args, **kwargs): + raise Exception(_("PUT and PATCH não implementado")) def delete(self, request, *args, **kwargs): raise Exception(_("DELETE Delete não implementado")) From dfe74c59f706f61547fa9cfb1f2d926b1d5b25f1 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Tue, 2 Apr 2019 02:02:23 -0300 Subject: [PATCH 18/18] =?UTF-8?q?simplifica=20customiza=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20viewsets=20da=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/api/urls.py | 7 +-- sapl/api/views.py | 110 ++++++++++++++++++++++++++++------------------ 2 files changed, 71 insertions(+), 46 deletions(-) diff --git a/sapl/api/urls.py b/sapl/api/urls.py index 3e874add2..27196146d 100644 --- a/sapl/api/urls.py +++ b/sapl/api/urls.py @@ -8,7 +8,7 @@ from rest_framework.routers import DefaultRouter from sapl.api.deprecated import MateriaLegislativaViewSet, SessaoPlenariaViewSet,\ AutoresProvaveisListView, AutoresPossiveisListView, AutorListView,\ ModelChoiceView -from sapl.api.views import SaplSetViews +from sapl.api.views import SaplApiViewSetConstrutor from .apps import AppConfig @@ -21,9 +21,10 @@ router.register(r'materia$', MateriaLegislativaViewSet) router.register(r'sessao-plenaria', SessaoPlenariaViewSet) -for app, built_sets in SaplSetViews.items(): +for app, built_sets in SaplApiViewSetConstrutor._built_sets.items(): for view_prefix, viewset in built_sets.items(): - router.register(app + '/' + view_prefix, viewset) + router.register(app.label + '/' + + view_prefix._meta.model_name, viewset) urlpatterns_router = router.urls diff --git a/sapl/api/views.py b/sapl/api/views.py index 5d2ca37eb..1cfdd1d44 100644 --- a/sapl/api/views.py +++ b/sapl/api/views.py @@ -22,8 +22,12 @@ from sapl.api.forms import SaplFilterSetMixin from sapl.api.permissions import SaplModelPermissions from sapl.api.serializers import ChoiceSerializer from sapl.base.models import Autor, AppConfig, DOC_ADM_OSTENSIVO -from sapl.materia.models import Proposicao, TipoMateriaLegislativa +from sapl.materia.models import Proposicao, TipoMateriaLegislativa,\ + MateriaLegislativa, Tramitacao from sapl.parlamentares.models import Parlamentar +from sapl.protocoloadm.models import DocumentoAdministrativo,\ + DocumentoAcessorioAdministrativo, TramitacaoAdministrativo +from sapl.sessao.models import SessaoPlenaria from sapl.utils import models_with_gr_for_model, choice_anos_com_sessaoplenaria @@ -38,10 +42,18 @@ class BusinessRulesNotImplementedMixin: raise Exception(_("DELETE Delete não implementado")) -class SaplApiViewSetConstrutor(ModelViewSet): - +class SaplApiViewSet(ModelViewSet): filter_backends = (DjangoFilterBackend,) + +class SaplApiViewSetConstrutor(): + + _built_sets = {} + + @classonlymethod + def get_class_for_model(cls, model): + return cls._built_sets[model._meta.app_config][model] + @classonlymethod def build_class(cls): import inspect @@ -92,7 +104,7 @@ class SaplApiViewSetConstrutor(ModelViewSet): model = _model # Define uma classe padrão ModelViewSet de DRF - class ModelSaplViewSet(cls): + class ModelSaplViewSet(SaplApiViewSet): queryset = _model.objects.all() # Utiliza o filtro customizado pela classe @@ -116,12 +128,12 @@ class SaplApiViewSetConstrutor(ModelViewSet): apps_sapl = [apps.apps.get_app_config( n[5:]) for n in settings.SAPL_APPS] for app in apps_sapl: - built_sets[app.label] = {} + cls._built_sets[app] = {} for model in app.get_models(): - built_sets[app.label][model._meta.model_name] = build(model) + cls._built_sets[app][model] = build(model) - return built_sets +SaplApiViewSetConstrutor.build_class() """ 1. Constroi uma rest_framework.viewsets.ModelViewSet para @@ -184,15 +196,39 @@ class SaplApiViewSetConstrutor(ModelViewSet): } """ -SaplSetViews = SaplApiViewSetConstrutor.build_class() - # Toda Classe construida acima, pode ser redefinida e aplicado quaisquer # das possibilidades para uma classe normal criada a partir de # rest_framework.viewsets.ModelViewSet conforme exemplo para a classe autor +# decorator para recuperar e transformar o default + + +class customize(object): + def __init__(self, model): + self.model = model + + def __call__(self, cls): + + class _SaplApiViewSet( + cls, + SaplApiViewSetConstrutor._built_sets[ + self.model._meta.app_config][self.model] + ): + pass + + if hasattr(_SaplApiViewSet, 'build'): + _SaplApiViewSet = _SaplApiViewSet.build() + + SaplApiViewSetConstrutor._built_sets[ + self.model._meta.app_config][self.model] = _SaplApiViewSet + return _SaplApiViewSet + # Customização para AutorViewSet com implementação de actions específicas -class _AutorViewSet(SaplSetViews['base']['autor']): + + +@customize(Autor) +class _AutorViewSet: """ Neste exemplo de customização do que foi criado em SaplApiViewSetConstrutor além do ofertado por @@ -237,7 +273,7 @@ class _AutorViewSet(SaplSetViews['base']['autor']): return Response(serializer.data) @classonlymethod - def build_class_with_actions(cls): + def build(cls): models_with_gr_for_autor = models_with_gr_for_model(Autor) @@ -260,7 +296,8 @@ class _AutorViewSet(SaplSetViews['base']['autor']): return cls -class _ParlamentarViewSet(SaplSetViews['parlamentares']['parlamentar']): +@customize(Parlamentar) +class _ParlamentarViewSet: @action(detail=True) def proposicoes(self, request, *args, **kwargs): """ @@ -285,15 +322,16 @@ class _ParlamentarViewSet(SaplSetViews['parlamentares']['parlamentar']): page = self.paginate_queryset(qs) if page is not None: - serializer = SaplSetViews[ - 'materia']['proposicao'].serializer_class(page, many=True) + serializer = SaplApiViewSetConstrutor.get_class_for_model( + Proposicao).serializer_class(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(page, many=True) return Response(serializer.data) -class _ProposicaoViewSet(SaplSetViews['materia']['proposicao']): +@customize(Proposicao) +class _ProposicaoViewSet(): """ list: Retorna lista de Proposições @@ -346,7 +384,8 @@ class _ProposicaoViewSet(SaplSetViews['materia']['proposicao']): return qs -class _MateriaLegislativaViewSet(SaplSetViews['materia']['materialegislativa']): +@customize(MateriaLegislativa) +class _MateriaLegislativaViewSet: @action(detail=True, methods=['GET']) def ultima_tramitacao(self, request, *args, **kwargs): @@ -357,13 +396,14 @@ class _MateriaLegislativaViewSet(SaplSetViews['materia']['materialegislativa']): ultima_tramitacao = materia.tramitacao_set.last() - serializer_class = SaplSetViews[ - 'materia']['tramitacao'].serializer_class(ultima_tramitacao) + serializer_class = SaplApiViewSetConstrutor.get_class_for_model( + Tramitacao).serializer_class(ultima_tramitacao) return Response(serializer_class.data) -class _TipoMateriaLegislativaViewSet(SaplSetViews['materia']['tipomaterialegislativa']): +@customize(TipoMateriaLegislativa) +class _TipoMateriaLegislativaViewSet: @action(detail=True, methods=['POST']) def change_position(self, request, *args, **kwargs): @@ -380,7 +420,8 @@ class _TipoMateriaLegislativaViewSet(SaplSetViews['materia']['tipomaterialegisla return Response(result) -class _DocumentoAdministrativoViewSet(SaplSetViews['protocoloadm']['documentoadministrativo']): +@customize(DocumentoAdministrativo) +class _DocumentoAdministrativoViewSet: class DocumentoAdministrativoPermission(SaplModelPermissions): def has_permission(self, request, view): @@ -414,8 +455,8 @@ class _DocumentoAdministrativoViewSet(SaplSetViews['protocoloadm']['documentoadm return qs -class _DocumentoAcessorioAdministrativoViewSet( - SaplSetViews['protocoloadm']['documentoacessorioadministrativo']): +@customize(DocumentoAcessorioAdministrativo) +class _DocumentoAcessorioAdministrativoViewSet: permission_classes = ( _DocumentoAdministrativoViewSet.DocumentoAdministrativoPermission, ) @@ -428,9 +469,8 @@ class _DocumentoAcessorioAdministrativoViewSet( return qs -class _TramitacaoAdministrativoViewSet( - SaplSetViews['protocoloadm']['tramitacaoadministrativo'], - BusinessRulesNotImplementedMixin): +@customize(TramitacaoAdministrativo) +class _TramitacaoAdministrativoViewSet(BusinessRulesNotImplementedMixin): # TODO: Implementar regras de manutenção das tramitações de docs adms permission_classes = ( @@ -444,8 +484,8 @@ class _TramitacaoAdministrativoViewSet( return qs -class _SessaoPlenariaViewSet( - SaplSetViews['sessao']['sessaoplenaria']): +@customize(SessaoPlenaria) +class _SessaoPlenariaViewSet: @action(detail=False) def years(self, request, *args, **kwargs): @@ -453,19 +493,3 @@ class _SessaoPlenariaViewSet( serializer = ChoiceSerializer(years, many=True) return Response(serializer.data) - - -SaplSetViews['base']['autor'] = _AutorViewSet.build_class_with_actions() - - -SaplSetViews['materia']['materialegislativa'] = _MateriaLegislativaViewSet -SaplSetViews['materia']['proposicao'] = _ProposicaoViewSet -SaplSetViews['materia']['tipomaterialegislativa'] = _TipoMateriaLegislativaViewSet - -SaplSetViews['parlamentares']['parlamentar'] = _ParlamentarViewSet - -SaplSetViews['protocoloadm']['documentoadministrativo'] = _DocumentoAdministrativoViewSet -SaplSetViews['protocoloadm']['documentoacessorioadministrativo'] = _DocumentoAcessorioAdministrativoViewSet -SaplSetViews['protocoloadm']['tramitacaoadministrativo'] = _TramitacaoAdministrativoViewSet - -SaplSetViews['sessao']['sessaoplenaria'] = _SessaoPlenariaViewSet