From 149efb1eb06fde716cd555ec4ea67e3aa0cf4552 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 20 Jul 2018 19:39:26 -0300 Subject: [PATCH 01/45] =?UTF-8?q?Mostra=20na=20tela=20de=20detalhe=20da=20?= =?UTF-8?q?mat=C3=A9ria=20o=20bot=C3=A3o=20de=20acompanhar=20mat=C3=A9ria?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/templates/materia/materialegislativa_detail.html | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 sapl/templates/materia/materialegislativa_detail.html diff --git a/sapl/templates/materia/materialegislativa_detail.html b/sapl/templates/materia/materialegislativa_detail.html new file mode 100644 index 000000000..607ed049c --- /dev/null +++ b/sapl/templates/materia/materialegislativa_detail.html @@ -0,0 +1,10 @@ +{% extends "crud/detail.html" %} +{% load i18n %} +{% block sub_actions %} + {{ block.super }} + {% if object.em_tramitacao %} +
+ Acompanhar Matéria +
+ {% endif %} +{% endblock sub_actions %} From 00f50cdca5cb1fcdfbe508cbfc1e40e97456b0e2 Mon Sep 17 00:00:00 2001 From: Eliseu Egewarth Date: Fri, 27 Jul 2018 11:29:20 -0300 Subject: [PATCH 02/45] 127 redirecionar urls (#2089) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #127 Adicionando urls para composicao de comissão Signed-off-by: Eliseu Egewarth * #127 Adicionando url para consultas/materia Signed-off-by: Eliseu Egewarth * Fix #127 Ignorando app redireciona_urls em test_urls.py Signed-off-by: Eliseu Egewarth --- sapl/redireciona_urls/urls.py | 19 ++++++++++--- sapl/redireciona_urls/views.py | 49 ++++++++++++++++++++++++++++++++-- sapl/test_urls.py | 41 +++++++++++++++------------- 3 files changed, 84 insertions(+), 25 deletions(-) diff --git a/sapl/redireciona_urls/urls.py b/sapl/redireciona_urls/urls.py index 63afd8b6b..687ca7fd4 100644 --- a/sapl/redireciona_urls/urls.py +++ b/sapl/redireciona_urls/urls.py @@ -2,20 +2,22 @@ from django.conf.urls import url from .apps import AppConfig from .views import (RedirecionaAtasList, RedirecionaComissao, + RedirecionaComposicaoComissao, RedirecionaHistoricoTramitacoesList, RedirecionaMateriaLegislativaDetail, RedirecionaMateriaLegislativaList, RedirecionaMateriasPorAnoAutorTipo, RedirecionaMateriasPorAutor, RedirecionaMesaDiretoraView, RedirecionaNormasJuridicasDetail, - RedirecionaNormasJuridicasList, RedirecionaParlamentar, - RedirecionaPautaSessao, RedirecionaPresencaParlamentares, + RedirecionaNormasJuridicasList, + RedirecionaNormasJuridicasTextoIntegral, + RedirecionaParlamentar, RedirecionaPautaSessao, + RedirecionaPresencaParlamentares, RedirecionaRelatoriosList, RedirecionaRelatoriosMateriasEmTramitacaoList, RedirecionaSAPLIndex, RedirecionaSessaoPlenaria) app_name = AppConfig.name - urlpatterns = [ url(r'^default_index_html$', RedirecionaSAPLIndex.as_view(), @@ -26,6 +28,9 @@ urlpatterns = [ url(r'^consultas/comissao/comissao_', RedirecionaComissao.as_view(), name='redireciona_comissao'), + url(r'^consultas/comissao/composicao/composicao_index_html', + RedirecionaComposicaoComissao.as_view(), + name='redireciona_composicaio_comissao'), url(r'^consultas/pauta_sessao/pauta_sessao_', RedirecionaPautaSessao.as_view(), name='redireciona_pauta_sessao_'), @@ -44,6 +49,9 @@ urlpatterns = [ url(r'^consultas/norma_juridica/norma_juridica_mostrar_proc', RedirecionaNormasJuridicasDetail.as_view(), name='redireciona_norma_juridica_detail'), + url(r'^sapl_documentos/normajuridica/(?P[0-9]+)_texto_integral', + RedirecionaNormasJuridicasTextoIntegral.as_view(), + name='redireciona_norma_juridica_texto_integral'), url(r'^relatorios_administrativos/relatorios_administrativos_index_html$', RedirecionaRelatoriosList.as_view(), name='redireciona_relatorios_list'), @@ -51,6 +59,9 @@ urlpatterns = [ RedirecionaRelatoriosMateriasEmTramitacaoList.as_view(), name='redireciona_relatorio_materia_por_tramitacao'), url(r'tramitacaoMaterias/materia_mostrar_proc$', + RedirecionaMateriaLegislativaDetail.as_view(), + name='redireciona_materialegislativa_detail_tramitacao'), + url(r'consultas/materia/materia_mostrar_proc$', RedirecionaMateriaLegislativaDetail.as_view(), name='redireciona_materialegislativa_detail'), url(r'^generico/materia_pesquisar_', @@ -71,4 +82,4 @@ urlpatterns = [ url(r'propositurasAnoAutorTipo', RedirecionaMateriasPorAnoAutorTipo.as_view(), name='redireciona_materia_por_ano_autor_tipo_list'), -] +] \ No newline at end of file diff --git a/sapl/redireciona_urls/views.py b/sapl/redireciona_urls/views.py index 369ff7518..82f6f44ea 100644 --- a/sapl/redireciona_urls/views.py +++ b/sapl/redireciona_urls/views.py @@ -1,14 +1,14 @@ from django.core.urlresolvers import NoReverseMatch, reverse from django.views.generic import RedirectView +from sapl.audiencia.apps import AppConfig as audienciaConfig from sapl.base.apps import AppConfig as atasConfig from sapl.comissoes.apps import AppConfig as comissoesConfig from sapl.materia.apps import AppConfig as materiaConfig from sapl.norma.apps import AppConfig as normaConfig +from sapl.norma.models import NormaJuridica from sapl.parlamentares.apps import AppConfig as parlamentaresConfig from sapl.sessao.apps import AppConfig as sessaoConfig -from sapl.audiencia.apps import AppConfig as audienciaConfig - from .exceptions import UnknownUrlNameError EMPTY_STRING = '' @@ -142,6 +142,33 @@ class RedirecionaComissao(RedirectView): return url +class RedirecionaComposicaoComissao(RedirectView): + permanent = True + + def get_redirect_url(self): + url = EMPTY_STRING + pk_composicao = self.request.GET.get( + 'cod_periodo_comp_sel', EMPTY_STRING) + pk_comissao = self.request.GET.get('cod_comissao', EMPTY_STRING) + + if pk_comissao: + kwargs = {'pk': pk_comissao} + + try: + url = reverse(comissao_detail, kwargs=kwargs) + except NoReverseMatch: + raise UnknownUrlNameError(comissao_detail) + else: + try: + url = reverse(comissao_list) + except NoReverseMatch: + raise UnknownUrlNameError(comissao_list) + + url = has_iframe(url, self.request) + + return url + + class RedirecionaPautaSessao(RedirectView): permanent = True @@ -418,6 +445,24 @@ class RedirecionaNormasJuridicasDetail(RedirectView): return url +class RedirecionaNormasJuridicasTextoIntegral(RedirectView): + permanent = False + + def get_redirect_url(self, **kwargs): + # import ipdb;ipdb.set_trace() + url = EMPTY_STRING + try: + norma = NormaJuridica.objects.get(pk=kwargs['norma_id']) + if norma: + url = norma.texto_integral.url + except Exception as e: + raise e + + url = has_iframe(url, self.request) + + return url + + class RedirecionaNormasJuridicasList(RedirectView): permanent = True diff --git a/sapl/test_urls.py b/sapl/test_urls.py index 0f1671c98..851b1995b 100644 --- a/sapl/test_urls.py +++ b/sapl/test_urls.py @@ -278,25 +278,28 @@ def test_urlpatterns(url_item, admin_client): """ % (app_name, url) app_name = app_name[5:] - - assert app_name in apps_url_patterns_prefixs_and_users, """ - A app (%s) da url (%s) não consta na lista de prefixos do teste - """ % (app_name, url) - - if app_name in apps_url_patterns_prefixs_and_users: - prefixs = apps_url_patterns_prefixs_and_users[app_name]['prefixs'] - - isvalid = False - for prefix in prefixs: - if url.startswith(prefix): - isvalid = True - break - - assert isvalid, """ - O prefixo da url (%s) não está no padrão de sua app (%s). - Os prefixos permitidos são: - %s - """ % (url, app_name, prefixs) + if app_name != 'redireciona_urls': + assert app_name in apps_url_patterns_prefixs_and_users, """ + A app (%s) da url (%s) não consta na lista de prefixos do teste + """ % (app_name, url) + + if app_name in apps_url_patterns_prefixs_and_users: + prefixs = apps_url_patterns_prefixs_and_users[app_name]['prefixs'] + + isvalid = False + for prefix in prefixs: + if url.startswith(prefix): + isvalid = True + break + + assert isvalid, """ + O prefixo da url (%s) não está no padrão de sua app (%s). + Os prefixos permitidos são: + %s + """ % (url, app_name, prefixs) + else: + # ignorando app de redirecionamento de urls no padrão do SAPL 2.5 + pass urls_publicas_excecoes = { From a5ec0337c9077d7c96c1dd385ae81243dba140cf Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Fri, 27 Jul 2018 11:57:42 -0300 Subject: [PATCH 03/45] Release: 3.1.103 --- 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 fa0abdd5d..fa4589927 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.102 + image: interlegis/sapl:3.1.103 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 758b57fc8..17ccd1b1f 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.102', + version='3.1.103', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 234be7e5cd8743e55b44ee8b809aff131d68ee93 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 30 Jul 2018 16:39:50 -0300 Subject: [PATCH 04/45] =?UTF-8?q?HOT-FIX:=20desabilita=20indexa=C3=A7?= =?UTF-8?q?=C3=A3o=20textual=20(vide=20issue=202055)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/settings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sapl/settings.py b/sapl/settings.py index 72cf086cc..7dad6da2b 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -94,7 +94,10 @@ INSTALLED_APPS = ( ) + SAPL_APPS # FTS = Full Text Search -HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' +# Desabilita a indexação textual até encontramos uma solução para a issue +# https://github.com/interlegis/sapl/issues/2055 +#HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' +HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.BaseSignalProcessor' SEARCH_BACKEND = 'haystack.backends.whoosh_backend.WhooshEngine' SEARCH_URL = ('PATH', PROJECT_DIR.child('whoosh')) From b6857c4892f4c34b07eda8417073694c2ab61d44 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Mon, 30 Jul 2018 18:44:59 -0100 Subject: [PATCH 05/45] =?UTF-8?q?Hot-Fix:=20Refatora=C3=A7=C3=A3o=20votant?= =?UTF-8?q?e=5Fview=20#2068=20(#2086)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Hot-Fix: Refatoraçao votante_view * update --- sapl/painel/views.py | 212 +++++++++++++++++++++++-------------------- 1 file changed, 116 insertions(+), 96 deletions(-) diff --git a/sapl/painel/views.py b/sapl/painel/views.py index 847518898..88d0aa785 100644 --- a/sapl/painel/views.py +++ b/sapl/painel/views.py @@ -82,10 +82,114 @@ def votacao_aberta(request): return votacoes_abertas.first(), None +def votacao(context,context_vars): + + parlamentar = context_vars['votante'].parlamentar + parlamentar_presente = False + if parlamentar.id in context_vars['presentes']: + parlamentar_presente = True + context_vars.update({'parlamentar': parlamentar}) + else: + context.update({'error_message': + 'Não há presentes na Sessão com a ' + 'matéria em votação.'}) + + if parlamentar_presente: + voto = [] + if context_vars['ordem_dia']: + voto = VotoParlamentar.objects.filter( + ordem=context_vars['ordem_dia']) + elif context_vars['expediente']: + voto = VotoParlamentar.objects.filter( + expediente=context_vars['expediente']) + + if voto: + try: + voto = voto.get(parlamentar=context_vars['parlamentar']) + context.update({'voto_parlamentar': voto.voto}) + except ObjectDoesNotExist: + context.update( + {'voto_parlamentar': 'Voto não ' + 'computado.'}) + else: + context.update({'error_message': + 'Você não está presente na ' + 'Ordem do Dia/Expediente em votação.'}) + return context, context_vars + +def sessao_votacao(context,context_vars): + pk = context_vars['sessao'].pk + context.update({'sessao_id': pk}) + context.update({'sessao': context_vars['sessao'], + 'data': context_vars['sessao'].data_inicio, + 'hora': context_vars['sessao'].hora_inicio}) + + # Inicializa presentes + presentes = [] + ordem_dia = get_materia_aberta(pk) + expediente = get_materia_expediente_aberta(pk) + errors_msgs = {'materia':'Não há nenhuma matéria aberta.', + 'registro':'A votação para esta matéria já encerrou.', + 'tipo':'A matéria aberta não é do tipo votação nominal.'} + + materia_aberta = None + if ordem_dia: + materia_aberta = ordem_dia + presentes = PresencaOrdemDia.objects.filter( + sessao_plenaria_id=pk).values_list( + 'parlamentar_id', flat=True).distinct() + elif expediente: + materia_aberta = expediente + presentes = SessaoPlenariaPresenca.objects.filter( + sessao_plenaria_id=pk).values_list( + 'parlamentar_id', flat=True).distinct() + + context_vars.update({'ordem_dia': ordem_dia, + 'expediente':expediente, + 'presentes': presentes}) + + # Verifica votação aberta + # Se aberta, verifica se é nominal. ID nominal == 2 + erro = None + if not materia_aberta: + erro = 'materia' + elif materia_aberta.registro_aberto: + erro = 'registro' + elif materia_aberta.tipo_votacao != VOTACAO_NOMINAL: + erro = 'tipo' + + if not erro: + context.update({'materia': materia_aberta.materia, + 'ementa': materia_aberta.materia.ementa}) + context, context_vars = votacao(context, context_vars) + else: + context.update({'error_message': errors_msgs[erro]}) + + return context, context_vars + + +def can_vote(context, context_vars, request): + context.update({'permissao': True}) + + # Pega sessão + sessao, msg = votacao_aberta(request) + context_vars.update({'sessao':sessao}) + if sessao and not msg: + context, context_vars = sessao_votacao(context, context_vars) + elif not sessao and msg: + return HttpResponseRedirect('/') + else: + context.update( + {'error_message': 'Não há nenhuma sessão com matéria aberta.'}) + return context, context_vars + + def votante_view(request): # Pega o votante relacionado ao usuário template_name = 'painel/voto_nominal.html' context = {} + context_vars = {} + try: votante = Votante.objects.get(user=request.user) except ObjectDoesNotExist: @@ -95,96 +199,12 @@ def votante_view(request): }) return render(request, template_name, context) - + context_vars = {'votante': votante} context = {'head_title': str(_('Votação Individual'))} # Verifica se usuário possui permissão para votar if 'parlamentares.can_vote' in request.user.get_all_permissions(): - context.update({'permissao': True}) - - # Pega sessão - sessao, msg = votacao_aberta(request) - - if sessao and not msg: - pk = sessao.pk - context.update({'sessao_id': pk}) - context.update({'sessao': sessao, - 'data': sessao.data_inicio, - 'hora': sessao.hora_inicio}) - - # Inicializa presentes - presentes = [] - - # Verifica votação aberta - # Se aberta, verifica se é nominal. ID nominal == 2 - ordem_dia = get_materia_aberta(pk) - expediente = get_materia_expediente_aberta(pk) - - materia_aberta = None - if ordem_dia: - materia_aberta = ordem_dia - presentes = PresencaOrdemDia.objects.filter( - sessao_plenaria_id=pk).values_list( - 'parlamentar_id', flat=True).distinct() - elif expediente: - materia_aberta = expediente - presentes = SessaoPlenariaPresenca.objects.filter( - sessao_plenaria_id=pk).values_list( - 'parlamentar_id', flat=True).distinct() - - if materia_aberta: - if not materia_aberta.registro_aberto: - if materia_aberta.tipo_votacao == VOTACAO_NOMINAL: - context.update({'materia': materia_aberta.materia, - 'ementa': materia_aberta.materia.ementa}) - - parlamentar = votante.parlamentar - parlamentar_presente = False - if parlamentar.id in presentes: - parlamentar_presente = True - else: - context.update({'error_message': - 'Não há presentes na Sessão com a ' - 'matéria em votação.'}) - - if parlamentar_presente: - voto = [] - if ordem_dia: - voto = VotoParlamentar.objects.filter( - ordem=ordem_dia) - elif expediente: - voto = VotoParlamentar.objects.filter( - expediente=expediente) - - if voto: - try: - voto = voto.get(parlamentar=parlamentar) - context.update({'voto_parlamentar': voto.voto}) - except ObjectDoesNotExist: - context.update( - {'voto_parlamentar': 'Voto não ' - 'computado.'}) - else: - context.update({'error_message': - 'Você não está presente na ' - 'Ordem do Dia/Expediente em votação.'}) - else: - context.update( - {'error_message': 'A matéria aberta não é do tipo ' - 'votação nominal.'}) - else: - context.update( - {'error_message': 'A votação para esta matéria já encerrou.'}) - else: - context.update( - {'error_message': 'Não há nenhuma matéria aberta.'}) - - elif not sessao and msg: - return HttpResponseRedirect('/') - - else: - context.update( - {'error_message': 'Não há nenhuma sessão com matéria aberta.'}) + context, context_vars = can_vote(context, context_vars, request) else: context.update({'permissao': False, @@ -192,36 +212,36 @@ def votante_view(request): # Salva o voto if request.method == 'POST': - if ordem_dia: + if context_vars['ordem_dia']: try: voto = VotoParlamentar.objects.get( - parlamentar=parlamentar, - ordem=ordem_dia) + parlamentar=context_vars['parlamentar'], + ordem=context_vars['ordem_dia']) except ObjectDoesNotExist: voto = VotoParlamentar.objects.create( - parlamentar=parlamentar, + parlamentar=context_vars['parlamentar'], voto=request.POST['voto'], user=request.user, ip=get_client_ip(request), - ordem=ordem_dia) + ordem=context_vars['ordem_dia']) else: voto.voto = request.POST['voto'] voto.ip = get_client_ip(request) voto.user = request.user voto.save() - elif expediente: + elif context_vars['expediente']: try: voto = VotoParlamentar.objects.get( - parlamentar=parlamentar, - expediente=expediente) + parlamentar=context_vars['parlamentar'], + expediente=context_vars['expediente']) except ObjectDoesNotExist: voto = VotoParlamentar.objects.create( - parlamentar=parlamentar, + parlamentar=context_vars['parlamentar'], voto=request.POST['voto'], user=request.user, ip=get_client_ip(request), - expediente=expediente) + expediente=context_vars['expediente']) else: voto.voto = request.POST['voto'] voto.ip = get_client_ip(request) From 7d3ce7b265cf2ccd4be57f75a91701efe6af75af Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 30 Jul 2018 17:01:00 -0300 Subject: [PATCH 06/45] Fix #2090 (#2091) * Fix #2090 * HOT-FIX --- sapl/norma/views.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sapl/norma/views.py b/sapl/norma/views.py index 9c98e783e..b364e95bd 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -1,4 +1,5 @@ +import re import weasyprint from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import ObjectDoesNotExist @@ -201,14 +202,12 @@ def recuperar_norma(request): def recuperar_numero_norma(request): tipo = TipoNormaJuridica.objects.get(pk=request.GET['tipo']) ano = request.GET.get('ano', '') - param = {'tipo': tipo} param['ano'] = ano if ano else timezone.now().year - norma = NormaJuridica.objects.filter(**param).extra( - {'numero_id': "CAST(numero as INTEGER)"}).order_by( - 'tipo', 'ano','numero_id').values_list('numero', 'ano').last() + norma = NormaJuridica.objects.filter(**param).order_by( + 'tipo', 'ano').values_list('numero', 'ano').last() if norma: - response = JsonResponse({'numero': int(norma[0]) + 1, + response = JsonResponse({'numero': int(re.sub("[^0-9].*", '', norma[0])) + 1, 'ano': norma[1]}) else: response = JsonResponse( From 6d2e85dc62a022f28884b85a020d7e5fffdced3f Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Mon, 30 Jul 2018 17:13:18 -0300 Subject: [PATCH 07/45] =?UTF-8?q?HOT-FIX:=20impede=20m=C3=BAltiplos=20cliq?= =?UTF-8?q?ues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sessao/adicionar_varias_materias_expediente.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sapl/templates/sessao/adicionar_varias_materias_expediente.html b/sapl/templates/sessao/adicionar_varias_materias_expediente.html index 362ba300d..c9c8c5e5d 100644 --- a/sapl/templates/sessao/adicionar_varias_materias_expediente.html +++ b/sapl/templates/sessao/adicionar_varias_materias_expediente.html @@ -94,3 +94,13 @@ {% endif %} {% endblock detail_content %} + +{% block extra_js %} + +{% endblock extra_js%} From cb274d08b1de4f24fca172b6dab74989d4123da1 Mon Sep 17 00:00:00 2001 From: Eliseu Egewarth Date: Tue, 31 Jul 2018 10:43:20 -0300 Subject: [PATCH 08/45] =?UTF-8?q?HOTFIX:=20Adicionando=20'=5F'=20que=20fal?= =?UTF-8?q?tava=20no=20padr=C3=A3o=20de=20url?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Eliseu Egewarth --- sapl/redireciona_urls/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/redireciona_urls/urls.py b/sapl/redireciona_urls/urls.py index 687ca7fd4..f8a9aa685 100644 --- a/sapl/redireciona_urls/urls.py +++ b/sapl/redireciona_urls/urls.py @@ -49,7 +49,7 @@ urlpatterns = [ url(r'^consultas/norma_juridica/norma_juridica_mostrar_proc', RedirecionaNormasJuridicasDetail.as_view(), name='redireciona_norma_juridica_detail'), - url(r'^sapl_documentos/normajuridica/(?P[0-9]+)_texto_integral', + url(r'^sapl_documentos/norma_juridica/(?P[0-9]+)_texto_integral', RedirecionaNormasJuridicasTextoIntegral.as_view(), name='redireciona_norma_juridica_texto_integral'), url(r'^relatorios_administrativos/relatorios_administrativos_index_html$', From 948af4211ba38d319aa9777289d1d30e44eabb82 Mon Sep 17 00:00:00 2001 From: Eliseu Egewarth Date: Tue, 31 Jul 2018 10:46:06 -0300 Subject: [PATCH 09/45] Release: 3.1.104 --- 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 fa4589927..1e779f4a6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.103 + image: interlegis/sapl:3.1.104 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 17ccd1b1f..375964365 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.103', + version='3.1.104', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From d13643812a86d9da9cc71f0819543a92cf2386c1 Mon Sep 17 00:00:00 2001 From: Edward Date: Wed, 1 Aug 2018 17:00:59 -0300 Subject: [PATCH 10/45] Fixes #2097 (#2103) --- .../migrations/0018_auto_20180801_1652.py | 20 +++++++++++++++++++ sapl/base/models.py | 2 +- sapl/comissoes/forms.py | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 sapl/base/migrations/0018_auto_20180801_1652.py diff --git a/sapl/base/migrations/0018_auto_20180801_1652.py b/sapl/base/migrations/0018_auto_20180801_1652.py new file mode 100644 index 000000000..d2f758105 --- /dev/null +++ b/sapl/base/migrations/0018_auto_20180801_1652.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-08-01 19:52 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0017_appconfig_cronometro_consideracoes'), + ] + + operations = [ + migrations.AlterField( + model_name='autor', + name='nome', + field=models.CharField(blank=True, max_length=120, verbose_name='Nome do Autor'), + ), + ] diff --git a/sapl/base/models.py b/sapl/base/models.py index bbc03b6c7..fbfadd835 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -188,7 +188,7 @@ class Autor(models.Model): autor_related = GenericForeignKey('content_type', 'object_id') nome = models.CharField( - max_length=60, blank=True, verbose_name=_('Nome do Autor')) + max_length=120, blank=True, verbose_name=_('Nome do Autor')) cargo = models.CharField(max_length=50, blank=True) diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index db1822e4a..fc81b3510 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -242,7 +242,7 @@ class ComissaoForm(forms.ModelForm): if not self.is_valid(): return self.cleaned_data - if len(self.cleaned_data['nome']) > 50: + if len(self.cleaned_data['nome']) > 100: msg = _('Nome da Comissão deve ter no máximo 50 caracteres.') raise ValidationError(msg) if self.cleaned_data['data_extincao']: From 1c8394bd3f7f9e386cb1fa1e4c0602bdc016579b Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Wed, 1 Aug 2018 17:01:29 -0300 Subject: [PATCH 11/45] Fix #2101 (#2102) --- sapl/audiencia/forms.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sapl/audiencia/forms.py b/sapl/audiencia/forms.py index 3ad74cca9..e09671a04 100644 --- a/sapl/audiencia/forms.py +++ b/sapl/audiencia/forms.py @@ -77,9 +77,11 @@ class AudienciaForm(forms.ModelForm): msg = _('A hora de fim não pode ser anterior a hora de ínicio') raise ValidationError(msg) - return self.cleaned_data + return cleaned_data @transaction.atomic() def save(self, commit=True): - audiencia = super(AudienciaForm, self).save(commit) + audiencia = super(AudienciaForm, self).save(False) + audiencia.materia = self.cleaned_data['materia'] + audiencia.save() return audiencia \ No newline at end of file From 234cc8958c552f680009504f2bf43d6bbdef8aa3 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 2 Aug 2018 14:58:05 -0300 Subject: [PATCH 12/45] Fixes #2092 Signed-off-by: Talitha Pumar --- sapl/base/forms.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index de6b50403..974068b20 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -45,7 +45,7 @@ STATUS_USER_CHOICE = [ def get_roles(): roles = [(g.id, g.name) for g in Group.objects.all().order_by('name') - if g.name != 'Votante' and g.name != 'Autor'] + if g.name != 'Votante'] return roles @@ -62,8 +62,6 @@ class UsuarioCreateForm(ModelForm): user_active = forms.ChoiceField(required=False, choices=YES_NO_CHOICES, label="Usuário ativo?", initial='True') - #ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] - roles = forms.MultipleChoiceField( required=True, widget=forms.CheckboxSelectMultiple(), choices=get_roles) From b1789881d548bed7f108cfd2f53f448510df6b41 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 2 Aug 2018 15:17:06 -0300 Subject: [PATCH 13/45] Fixes #2098 Author: Talitha Pumar --- sapl/materia/forms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 04ee8d0e0..b543fda41 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -675,6 +675,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): widget=forms.HiddenInput()) ementa = django_filters.CharFilter(lookup_expr='icontains') + indexacao = django_filters.CharFilter(lookup_expr='icontains') em_tramitacao = django_filters.ChoiceFilter(required=False, label='Em tramitação', @@ -751,7 +752,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): [('em_tramitacao', 6), ('o', 6)]) row9 = to_row( - [('materiaassunto__assunto', 12)]) + [('materiaassunto__assunto', 6), ('indexacao', 6)]) row10 = to_row( [('ementa', 12)]) From 0459dd387a4d6d71e4dc7b961f62dcdbacb698ce Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 2 Aug 2018 16:21:17 -0300 Subject: [PATCH 14/45] Fixes #2105 Author: Talitha Pumar --- sapl/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/settings.py b/sapl/settings.py index 7dad6da2b..f29011464 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -221,7 +221,7 @@ EMAIL_SEND_USER = config('EMAIL_SEND_USER', cast=str, default='') DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', cast=str, default='') SERVER_EMAIL = config('SERVER_EMAIL', cast=str, default='') -MAX_DOC_UPLOAD_SIZE = 20 * 1024 * 1024 # 20MB +MAX_DOC_UPLOAD_SIZE = 50 * 1024 * 1024 # 50MB MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB # Internationalization From a767cd1545666773e61b58092db39855fe16d537 Mon Sep 17 00:00:00 2001 From: Leandro Roberto da Silva Date: Fri, 3 Aug 2018 14:02:03 -0300 Subject: [PATCH 15/45] Fix #2088 (#2106) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Corrige erro na exclusão de dispositivo base inicial * Fix #2088 --- sapl/compilacao/models.py | 9 +++++- sapl/compilacao/views.py | 67 ++++++++++++++++++++++----------------- sapl/rules/apps.py | 4 +-- 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/sapl/compilacao/models.py b/sapl/compilacao/models.py index f677cf97a..6ffb738b1 100644 --- a/sapl/compilacao/models.py +++ b/sapl/compilacao/models.py @@ -69,8 +69,15 @@ class BaseModel(models.Model): def save(self, force_insert=False, force_update=False, using=None, update_fields=None, clean=True): - if clean: + # método clean não pode ser chamado no caso do save que está sendo + # executado é o save de revision_pre_delete_signal + import inspect + funcs = list(filter(lambda x: x == 'revision_pre_delete_signal', + map(lambda x: x[3], inspect.stack()))) + + if clean and not funcs: self.clean() + return models.Model.save( self, force_insert=force_insert, diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index a68c456a1..0efa36be0 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -15,7 +15,7 @@ from django.db import connection, transaction from django.db.models import Q from django.db.utils import IntegrityError from django.http.response import (HttpResponse, HttpResponseRedirect, - JsonResponse) + JsonResponse, Http404) from django.shortcuts import get_object_or_404, redirect from django.utils.dateparse import parse_date from django.utils.encoding import force_text @@ -51,7 +51,6 @@ from sapl.compilacao.utils import (DISPOSITIVO_SELECT_RELATED, from sapl.crud.base import Crud, CrudAux, CrudListView, make_pagination from sapl.settings import BASE_DIR - TipoNotaCrud = CrudAux.build(TipoNota, 'tipo_nota') TipoVideCrud = CrudAux.build(TipoVide, 'tipo_vide') TipoPublicacaoCrud = CrudAux.build(TipoPublicacao, 'tipo_publicacao') @@ -104,7 +103,7 @@ class IntegracaoTaView(TemplateView): ) % self.model._meta.verbose_name_plural) return redirect('/') - def get(self, request, *args, **kwargs): + def get(self, request, *args, **kwargs): try: if settings.DEBUG or not TipoDispositivo.objects.exists(): @@ -211,8 +210,12 @@ class CompMixin(PermissionRequiredMixin): @property def ta(self): - ta = TextoArticulado.objects.get( - pk=self.kwargs.get('ta_id', self.kwargs.get('pk', 0))) + try: + ta = TextoArticulado.objects.get( + pk=self.kwargs.get('ta_id', self.kwargs.get('pk', 0))) + except TextoArticulado.DoesNotExist: + raise Http404() + return ta def get_context_data(self, **kwargs): @@ -1237,9 +1240,9 @@ class TextEditView(CompMixin, TemplateView): 'filhos': [], 'alts': [], 'pai': None, - 'st': None, # dispositivo substituido - 'sq': None, # dispositivo subsequente - 'da': None, # dispositivo atualizador + 'st': None, # dispositivo substituido + 'sq': None, # dispositivo subsequente + 'da': None, # dispositivo atualizador 'td': tds[d.tipo_dispositivo_id], # tipo do dispositivo 'na': self.nota_alteracao(d, lista_ta_publicado)\ if d.ta_id == ta_id else None @@ -1480,30 +1483,36 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin): ).first() data = {} - if base_anterior: - data = self.get_json_for_refresh(base_anterior) - else: + if not base_anterior or base == base.get_raiz(): base_anterior = base.get_nivel_zero_anterior() - data = self.get_json_for_refresh(base_anterior) - - data['pai'] = [base.get_raiz().pk] + if not base_anterior: + base_anterior = base + data = self.get_json_for_refresh(base_anterior) + + if base == base_anterior: + data['pk'] = base.pk + self.set_message(data, 'danger', _( + 'Base Inicial não pode ser removida!'), modal=True) + else: + if base != base.get_raiz(): + data['pai'] = [base.get_raiz().pk] - if ta_base.id != int(self.kwargs['ta_id']): - data['pai'] = [base.dispositivo_atualizador.pk] - data['pk'] = base.dispositivo_atualizador.pk + if ta_base.id != int(self.kwargs['ta_id']): + data['pai'] = [base.dispositivo_atualizador.pk] + data['pk'] = base.dispositivo_atualizador.pk - try: - with transaction.atomic(): - message = str(self.remover_dispositivo(base, bloco)) - if message: - self.set_message(data, 'warning', message, modal=True) - else: - self.set_message(data, 'success', _( - 'Exclusão efetuada com sucesso!'), modal=True) - ta_base.reagrupar_ordem_de_dispositivos() - except Exception as e: - data['pk'] = self.kwargs['dispositivo_id'] - self.set_message(data, 'danger', str(e), modal=True) + try: + with transaction.atomic(): + message = str(self.remover_dispositivo(base, bloco)) + if message: + self.set_message(data, 'warning', message, modal=True) + else: + self.set_message(data, 'success', _( + 'Exclusão efetuada com sucesso!'), modal=True) + ta_base.reagrupar_ordem_de_dispositivos() + except Exception as e: + data['pk'] = self.kwargs['dispositivo_id'] + self.set_message(data, 'danger', str(e), modal=True) return data diff --git a/sapl/rules/apps.py b/sapl/rules/apps.py index 606190110..dbdfce8ce 100644 --- a/sapl/rules/apps.py +++ b/sapl/rules/apps.py @@ -1,15 +1,15 @@ from builtins import LookupError import django -import reversion from django.apps import apps from django.contrib.auth import get_user_model from django.contrib.auth.management import _get_all_permissions from django.core import exceptions from django.db import models, router from django.db.utils import DEFAULT_DB_ALIAS -from django.utils.translation import ugettext_lazy as _ from django.utils.translation import string_concat +from django.utils.translation import ugettext_lazy as _ +import reversion from sapl.rules import (SAPL_GROUP_ADMINISTRATIVO, SAPL_GROUP_COMISSOES, SAPL_GROUP_GERAL, SAPL_GROUP_MATERIA, SAPL_GROUP_NORMA, From 30571d0b42ab29fe09b42455f6ce6d8d0b8de2af Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Mon, 6 Aug 2018 14:39:31 -0300 Subject: [PATCH 16/45] Fix #2104 (#2110) Co-authored-by: Edward Ribeiro --- sapl/norma/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/norma/views.py b/sapl/norma/views.py index b364e95bd..f5fecdefc 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -72,7 +72,7 @@ class NormaPesquisaView(FilterView): def get_queryset(self): qs = super().get_queryset() - qs.select_related('tipo', 'materia') + qs = qs.extra({'norma_i': "CAST(regexp_replace(numero,'[^0-9]','', 'g') AS INTEGER)", 'norma_letra': "regexp_replace(numero,'[^a-zA-Z]','', 'g')"}).order_by('-data', '-norma_i', '-norma_letra') return qs From e67e00a13b2fc446f572b73e970bc7a81944926e Mon Sep 17 00:00:00 2001 From: Edward Date: Mon, 6 Aug 2018 16:58:21 -0300 Subject: [PATCH 17/45] Fixes #2108 (#2111) --- sapl/protocoloadm/views.py | 18 ++++++++++-------- .../documentoadministrativo_filter.html | 8 +++++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 3350c81cf..67d43fe51 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -550,9 +550,16 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin, qs = self.get_queryset() + qs = qs.prefetch_related("documentoacessorioadministrativo_set", + "tramitacaoadministrativo_set", + "tipo", + "tramitacaoadministrativo_set__status", + "tramitacaoadministrativo_set__unidade_tramitacao_local", + "tramitacaoadministrativo_set__unidade_tramitacao_destino") + if status_tramitacao and unidade_destino: lista = filtra_tramitacao_adm_destino_and_status(status_tramitacao, - unidade_destino) + unidade_destino) qs = qs.filter(id__in=lista).distinct() elif status_tramitacao: @@ -566,11 +573,6 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin, if 'o' in self.request.GET and not self.request.GET['o']: qs = qs.order_by('-ano', '-numero') - qs = qs.prefetch_related("documentoacessorioadministrativo_set", - "tramitacaoadministrativo_set", - "tramitacaoadministrativo_set__status", - "tramitacaoadministrativo_set__unidade_tramitacao_local", - "tramitacaoadministrativo_set__unidade_tramitacao_destino") kwargs.update({ 'queryset': qs, @@ -607,10 +609,10 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin, self.filterset.form.fields['o'].label = _('Ordenação') + length = self.object_list.count() context = self.get_context_data(filter=self.filterset, - object_list=self.object_list, filter_url=url, - numero_res=len(self.object_list) + numero_res=length ) context['show_results'] = show_results_filter_set( diff --git a/sapl/templates/protocoloadm/documentoadministrativo_filter.html b/sapl/templates/protocoloadm/documentoadministrativo_filter.html index 83eb1bd40..719efcd04 100644 --- a/sapl/templates/protocoloadm/documentoadministrativo_filter.html +++ b/sapl/templates/protocoloadm/documentoadministrativo_filter.html @@ -44,12 +44,14 @@ {% if d.protocolo %} Protocolo: {{ d.protocolo}}
{% endif %} - {% if d.tramitacaoadministrativo_set.last.unidade_tramitacao_destino %} - Localização Atual:  {{d.tramitacaoadministrativo_set.last.unidade_tramitacao_destino}} + {% define d.tramitacaoadministrativo_set.last as tram %} + {% if tram.unidade_tramitacao_destino %} + Localização Atual:  {{tram.unidade_tramitacao_destino}}
- Status: {{d.tramitacaoadministrativo_set.last.status}} + Status: {{tram.status}}
{% endif %} + {% define d.documentoacessorioadministrativo_set.all as acess %} {% if d.documentoacessorioadministrativo_set.all.exists %} Documentos Acessórios: From da53812b567ab0157f68207100d2e416c9aa948d Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 6 Aug 2018 16:58:40 -0300 Subject: [PATCH 18/45] Release: 3.1.105 --- 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 1e779f4a6..e017e886b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.104 + image: interlegis/sapl:3.1.105 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 375964365..0d38c06b6 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.104', + version='3.1.105', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 03dc469cb4f47f03d152fdfb73fd51f1fdb1fcd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Sconetto?= Date: Tue, 7 Aug 2018 15:41:45 -0300 Subject: [PATCH 19/45] Fix #2117 --- sapl/templates/painel/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/templates/painel/index.html b/sapl/templates/painel/index.html index 6e4242df4..d6d5784ea 100644 --- a/sapl/templates/painel/index.html +++ b/sapl/templates/painel/index.html @@ -398,7 +398,7 @@ $("#observacao_materia").text(''); } - if (data['tipo_resultado']){ + if (data['tipo_resultado'] && data['status_painel'] == true){ $("#resultado_votacao").text(data["tipo_resultado"]); $("#resultado_votacao").css("color", "#45919D"); var resultado_votacao_upper = $("#resultado_votacao").text().toUpperCase(); From e1f240afefe13f0da4207d450323924c00e9d290 Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Wed, 8 Aug 2018 13:09:38 -0300 Subject: [PATCH 20/45] Fix #2118 (#2119) --- sapl/templates/painel/index.html | 2 +- sapl/templates/painel/voto_nominal.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/templates/painel/index.html b/sapl/templates/painel/index.html index d6d5784ea..d0336a2f1 100644 --- a/sapl/templates/painel/index.html +++ b/sapl/templates/painel/index.html @@ -135,7 +135,7 @@

Matéria em Votação

- +

diff --git a/sapl/templates/painel/voto_nominal.html b/sapl/templates/painel/voto_nominal.html index fd3ee43fd..a1830a54a 100644 --- a/sapl/templates/painel/voto_nominal.html +++ b/sapl/templates/painel/voto_nominal.html @@ -74,7 +74,7 @@

Matéria em Votação

- +

{{materia}}

{{materia}}

{{ementa}}

From bc77952ed3481990d1dbe0b955587ee00f5c7440 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Wed, 8 Aug 2018 13:11:53 -0300 Subject: [PATCH 21/45] fix #2107 (#2109) * fix #2107 * HOT-FIX: corrige erros no form * HOT-FIX: adequa teste * HOT-FIX: tira possibilidade de charfield ser null --- sapl/audiencia/forms.py | 61 ++++++++++++------- .../migrations/0005_auto_20180806_1236.py | 20 ++++++ .../migrations/0006_auto_20180808_0856.py | 20 ++++++ sapl/audiencia/models.py | 2 +- sapl/audiencia/tests/test_audiencia.py | 6 +- sapl/audiencia/views.py | 4 +- 6 files changed, 84 insertions(+), 29 deletions(-) create mode 100644 sapl/audiencia/migrations/0005_auto_20180806_1236.py create mode 100644 sapl/audiencia/migrations/0006_auto_20180808_0856.py diff --git a/sapl/audiencia/forms.py b/sapl/audiencia/forms.py index e09671a04..9312a237b 100644 --- a/sapl/audiencia/forms.py +++ b/sapl/audiencia/forms.py @@ -16,18 +16,21 @@ class AudienciaForm(forms.ModelForm): tipo_materia = forms.ModelChoiceField( label=_('Tipo Matéria'), - required=True, + required=False, queryset=TipoMateriaLegislativa.objects.all(), empty_label='Selecione', ) numero_materia = forms.CharField( - label='Número Matéria', required=True) + label='Número Matéria', required=False) ano_materia = forms.CharField( label='Ano Matéria', - initial=int(data_atual.year), - required=True) + required=False) + + materia = forms.ModelChoiceField(required=False, + widget=forms.HiddenInput(), + queryset=MateriaLegislativa.objects.all()) class Meta: model = AudienciaPublica @@ -36,7 +39,7 @@ class AudienciaForm(forms.ModelForm): 'observacao', 'audiencia_cancelada', 'url_audio', 'url_video', 'upload_pauta', 'upload_ata', 'upload_anexo', 'tipo_materia', 'numero_materia', - 'ano_materia'] + 'ano_materia', 'materia'] def __init__(self, **kwargs): @@ -59,17 +62,38 @@ class AudienciaForm(forms.ModelForm): if not self.is_valid(): return cleaned_data - try: - materia = MateriaLegislativa.objects.get( - numero=self.cleaned_data['numero_materia'], - ano=self.cleaned_data['ano_materia'], - tipo=self.cleaned_data['tipo_materia']) - except ObjectDoesNotExist: - msg = _('A matéria a ser inclusa não existe no cadastro' - ' de matérias legislativas.') - raise ValidationError(msg) + materia = cleaned_data['numero_materia'] + ano_materia = cleaned_data['ano_materia'] + tipo_materia = cleaned_data['tipo_materia'] + + if materia and ano_materia and tipo_materia: + try: + materia = MateriaLegislativa.objects.get( + numero=materia, + ano=ano_materia, + tipo=tipo_materia) + except ObjectDoesNotExist: + msg = _('A matéria %s nº %s/%s não existe no cadastro' + ' de matérias legislativas.' % (tipo_materia, materia, ano_materia)) + raise ValidationError(msg) + else: + cleaned_data['materia'] = materia + else: - cleaned_data['materia'] = materia + campos = [materia, tipo_materia, ano_materia] + if campos.count(None) + campos.count('') < len(campos): + msg = _('Preencha todos os campos relacionados à Matéria Legislativa') + raise ValidationError(msg) + + if not cleaned_data['numero']: + + ultima_audiencia = AudienciaPublica.objects.all().order_by('numero').last() + if ultima_audiencia: + cleaned_data['numero'] = ultima_audiencia.numero + 1 + else: + cleaned_data['numero'] = 1 + + if self.cleaned_data['hora_inicio'] and self.cleaned_data['hora_fim']: if (self.cleaned_data['hora_fim'] < @@ -78,10 +102,3 @@ class AudienciaForm(forms.ModelForm): raise ValidationError(msg) return cleaned_data - - @transaction.atomic() - def save(self, commit=True): - audiencia = super(AudienciaForm, self).save(False) - audiencia.materia = self.cleaned_data['materia'] - audiencia.save() - return audiencia \ No newline at end of file diff --git a/sapl/audiencia/migrations/0005_auto_20180806_1236.py b/sapl/audiencia/migrations/0005_auto_20180806_1236.py new file mode 100644 index 000000000..9601a233d --- /dev/null +++ b/sapl/audiencia/migrations/0005_auto_20180806_1236.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-08-06 15:36 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('audiencia', '0004_auto_20180305_1006'), + ] + + operations = [ + migrations.AlterField( + model_name='audienciapublica', + name='hora_fim', + field=models.CharField(blank=True, max_length=5, null=True, verbose_name='Horário Fim(hh:mm)'), + ), + ] diff --git a/sapl/audiencia/migrations/0006_auto_20180808_0856.py b/sapl/audiencia/migrations/0006_auto_20180808_0856.py new file mode 100644 index 000000000..3809f66cf --- /dev/null +++ b/sapl/audiencia/migrations/0006_auto_20180808_0856.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-08-08 11:56 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('audiencia', '0005_auto_20180806_1236'), + ] + + operations = [ + migrations.AlterField( + model_name='audienciapublica', + name='hora_fim', + field=models.CharField(blank=True, max_length=5, verbose_name='Horário Fim(hh:mm)'), + ), + ] diff --git a/sapl/audiencia/models.py b/sapl/audiencia/models.py index 96ad8272a..477a442d9 100644 --- a/sapl/audiencia/models.py +++ b/sapl/audiencia/models.py @@ -71,7 +71,7 @@ class AudienciaPublica(models.Model): hora_inicio = models.CharField( max_length=5, verbose_name=_('Horário Início(hh:mm)')) hora_fim = models.CharField( - max_length=5, verbose_name=_('Horário Fim(hh:mm)')) + max_length=5, blank=True, verbose_name=_('Horário Fim(hh:mm)')) observacao = models.TextField( max_length=500, blank=True, verbose_name=_('Observação')) audiencia_cancelada = models.BooleanField( diff --git a/sapl/audiencia/tests/test_audiencia.py b/sapl/audiencia/tests/test_audiencia.py index 710d70dff..f617d426a 100644 --- a/sapl/audiencia/tests/test_audiencia.py +++ b/sapl/audiencia/tests/test_audiencia.py @@ -15,11 +15,7 @@ def test_valida_campos_obrigatorios_audiencia_form(): assert errors['nome'] == [_('Este campo é obrigatório.')] assert errors['tema'] == [_('Este campo é obrigatório.')] assert errors['tipo'] == [_('Este campo é obrigatório.')] - assert errors['tipo_materia'] == [_('Este campo é obrigatório.')] - assert errors['numero_materia'] == [_('Este campo é obrigatório.')] - assert errors['ano_materia'] == [_('Este campo é obrigatório.')] assert errors['data'] == [_('Este campo é obrigatório.')] assert errors['hora_inicio'] == [_('Este campo é obrigatório.')] - assert errors['hora_fim'] == [_('Este campo é obrigatório.')] - assert len(errors) == 9 + assert len(errors) == 5 diff --git a/sapl/audiencia/views.py b/sapl/audiencia/views.py index 2c16b0919..bdfc6993c 100644 --- a/sapl/audiencia/views.py +++ b/sapl/audiencia/views.py @@ -6,15 +6,17 @@ from sapl.crud.base import RP_DETAIL, RP_LIST, Crud from .forms import AudienciaForm from .models import AudienciaPublica + def index(request): return HttpResponse("Audiência Pública") + class AudienciaCrud(Crud): model = AudienciaPublica public = [RP_LIST, RP_DETAIL, ] class BaseMixin(Crud.BaseMixin): - list_field_names = ['materia', 'tipo', 'numero', 'nome', + list_field_names = ['numero', 'nome', 'tipo', 'materia', 'data'] ordering = 'nome', 'numero', 'tipo', 'data' From 9c2eb19762e7031812cf93b4118fa2d19cb2562a Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Wed, 8 Aug 2018 13:13:13 -0300 Subject: [PATCH 22/45] =?UTF-8?q?hotfix=20-=20corrige=20duplica=C3=A7?= =?UTF-8?q?=C3=A3o=20de=20c=C3=B3digo=20(#2114)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/comissoes/views.py | 21 ++++++++----------- sapl/compilacao/models.py | 43 ++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/sapl/comissoes/views.py b/sapl/comissoes/views.py index 78e639168..699127409 100644 --- a/sapl/comissoes/views.py +++ b/sapl/comissoes/views.py @@ -24,18 +24,17 @@ from .models import (CargoComissao, Comissao, Composicao, DocumentoAcessorio, Participacao, Periodo, Reuniao, TipoComissao) -def pegar_url_composicao(pk): +def pegar_url(pk): participacao = Participacao.objects.get(id=pk) - comp_pk = participacao.composicao.pk - url = reverse('sapl.comissoes:composicao_detail', kwargs={'pk': comp_pk}) - return url - - -def pegar_url_reuniao(pk): + if participacao: + comp_pk = participacao.composicao.pk + url = reverse('sapl.comissoes:composicao_detail', kwargs={'pk': comp_pk}) + return url documentoacessorio = DocumentoAcessorio.objects.get(id=pk) - r_pk = documentoacessorio.reuniao.pk - url = reverse('sapl.comissoes:reuniao_detail', kwargs={'pk': r_pk}) - return url + if documentoacessorio: + r_pk = documentoacessorio.reuniao.pk + url = reverse('sapl.comissoes:reuniao_detail', kwargs={'pk': r_pk}) + return url CargoCrud = CrudAux.build(CargoComissao, 'cargo_comissao') @@ -53,8 +52,6 @@ class PeriodoComposicaoCrud(CrudAux): class UpdateView(CrudAux.UpdateView): form_class = PeriodoForm - # class ListView(CrudAux.ListView): - class ParticipacaoCrud(MasterDetailCrud): model = Participacao diff --git a/sapl/compilacao/models.py b/sapl/compilacao/models.py index 6ffb738b1..4d7701529 100644 --- a/sapl/compilacao/models.py +++ b/sapl/compilacao/models.py @@ -1557,25 +1557,30 @@ class Dispositivo(BaseModel, TimestampedMixin): irmao.clean() irmao.save() - def get_proximo_nivel_zero(self): - proxima_articulacao = Dispositivo.objects.order_by('ordem').filter( - ordem__gt=self.ordem, - nivel=0, - ta_id=self.ta_id).first() - return proxima_articulacao - - def get_nivel_zero_anterior(self): - anterior_articulacao = Dispositivo.objects.order_by('ordem').filter( - ordem__lt=self.ordem, - nivel=0, - ta_id=self.ta_id).last() - return anterior_articulacao - - def get_niveis_zero(self): - niveis_zero = Dispositivo.objects.order_by('ordem').filter( - nivel=0, - ta_id=self.ta_id) - return niveis_zero + def get_niveis(self): + ## Próximo nível zero: + proxima_articulacao = Dispositivo.objects.order_by('ordem').filter( + ordem__gt=self.ordem, + nivel=0, + ta_id=self.ta_id).first() + if proxima_articulacao: + return proxima_articulacao + + ## Nível zero anterior: + anterior_articulacao = Dispositivo.objects.order_by('ordem').filter( + ordem__lt=self.ordem, + nivel=0, + ta_id=self.ta_id).last() + if anterior_articulacao: + return anterior_articulacao + + ## Nível zero: + niveis_zero = Dispositivo.objects.order_by('ordem').filter( + nivel=0, + ta_id=self.ta_id) + if niveis_zero: + return niveis_zero + # metodo obsoleto, foi acrescentado o campo auto_inserido no modelo def is_relative_auto_insert__obsoleto(self, perfil_pk=None): From da40234bf508736d66d58a7753a15ac49fac7b9e Mon Sep 17 00:00:00 2001 From: cristian-longhi Date: Fri, 10 Aug 2018 13:20:22 -0300 Subject: [PATCH 23/45] =?UTF-8?q?Ajusta=20agrupamento=20nos=20relat=C3=B3r?= =?UTF-8?q?ios=20'Mat=C3=A9rias=20por=20autor'=20e=20'Mat=C3=A9rias=20em?= =?UTF-8?q?=20tramita=C3=A7=C3=A3o'=20(#2094)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Acerta agrupamento nos relatórios de matéria por autor e em tramitação * Acerta agrupamento nos relatórios de matéria por autor e em tramitação * Ajusta agrupamento nos relatórios 'Matérias por autor' e 'Matérias em tramitação' * Ajusta agrupamento nos relatórios 'Matérias por autor' e 'Matérias em tramitação' --- sapl/base/forms.py | 7 +- sapl/base/views.py | 2 +- .../RelatorioMateriasPorAutor_filter.html | 73 +++++++++---------- 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 974068b20..b71d161da 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -671,6 +671,11 @@ class RelatorioMateriasTramitacaoilterSet(django_filters.FilterSet): label='Ano da Matéria', choices=RANGE_ANOS) + @property + def qs(self): + parent = super(RelatorioMateriasTramitacaoilterSet, self).qs + return parent.distinct().order_by('-ano', 'tipo', '-numero') + class Meta: model = MateriaLegislativa fields = ['ano', 'tipo', 'tramitacao__unidade_tramitacao_local', @@ -736,7 +741,7 @@ class RelatorioMateriasPorAutorFilterSet(django_filters.FilterSet): @property def qs(self): parent = super(RelatorioMateriasPorAutorFilterSet, self).qs - return parent.distinct().order_by('-ano', '-numero') + return parent.distinct().filter(autoria__primeiro_autor=True).order_by('autoria__autor', '-autoria__primeiro_autor', 'tipo', '-ano', '-numero') class Meta: model = MateriaLegislativa diff --git a/sapl/base/views.py b/sapl/base/views.py index b41492f4e..870fbbaa5 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -393,7 +393,7 @@ class RelatorioMateriasTramitacaoView(FilterView): context = super(RelatorioMateriasTramitacaoView, self).get_context_data(**kwargs) - context['title'] = _('Matérias por Ano, Autor e Tipo') + context['title'] = _('Matérias em Tramitação') qs = context['object_list'] qs = qs.filter(em_tramitacao=True) diff --git a/sapl/templates/base/RelatorioMateriasPorAutor_filter.html b/sapl/templates/base/RelatorioMateriasPorAutor_filter.html index ec26ecd63..bf0b7702f 100644 --- a/sapl/templates/base/RelatorioMateriasPorAutor_filter.html +++ b/sapl/templates/base/RelatorioMateriasPorAutor_filter.html @@ -15,56 +15,55 @@ - + - + {% for key, value in qtdes.items %} - + {% endfor %} -
QUADRO GERAL
QUADRO GERAL
Tipo MatériaTipo Matéria Quantidade
{{key.sigla}} - {{key}}{{key.sigla}} - {{key}} {{value}}
- - - - - - - - - - - {% for materia in object_list %} - - - - - - - {% endfor %} - + {% for materia in object_list %} + {% ifchanged materia.autoria_set.first.autor %} + + + + + + + + + + + {% endifchanged %} + + + + + + + + + {% endfor %}
MatériaEmentaAutorCoautor(es)
- {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} - {{materia.ementa}} - {% for autor in materia.autoria_set.all %} - {% if autor.primeiro_autor %} - {{autor.autor}}
- {% endif %} - {% endfor %} -
- {% for autor in materia.autoria_set.all %} - {% if not autor.primeiro_autor %} - {{autor.autor}}
- {% endif %} - {% endfor %} -
Autor: {{ materia.autoria_set.first.autor }}
MatériaEmentaCoautor(es)
+ {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} + {% autoescape off %}{{materia.ementa}}{% endautoescape %} + {% if materia.autoria_set.first != materia.autoria_set.last %} + {% for autor in materia.autoria_set.all %} + {% if not autor.primeiro_autor %} + {{ autor.autor }}
+ {% endif %} + {% endfor %} + {% endif %} +
+ {% endif %} {% endblock base_content %} From d5d12c7c89b06e344b5c0e89225f41be97160155 Mon Sep 17 00:00:00 2001 From: cristian-longhi Date: Fri, 10 Aug 2018 13:41:21 -0300 Subject: [PATCH 24/45] =?UTF-8?q?Ajusta=20ordena=C3=A7=C3=A3o=20em=20propo?= =?UTF-8?q?si=C3=A7=C3=B5es=20n=C3=A3o=20recebidas=20(#2124)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/base/templatetags/common_tags.py | 10 +++++ sapl/materia/views.py | 6 +++ .../materia/prop_pendentes_list.html | 41 +++++++++++-------- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py index 73d71faa8..3d906e446 100644 --- a/sapl/base/templatetags/common_tags.py +++ b/sapl/base/templatetags/common_tags.py @@ -63,6 +63,16 @@ def sort_by_keys(value, key): return transformed +@register.filter +def paginacao_limite_inferior(pagina): + return (int(pagina) - 1) * 10 + + +@register.filter +def paginacao_limite_superior(pagina): + return int(pagina) * 10 + + @register.filter def lookup(d, key): return d[key] if key in d else [] diff --git a/sapl/materia/views.py b/sapl/materia/views.py index f2e3e76db..fcfa15677 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -426,6 +426,10 @@ class ProposicaoPendente(PermissionRequiredMixin, ListView): def get_context_data(self, **kwargs): context = super(ProposicaoPendente, self).get_context_data(**kwargs) + context['object_list'] = Proposicao.objects.filter( + data_envio__isnull=False, + data_recebimento__isnull=True, + data_devolucao__isnull=True) paginator = context['paginator'] page_obj = context['page_obj'] context['AppConfig'] = sapl.base.models.AppConfig.objects.all().last() @@ -434,6 +438,8 @@ class ProposicaoPendente(PermissionRequiredMixin, ListView): context['NO_ENTRIES_MSG'] = 'Nenhuma proposição pendente.' context['subnav_template_name'] = 'materia/subnav_prop.yaml' + qr = self.request.GET.copy() + context['filter_url'] = ('&o=' + qr['o']) if 'o' in qr.keys() else '' return context diff --git a/sapl/templates/materia/prop_pendentes_list.html b/sapl/templates/materia/prop_pendentes_list.html index 518ba7601..251c4ed22 100644 --- a/sapl/templates/materia/prop_pendentes_list.html +++ b/sapl/templates/materia/prop_pendentes_list.html @@ -39,24 +39,33 @@ {% define object_list as list %} {% endif %} + {% if 'page' in request.GET %} + {% define request.GET.page as pagina %} + {% else %} + {% define '1' as pagina %} + {% endif %} + {% for prop in list %} - - -
{{ prop.data_envio|localtime|date:"d/m/Y H:i:s" }} - - {{ prop.tipo.descricao }} - {{ prop.descricao }} - {{ prop.autor }} - - {% if not AppConfig.receber_recibo_proposicao %} - {%if prop.hash_code %} - {{ prop.hash_code }} - {% else %} - {{ prop.hash_code }} + + {% if forloop.counter > pagina|paginacao_limite_inferior and forloop.counter <= pagina|paginacao_limite_superior %} + + + {{ prop.data_envio|localtime|date:"d/m/Y H:i:s" }} + + {{ prop.tipo.descricao }} + {{ prop.descricao }} + {{ prop.autor }} + + {% if not AppConfig.receber_recibo_proposicao %} + {%if prop.hash_code %} + {{ prop.hash_code }} + {% else %} + {{ prop.hash_code }} + {% endif %} {% endif %} - {% endif %} - - + + + {% endif %} {% endfor %} From 217a4a0e1e7cbc321fb98827d9bc767bda8b7d46 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Fri, 10 Aug 2018 15:58:18 -0100 Subject: [PATCH 25/45] =?UTF-8?q?Fix=20#2127=20Checagem=20de=20datas=20de?= =?UTF-8?q?=20Frente=20Parlamentar=20e=20coluna=20extra=20na=20l=E2=80=A6?= =?UTF-8?q?=20(#2131)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #2127 Checagem de datas de Frente Parlamentar e coluna extra na listagem * Update views.py --- sapl/parlamentares/forms.py | 32 +++++++++++++++++++++++--------- sapl/parlamentares/views.py | 10 +++++++--- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/sapl/parlamentares/forms.py b/sapl/parlamentares/forms.py index 36ce94c3a..d112e1d81 100644 --- a/sapl/parlamentares/forms.py +++ b/sapl/parlamentares/forms.py @@ -318,18 +318,32 @@ class FrenteForm(ModelForm): model = Frente fields = '__all__' + def clean(self): + frente = super(FrenteForm, self).clean() + cd = self.cleaned_data + if not self.is_valid(): + return self.cleaned_data + + if cd['data_criacao'] >= cd['data_extincao']: + raise ValidationError(_("Data Dissolução não pode ser anterior a Data Criação")) + + return cd + @transaction.atomic def save(self, commit=True): frente = super(FrenteForm, self).save(commit) - content_type = ContentType.objects.get_for_model(Frente) - object_id = frente.pk - tipo = TipoAutor.objects.get(descricao__icontains='Frente') - Autor.objects.create( - content_type=content_type, - object_id=object_id, - tipo=tipo, - nome=frente.nome - ) + + if not self.instance.pk: + frente = super(FrenteForm, self).save(commit) + content_type = ContentType.objects.get_for_model(Frente) + object_id = frente.pk + tipo = TipoAutor.objects.get(descricao__icontains='Frente') + Autor.objects.create( + content_type=content_type, + object_id=object_id, + tipo=tipo, + nome=frente.nome + ) return frente diff --git a/sapl/parlamentares/views.py b/sapl/parlamentares/views.py index 78678c3fc..ad4a8f5e5 100644 --- a/sapl/parlamentares/views.py +++ b/sapl/parlamentares/views.py @@ -87,8 +87,7 @@ class FrenteList(MasterDetailCrud): CreateView, UpdateView, DeleteView = None, None, None class BaseMixin(Crud.PublicMixin, MasterDetailCrud.BaseMixin): - list_field_names = ['nome', 'data_criacao'] - + list_field_names = ['nome', 'data_criacao', 'data_extincao'] @classmethod def url_name(cls, suffix): return '%s_parlamentar_%s' % (cls.model._meta.model_name, suffix) @@ -282,7 +281,8 @@ class FrenteCrud(CrudAux): model = Frente help_topic = 'tipo_situa_militar' public = [RP_DETAIL, RP_LIST] - list_field_names = ['nome', 'data_criacao', 'parlamentares'] + list_field_names = ['nome', 'data_criacao', 'data_extincao', 'parlamentares'] + class CreateView(Crud.CreateView): form_class = FrenteForm @@ -290,6 +290,10 @@ class FrenteCrud(CrudAux): def form_valid(self, form): return super(Crud.CreateView, self).form_valid(form) + class UpdateView(Crud.UpdateView): + form_class = FrenteForm + + class MandatoCrud(MasterDetailCrud): model = Mandato From 5e7c39060997653d9c88db75df8c0cb6f0674ae8 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Fri, 10 Aug 2018 16:47:44 -0100 Subject: [PATCH 26/45] Fix #697 Anexos da Norma Juridica (#2128) * teste * subnav anexos * Fix #697 * Fix #697 * Update forms.py * conserta problema de desempenho --- sapl/base/templatetags/common_tags.py | 9 +++++ sapl/norma/forms.py | 35 +++++++++++++++++- .../migrations/0012_anexonormajuridica.py | 31 ++++++++++++++++ sapl/norma/models.py | 31 ++++++++++++++++ sapl/norma/urls.py | 6 ++-- sapl/norma/views.py | 36 +++++++++++++++++-- sapl/rules/map_rules.py | 1 + sapl/templates/norma/layouts.yaml | 5 +++ .../templates/norma/normajuridica_detail.html | 16 +++++++++ sapl/templates/norma/subnav.yaml | 2 ++ 10 files changed, 166 insertions(+), 6 deletions(-) create mode 100644 sapl/norma/migrations/0012_anexonormajuridica.py diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py index 3d906e446..71f63e130 100644 --- a/sapl/base/templatetags/common_tags.py +++ b/sapl/base/templatetags/common_tags.py @@ -44,6 +44,15 @@ def split(value, arg): return value.split(arg) +@register.filter +def to_str(arg): + return str(arg) + +@register.filter +def get_last_item_from_list(list,arg): + return list[arg] + + @register.filter def sort_by_keys(value, key): transformed = [] diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index 610895e09..92fadde55 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -14,7 +14,7 @@ from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.settings import MAX_DOC_UPLOAD_SIZE from sapl.utils import RANGE_ANOS, RangeWidgetOverride -from .models import (AssuntoNorma, NormaJuridica, NormaRelacionada, +from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada, TipoNormaJuridica) @@ -120,6 +120,7 @@ class NormaJuridicaForm(ModelForm): 'assuntos'] widgets = {'assuntos': widgets.CheckboxSelectMultiple} + def clean(self): cleaned_data = super(NormaJuridicaForm, self).clean() @@ -175,9 +176,41 @@ class NormaJuridicaForm(ModelForm): norma.timestamp = timezone.now() norma.materia = self.cleaned_data['materia'] norma = super(NormaJuridicaForm, self).save(commit=True) + return norma +class AnexoNormaJuridicaForm(ModelForm): + class Meta: + model = AnexoNormaJuridica + fields = ['norma', 'anexo_arquivo'] + widgets = { + 'norma': forms.HiddenInput(), + } + + def clean(self): + cleaned_data = super(AnexoNormaJuridicaForm, self).clean() + if not self.is_valid(): + return cleaned_data + anexo_arquivo = self.cleaned_data.get('anexo_arquivo', False) + if anexo_arquivo: + if anexo_arquivo.size > MAX_DOC_UPLOAD_SIZE: + max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024)) + raise ValidationError( + "Arquivo muito grande. ( > {0}MB )".format(max_size)) + return cleaned_data + + def save(self, commit=False): + anexo = self.instance + anexo.ano = self.cleaned_data['norma'].ano + anexo = super(AnexoNormaJuridicaForm, self).save(commit=True) + anexo.norma = self.cleaned_data['norma'] + anexo.anexo_arquivo = self.cleaned_data['anexo_arquivo'] + anexo.save() + return anexo + + + class NormaRelacionadaForm(ModelForm): tipo = forms.ModelChoiceField( diff --git a/sapl/norma/migrations/0012_anexonormajuridica.py b/sapl/norma/migrations/0012_anexonormajuridica.py new file mode 100644 index 000000000..2ba9ebdca --- /dev/null +++ b/sapl/norma/migrations/0012_anexonormajuridica.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-08-06 19:48 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import sapl.norma.models +import sapl.utils + + +class Migration(migrations.Migration): + + dependencies = [ + ('norma', '0011_auto_20180220_1859'), + ] + + operations = [ + migrations.CreateModel( + name='AnexoNormaJuridica', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('anexo_arquivo', models.FileField(blank=True, null=True, upload_to=sapl.norma.models.norma_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Arquivo Anexo')), + ('ano', models.PositiveSmallIntegerField(choices=[(2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano')), + ('norma', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='norma', to='norma.NormaJuridica', verbose_name='Norma Juridica')), + ], + options={ + 'verbose_name_plural': 'Anexos da Norma Juridica', + 'verbose_name': 'Anexo da Norma Juridica', + }, + ), + ] diff --git a/sapl/norma/models.py b/sapl/norma/models.py index b045ea1f9..54f47e865 100644 --- a/sapl/norma/models.py +++ b/sapl/norma/models.py @@ -141,6 +141,12 @@ class NormaJuridica(models.Model): norma_relacionada=self.id) return (principais, relacionadas) + def get_anexos_norma_juridica(self): + anexos = AnexoNormaJuridica.objects.filter( + norma=self.id) + return anexos + + def __str__(self): return _('%(tipo)s nº %(numero)s de %(data)s') % { 'tipo': self.tipo, @@ -252,3 +258,28 @@ class NormaRelacionada(models.Model): ' - Relacionada: %(norma_relacionada)s') % { 'norma_principal': self.norma_principal, 'norma_relacionada': self.norma_relacionada} + + +@reversion.register() +class AnexoNormaJuridica(models.Model): + norma = models.ForeignKey( + NormaJuridica, + related_name='norma', + on_delete=models.PROTECT, + verbose_name=_('Norma Juridica')) + anexo_arquivo = models.FileField( + blank=True, + null=True, + upload_to=norma_upload_path, + verbose_name=_('Arquivo Anexo'), + validators=[restringe_tipos_de_arquivo_txt]) + ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'), + choices=RANGE_ANOS) + + class Meta: + verbose_name = _('Anexo da Norma Juridica') + verbose_name_plural = _('Anexos da Norma Juridica') + + def __str__(self): + return _('Anexo: %(anexo)s da norma %(norma)s') % { + 'anexo': self.anexo_arquivo, 'norma': self.norma} diff --git a/sapl/norma/urls.py b/sapl/norma/urls.py index 93081c4fc..d943f71e8 100644 --- a/sapl/norma/urls.py +++ b/sapl/norma/urls.py @@ -1,6 +1,6 @@ from django.conf.urls import include, url -from sapl.norma.views import (AssuntoNormaCrud, NormaCrud, NormaPesquisaView, +from sapl.norma.views import (AnexoNormaJuridicaCrud,AssuntoNormaCrud, NormaCrud, NormaPesquisaView, NormaRelacionadaCrud, NormaTaView, TipoNormaCrud, TipoVinculoNormaJuridicaCrud, recuperar_norma, recuperar_numero_norma) @@ -12,11 +12,11 @@ app_name = AppConfig.name urlpatterns = [ url(r'^norma/', include(NormaCrud.get_urls() + - NormaRelacionadaCrud.get_urls())), + NormaRelacionadaCrud.get_urls() + + AnexoNormaJuridicaCrud.get_urls())), # Integração com Compilação url(r'^norma/(?P[0-9]+)/ta$', NormaTaView.as_view(), name='norma_ta'), - url(r'^sistema/norma/tipo/', include(TipoNormaCrud.get_urls())), url(r'^sistema/norma/assunto/', include(AssuntoNormaCrud.get_urls())), url(r'^sistema/norma/vinculo/', include( diff --git a/sapl/norma/views.py b/sapl/norma/views.py index f5fecdefc..de3efa8ef 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -19,9 +19,9 @@ from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, MasterDetailCrud, make_pagination) from sapl.utils import show_results_filter_set -from .forms import (NormaFilterSet, NormaJuridicaForm, +from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm, NormaPesquisaSimplesForm, NormaRelacionadaForm) -from .models import (AssuntoNorma, NormaJuridica, NormaRelacionada, +from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada, TipoNormaJuridica, TipoVinculoNormaJuridica) # LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '') @@ -98,6 +98,38 @@ class NormaPesquisaView(FilterView): return context +class AnexoNormaJuridicaCrud(MasterDetailCrud): + model = AnexoNormaJuridica + parent_field = 'norma' + help_topic = 'anexonormajuridica' + public = [RP_LIST, RP_DETAIL] + + class BaseMixin(MasterDetailCrud.BaseMixin): + list_field_names = ['id','anexo_arquivo'] + + class CreateView(MasterDetailCrud.CreateView): + form_class = AnexoNormaJuridicaForm + layout_key = 'AnexoNormaJuridica' + def get_initial(self): + norma_id = str(self.request).split("/")[-3] + self.initial = super(MasterDetailCrud.CreateView, self).get_initial() + self.initial['norma'] = NormaJuridica.objects.get(id=norma_id) + return self.initial + + class UpdateView(MasterDetailCrud.UpdateView): + form_class = AnexoNormaJuridicaForm + layout_key = 'AnexoNormaJuridica' + def get_initial(self): + initial = super(UpdateView, self).get_initial() + initial['norma'] = self.object.norma + initial['anexo_arquivo'] = self.object.anexo_arquivo + initial['ano'] = self.object.ano + return initial + + class DetailView(MasterDetailCrud.DetailView): + form_class = AnexoNormaJuridicaForm + layout_key = 'AnexoNormaJuridica' + class NormaTaView(IntegracaoTaView): model = NormaJuridica diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index f98da8c0e..bba114149 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -135,6 +135,7 @@ rules_group_norma = { 'rules': [ (norma.NormaJuridica, __base__), (norma.NormaRelacionada, __base__), + (norma.AnexoNormaJuridica, __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/layouts.yaml b/sapl/templates/norma/layouts.yaml index a06b80b2b..591faed38 100644 --- a/sapl/templates/norma/layouts.yaml +++ b/sapl/templates/norma/layouts.yaml @@ -24,6 +24,11 @@ NormaJuridica: - observacao - assuntos +AnexoNormaJuridica: + {% trans 'Adicionar Anexos à Norma Jurídica' %}: + - anexo_arquivo + - norma + NormaJuridicaCreate: {% trans 'Identificação Básica' %}: - tipo ano numero diff --git a/sapl/templates/norma/normajuridica_detail.html b/sapl/templates/norma/normajuridica_detail.html index 6dcd3d592..24df5476a 100644 --- a/sapl/templates/norma/normajuridica_detail.html +++ b/sapl/templates/norma/normajuridica_detail.html @@ -58,6 +58,22 @@
{% endfor %} {% endif %} + +
+
+
+  

Anexos Norma Jurídica

+ {% if object.get_anexos_norma_juridica|length > 0 %} + {% for p in object.get_anexos_norma_juridica %} + + {% endfor %} + {% endif %} +
+
{% endblock detail_content %} diff --git a/sapl/templates/norma/subnav.yaml b/sapl/templates/norma/subnav.yaml index a89326fd7..9358787ff 100644 --- a/sapl/templates/norma/subnav.yaml +++ b/sapl/templates/norma/subnav.yaml @@ -5,6 +5,8 @@ - title: {% trans 'Alterações em Outras Normas' %} url: normarelacionada_list check_permission: norma.list_normarelacionada +- title: {% trans 'Anexos da Norma' %} + url: anexonormajuridica_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 From bdd4f4cbb67a098ff0d57e32158f3e4853bc56b0 Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Fri, 10 Aug 2018 17:27:43 -0300 Subject: [PATCH 27/45] FIX #2126 (#2130) * fix #2126 * Corrige os testes --- sapl/sessao/forms.py | 18 ++++++++++++++++++ sapl/sessao/tests/test_sessao.py | 18 +++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index 06dd40830..cc68df531 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -112,6 +112,24 @@ class BancadaForm(ModelForm): if not self.is_valid(): return self.cleaned_data + data = self.cleaned_data + + legislatura = data['legislatura'] + + data_criacao = data['data_criacao'] + if data_criacao: + if (data_criacao < legislatura.data_inicio or + data_criacao > legislatura.data_fim): + raise ValidationError(_("Data de criação da bancada fora do intervalo" + " de legislatura informada")) + + data_extincao = data['data_extincao'] + if data_extincao: + if (data_extincao < legislatura.data_inicio or + data_extincao > legislatura.data_fim): + raise ValidationError(_("Data fim da bancada fora do intervalo de" + " legislatura informada")) + if self.cleaned_data['data_extincao']: if (self.cleaned_data['data_extincao'] < self.cleaned_data['data_criacao']): diff --git a/sapl/sessao/tests/test_sessao.py b/sapl/sessao/tests/test_sessao.py index d83c56e86..336c62ad0 100644 --- a/sapl/sessao/tests/test_sessao.py +++ b/sapl/sessao/tests/test_sessao.py @@ -1,4 +1,5 @@ import pytest +from datetime import datetime from django.core.exceptions import ValidationError from django.utils.translation import ugettext_lazy as _ from model_mommy import mommy @@ -87,9 +88,16 @@ def test_valida_campos_obrigatorios_bancada_form(): assert len(errors) == 3 +def data(valor): + return datetime.strptime(valor, '%Y-%m-%d').date() + + @pytest.mark.django_db(transaction=False) def test_bancada_form_valido(): - legislatura = mommy.make(Legislatura) + legislatura = mommy.make(Legislatura, + data_inicio=data('2017-11-10'), + data_fim=data('2017-12-31'), + ) partido = mommy.make(Partido) form = forms.BancadaForm(data={'legislatura': str(legislatura.pk), @@ -105,7 +113,10 @@ def test_bancada_form_valido(): @pytest.mark.django_db(transaction=False) def test_bancada_form_datas_invalidas(): - legislatura = mommy.make(Legislatura) + legislatura = mommy.make(Legislatura, + data_inicio=data('2017-11-10'), + data_fim=data('2017-12-31'), + ) partido = mommy.make(Partido) form = forms.BancadaForm(data={'legislatura': str(legislatura.pk), @@ -116,9 +127,6 @@ def test_bancada_form_datas_invalidas(): 'descricao': 'teste' }) assert not form.is_valid() - assert form.errors['__all__'] == [_('Data de extinção não pode ser menor ' - 'que a de criação')] - @pytest.mark.django_db(transaction=False) def test_expediente_materia_form_valido(): From 78edd3dbfa3ff9fe71404f278242823a97d7f569 Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 14 Aug 2018 12:38:32 -0300 Subject: [PATCH 28/45] fix #2132 (#2139) --- .../migrations/0024_auto_20180814_1237.py | 20 +++++++++++++++++++ sapl/parlamentares/models.py | 2 +- sapl/templates/base.html | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 sapl/parlamentares/migrations/0024_auto_20180814_1237.py diff --git a/sapl/parlamentares/migrations/0024_auto_20180814_1237.py b/sapl/parlamentares/migrations/0024_auto_20180814_1237.py new file mode 100644 index 000000000..43873cc68 --- /dev/null +++ b/sapl/parlamentares/migrations/0024_auto_20180814_1237.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-08-14 15:37 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('parlamentares', '0023_auto_20180626_1524'), + ] + + operations = [ + migrations.AlterField( + model_name='mandato', + name='titular', + field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], db_index=True, default=True, verbose_name='Parlamentar Titular'), + ), + ] diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py index 19d4fa57c..43c4e2215 100644 --- a/sapl/parlamentares/models.py +++ b/sapl/parlamentares/models.py @@ -443,7 +443,7 @@ class Mandato(models.Model): db_index=True, default=True, choices=YES_NO_CHOICES, - verbose_name=_('Vereador Titular')) + verbose_name=_('Parlamentar Titular')) observacao = models.TextField( blank=True, verbose_name=_('Observação')) diff --git a/sapl/templates/base.html b/sapl/templates/base.html index c6a5d223b..3e1dc3a39 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -203,7 +203,7 @@ {{ endereco }}
CEP: {{ cep }} | Telefone: {{ telefone }}
- {% trans 'Site da Câmara' %} | + {% trans 'Site' %} | From c61f205f5081cdcca78cbe19e7f107c2d09ed68d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Sconetto?= Date: Tue, 14 Aug 2018 12:42:16 -0300 Subject: [PATCH 29/45] =?UTF-8?q?Verifica=C3=A7=C3=A3o=20do=20Mandato=20(#?= =?UTF-8?q?2138)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #2125 * Refatora código --- sapl/parlamentares/forms.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sapl/parlamentares/forms.py b/sapl/parlamentares/forms.py index d112e1d81..326d41b3a 100644 --- a/sapl/parlamentares/forms.py +++ b/sapl/parlamentares/forms.py @@ -99,6 +99,19 @@ class MandatoForm(ModelForm): raise ValidationError(_("Data fim mandato fora do intervalo de" " legislatura informada")) + data_expedicao_diploma = data['data_expedicao_diploma'] + if (data_expedicao_diploma and + data_expedicao_diploma > data_inicio_mandato): + raise ValidationError(_("A data da expedição do diploma deve ser anterior " + "a data de início do mandato")) + + coligacao = data['coligacao'] + if coligacao and not coligacao.legislatura == legislatura: + raise ValidationError(_("A coligação selecionada não está cadastrada " + "na mesma legislatura que o presente mandato, " + "favor verificar a coligação ou fazer o cadastro " + "de uma nova coligação na legislatura correspondente")) + existe_mandato = Mandato.objects.filter( parlamentar=data['parlamentar'], legislatura=data['legislatura']).exists() From 8fe6e4975d490748504fdeb6b6c0924d06d0bff3 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Tue, 14 Aug 2018 13:19:58 -0300 Subject: [PATCH 30/45] Release: 3.1.106 --- 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 e017e886b..3e233b26f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.105 + image: interlegis/sapl:3.1.106 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 0d38c06b6..a953732de 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.105', + version='3.1.106', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 5910fea33a84af4d6c1649afb6b6b46e160e190f Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 14 Aug 2018 13:20:37 -0300 Subject: [PATCH 31/45] =?UTF-8?q?HOT-FIX:=20renomear=20vari=C3=A1vel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/materia/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index fcfa15677..5f1b81ccf 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -707,12 +707,12 @@ class ProposicaoCrud(Crud): messages.success(request, _( 'Proposição enviada com sucesso.')) try: - Numero = MateriaLegislativa.objects.filter(tipo=p.tipo.tipo_conteudo_related, + numero = MateriaLegislativa.objects.filter(tipo=p.tipo.tipo_conteudo_related, ano=p.ano).last().numero + 1 messages.success(request, _( '%s : nº %s de %s
Atenção! Este número é apenas um provável ' 'número que pode não corresponder com a realidade' - % (p.tipo, Numero, p.ano))) + % (p.tipo, numero, p.ano))) except ValueError: pass From 8d0480c7d436ba33233c05a71a6246d29b991ceb Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 14 Aug 2018 14:38:19 -0300 Subject: [PATCH 32/45] HOT-FIX: Retira tipo do __str__() de NormaJuridica + refactoring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retira o campo tipo do __str__() de NormaJuridica porque ele estava fazendo uma query para cada norma recuperada, se utilizado em uma caixa de select, por exemplo. Em uma tela como Anexo de Norma isso gerava uma grande perda de desempenho, chegando a levar vários segundos para renderizar a tela. --- sapl/norma/forms.py | 9 ++++----- sapl/norma/models.py | 3 +-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index 92fadde55..e3fd6e435 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -193,11 +193,10 @@ class AnexoNormaJuridicaForm(ModelForm): if not self.is_valid(): return cleaned_data anexo_arquivo = self.cleaned_data.get('anexo_arquivo', False) - if anexo_arquivo: - if anexo_arquivo.size > MAX_DOC_UPLOAD_SIZE: - max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024)) - raise ValidationError( - "Arquivo muito grande. ( > {0}MB )".format(max_size)) + if anexo_arquivo and anexo_arquivo.size > MAX_DOC_UPLOAD_SIZE: + max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024)) + raise ValidationError( + "Arquivo muito grande. ( > {0}MB )".format(max_size)) return cleaned_data def save(self, commit=False): diff --git a/sapl/norma/models.py b/sapl/norma/models.py index 54f47e865..ff7b44dca 100644 --- a/sapl/norma/models.py +++ b/sapl/norma/models.py @@ -148,8 +148,7 @@ class NormaJuridica(models.Model): def __str__(self): - return _('%(tipo)s nº %(numero)s de %(data)s') % { - 'tipo': self.tipo, + return _('nº %(numero)s de %(data)s') % { 'numero': self.numero, 'data': defaultfilters.date(self.data, "d \d\e F \d\e Y")} From 4310589f6a60e096b3945d09f9e7ca4f9fa36068 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 14 Aug 2018 15:22:21 -0300 Subject: [PATCH 33/45] HOT-FIX: Refactorings --- sapl/materia/forms.py | 9 ++++----- sapl/norma/forms.py | 9 ++++----- sapl/norma/views.py | 9 +++++---- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index b543fda41..88db58f8b 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1295,12 +1295,11 @@ class ProposicaoForm(forms.ModelForm): def clean_texto_original(self): texto_original = self.cleaned_data.get('texto_original', False) - if texto_original: - if texto_original.size > MAX_DOC_UPLOAD_SIZE: - max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024)) - raise ValidationError( + if texto_original and texto_original.size > MAX_DOC_UPLOAD_SIZE: + max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024)) + raise ValidationError( "Arquivo muito grande. ( > {0}MB )".format(max_size)) - return texto_original + return texto_original def gerar_hash(self, inst, receber_recibo): diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index e3fd6e435..7d791207a 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -164,11 +164,10 @@ class NormaJuridicaForm(ModelForm): def clean_texto_integral(self): texto_integral = self.cleaned_data.get('texto_integral', False) - if texto_integral: - if texto_integral.size > MAX_DOC_UPLOAD_SIZE: - max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024)) - raise ValidationError( - "Arquivo muito grande. ( > {0}MB )".format(max_size)) + if texto_integral and texto_integral.size > MAX_DOC_UPLOAD_SIZE: + max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024)) + raise ValidationError( + "Arquivo muito grande. ( > {0}MB )".format(max_size)) return texto_integral def save(self, commit=False): diff --git a/sapl/norma/views.py b/sapl/norma/views.py index de3efa8ef..3f57ad387 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -110,15 +110,16 @@ class AnexoNormaJuridicaCrud(MasterDetailCrud): class CreateView(MasterDetailCrud.CreateView): form_class = AnexoNormaJuridicaForm layout_key = 'AnexoNormaJuridica' + def get_initial(self): - norma_id = str(self.request).split("/")[-3] - self.initial = super(MasterDetailCrud.CreateView, self).get_initial() - self.initial['norma'] = NormaJuridica.objects.get(id=norma_id) - return self.initial + initial = super(MasterDetailCrud.CreateView, self).get_initial() + initial['norma'] = NormaJuridica.objects.get(id=self.kwargs['pk']) + return initial class UpdateView(MasterDetailCrud.UpdateView): form_class = AnexoNormaJuridicaForm layout_key = 'AnexoNormaJuridica' + def get_initial(self): initial = super(UpdateView, self).get_initial() initial['norma'] = self.object.norma From 291c691aa4fe3c1cd4124e49a592d1b87d47dca6 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 14 Aug 2018 16:56:24 -0300 Subject: [PATCH 34/45] HOT-FIX: remove import ipdb --- sapl/redireciona_urls/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sapl/redireciona_urls/views.py b/sapl/redireciona_urls/views.py index 82f6f44ea..ade47c9de 100644 --- a/sapl/redireciona_urls/views.py +++ b/sapl/redireciona_urls/views.py @@ -449,7 +449,6 @@ class RedirecionaNormasJuridicasTextoIntegral(RedirectView): permanent = False def get_redirect_url(self, **kwargs): - # import ipdb;ipdb.set_trace() url = EMPTY_STRING try: norma = NormaJuridica.objects.get(pk=kwargs['norma_id']) From b91d083b3e99298c1b7ea89883d450a7bd568394 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Tue, 14 Aug 2018 18:42:17 -0300 Subject: [PATCH 35/45] Fix recurar_numero_norma (#2140) --- sapl/norma/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/norma/views.py b/sapl/norma/views.py index 3f57ad387..87b842802 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -238,7 +238,7 @@ def recuperar_numero_norma(request): param = {'tipo': tipo} param['ano'] = ano if ano else timezone.now().year norma = NormaJuridica.objects.filter(**param).order_by( - 'tipo', 'ano').values_list('numero', 'ano').last() + 'tipo', 'ano', 'numero').values_list('numero', 'ano').last() if norma: response = JsonResponse({'numero': int(re.sub("[^0-9].*", '', norma[0])) + 1, 'ano': norma[1]}) From ce621d8e486f1c01e6eb133a55ea69e4acb30548 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 11 Jul 2018 15:16:09 -0300 Subject: [PATCH 36/45] =?UTF-8?q?Corrige=20set=20generic=20fk=20na=20migra?= =?UTF-8?q?=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 4c953d5f5..45b3c9338 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -141,10 +141,6 @@ models_novos_para_antigos = { for model in field_renames} models_novos_para_antigos[Composicao] = models_novos_para_antigos[Participacao] -content_types = {model: ContentType.objects.get( - app_label=model._meta.app_label, model=model._meta.model_name) - for model in field_renames} - campos_novos_para_antigos = { model._meta.get_field(nome_novo): nome_antigo for model, renames in field_renames.items() @@ -1156,7 +1152,9 @@ def adjust_tipoafastamento(new, old): def set_generic_fk(new, campo_virtual, old): - new.content_type = content_types[campo_virtual.related_model] + model = campo_virtual.related_model + new.content_type = ContentType.objects.get( + app_label=model._meta.app_label, model=model._meta.model_name) new.object_id = get_fk_related(campo_virtual, old) From 05c6660e748523f991e16e805708ec535f4b6beb Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 11 Jul 2018 15:30:43 -0300 Subject: [PATCH 37/45] Migra perfil operador painel (do sapl 3.0) --- sapl/legacy/migracao_usuarios.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sapl/legacy/migracao_usuarios.py b/sapl/legacy/migracao_usuarios.py index 51b3348c8..d767343a3 100644 --- a/sapl/legacy/migracao_usuarios.py +++ b/sapl/legacy/migracao_usuarios.py @@ -16,6 +16,7 @@ PERFIL_LEGADO_PARA_NOVO = {legado: Group.objects.get(name=novo) ('Operador Protocolo', 'Operador de Protocolo Administrativo'), ('Operador Sessao Plenaria', 'Operador de Sessão Plenária'), ('Parlamentar', 'Votante'), + ('Operador Painel', 'Operador de Painel Eletrônico'), ] } From 43f86e3d796f96b5d39d023d19037d364a144d4c Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 13 Jul 2018 15:03:45 -0300 Subject: [PATCH 38/45] Torna apagar legado opcional --- .../management/commands/migracao_25_31.py | 11 +++++++- sapl/legacy/migracao.py | 4 +-- sapl/legacy/migracao_dados.py | 25 ++++++++++--------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/sapl/legacy/management/commands/migracao_25_31.py b/sapl/legacy/management/commands/migracao_25_31.py index e3864ad0f..ba9a80224 100644 --- a/sapl/legacy/management/commands/migracao_25_31.py +++ b/sapl/legacy/management/commands/migracao_25_31.py @@ -7,5 +7,14 @@ class Command(BaseCommand): help = 'Migração de dados do SAPL 2.5 para o SAPL 3.1' + def add_arguments(self, parser): + parser.add_argument( + '-a', + action='store_true', + default=False, + dest='apagar_do_legado', + help='Apagar entradas migradas do legado', + ) + def handle(self, *args, **options): - migrar(interativo=False) + migrar(apagar_do_legado=options['apagar_do_legado']) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index dd54a103e..c4c183b84 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -18,7 +18,7 @@ def adornar_msg(msg): return '\n{1}\n{0}\n{1}'.format(msg, '#' * len(msg)) -def migrar(interativo=False): +def migrar(apagar_do_legado=False): if TAG_MARCO in REPO.tags: info('A migração já está feita.') return @@ -26,7 +26,7 @@ def migrar(interativo=False): 'Antes de migrar ' 'é necessário fazer a exportação de documentos do zope') management.call_command('migrate') - migrar_dados() + migrar_dados(apagar_do_legado) migrar_usuarios(REPO.working_dir) migrar_documentos(REPO) gravar_marco() diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 45b3c9338..75007d821 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -804,7 +804,7 @@ def roda_comando_shell(cmd): assert res == 0, 'O comando falhou: {}'.format(cmd) -def migrar_dados(): +def migrar_dados(apagar_do_legado=False): try: ocorrencias.clear() ocorrencias.default_factory = list @@ -836,7 +836,7 @@ def migrar_dados(): fill_vinculo_norma_juridica() fill_dados_basicos() info('Começando migração: ...') - migrar_todos_os_models() + migrar_todos_os_models(apagar_do_legado) except Exception as e: ocorrencias['traceback'] = str(traceback.format_exc()) raise e @@ -886,12 +886,12 @@ def get_models_a_migrar(): return models -def migrar_todos_os_models(): +def migrar_todos_os_models(apagar_do_legado): for model in get_models_a_migrar(): - migrar_model(model) + migrar_model(model, apagar_do_legado) -def migrar_model(model): +def migrar_model(model, apagar_do_legado): print('Migrando %s...' % model.__name__) model_legado, tabela_legado, campos_pk_legado = \ @@ -945,12 +945,13 @@ def migrar_model(model): novos.append(new) # guarda para salvar # acumula deleção do registro no legado - sql_delete_legado += 'delete from {} where {};\n'.format( - tabela_legado, - ' and '.join( - '{} = "{}"'.format(campo, - getattr(old, campo)) - for campo in campos_pk_legado)) + if apagar_do_legado: + sql_delete_legado += 'delete from {} where {};\n'.format( + tabela_legado, + ' and '.join( + '{} = "{}"'.format(campo, + getattr(old, campo)) + for campo in campos_pk_legado)) # salva novos registros with reversion.create_revision(): @@ -969,7 +970,7 @@ def migrar_model(model): reinicia_sequence(model, ultima_pk_legado + 1) # apaga registros migrados do legado - if sql_delete_legado: + if apagar_do_legado and sql_delete_legado: exec_legado(sql_delete_legado) From 1cba4b42d8c09209b6406a4f40621b40c8308d3e Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 14 Aug 2018 14:13:38 -0300 Subject: [PATCH 39/45] =?UTF-8?q?Corrige=20propaga=C3=A7=C3=A3o=20de=20exc?= =?UTF-8?q?lus=C3=B5es=20de=20registros=20de=20vota=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 75007d821..24bc9948d 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -8,7 +8,6 @@ from datetime import date from functools import lru_cache, partial from itertools import groupby from operator import xor -from subprocess import PIPE, call import git import pkg_resources @@ -31,12 +30,10 @@ from unipath import Path from sapl.base.models import AppConfig as AppConf from sapl.base.models import Autor, TipoAutor, cria_models_tipo_autor from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao -from sapl.legacy import scripts from sapl.legacy.models import NormaJuridica as OldNormaJuridica from sapl.legacy.models import TipoNumeracaoProtocolo -from sapl.legacy_migration_settings import (DATABASES, DIR_DADOS_MIGRACAO, - DIR_REPO, NOME_BANCO_LEGADO, - PROJECT_DIR) +from sapl.legacy_migration_settings import (DIR_DADOS_MIGRACAO, DIR_REPO, + NOME_BANCO_LEGADO) from sapl.materia.models import (AcompanhamentoMateria, MateriaLegislativa, Proposicao, StatusTramitacao, TipoDocumento, TipoMateriaLegislativa, TipoProposicao, @@ -222,10 +219,6 @@ class ForeignKeyFaltando(ObjectDoesNotExist): 'Uma FK aponta para um registro inexistente' def __init__(self, field, valor, old): - if (field.related_model.__name__ == 'Comissao' - and old.__class__.__name__ == 'ReuniaoComissao' - and valor == 1): - __import__('pdb').set_trace() self.field = field self.valor = valor self.old = old @@ -542,7 +535,6 @@ PROPAGACOES_DE_EXCLUSAO = [ ('sessao_plenaria', 'ordem_dia', 'cod_sessao_plen'), ('sessao_plenaria', 'expediente_materia', 'cod_sessao_plen'), ('sessao_plenaria', 'expediente_sessao_plenaria', 'cod_sessao_plen'), - ('registro_votacao', 'registro_votacao_parlamentar', 'cod_votacao'), # as consultas no código do sapl 2.5 # votacao_ordem_dia_obter_zsql e votacao_expediente_materia_obter_zsql # indicam que os registros de votação de matérias excluídas não são @@ -558,30 +550,38 @@ PROPAGACOES_DE_EXCLUSAO = [ ('materia_legislativa', 'anexada', 'cod_materia_anexada'), ('materia_legislativa', 'documento_acessorio', 'cod_materia'), ('materia_legislativa', 'numeracao', 'cod_materia'), + ('materia_legislativa', 'expediente_materia', 'cod_materia'), # norma ('norma_juridica', 'vinculo_norma_juridica', 'cod_norma_referente'), ('norma_juridica', 'vinculo_norma_juridica', 'cod_norma_referida'), + ('norma_juridica', 'legislacao_citada', 'cod_norma'), # documento administrativo ('documento_administrativo', 'tramitacao_administrativo', 'cod_documento'), ] +PROPAGACOES_DE_EXCLUSAO_REGISTROS_VOTACAO = [ + ('registro_votacao', 'registro_votacao_parlamentar', 'cod_votacao'), +] + -def propaga_exclusoes(): - for tabela_pai, tabela_filha, fk in PROPAGACOES_DE_EXCLUSAO: +def propaga_exclusoes(propagacoes): + for tabela_pai, tabela_filha, fk in propagacoes: [pk_pai] = get_pk_legado(tabela_pai) - exec_legado(''' + sql = ''' update {} set ind_excluido = 1 where {} not in ( select {} from {} where ind_excluido != 1) - '''.format(tabela_filha, fk, pk_pai, tabela_pai)) + '''.format(tabela_filha, fk, pk_pai, tabela_pai) + exec_legado(sql) def uniformiza_banco(): exec_legado('SET SESSION sql_mode = "";') # desliga checagens do mysql - propaga_exclusoes() + propaga_exclusoes(PROPAGACOES_DE_EXCLUSAO) checa_registros_votacao_ambiguos_e_remove_nao_usados() + propaga_exclusoes(PROPAGACOES_DE_EXCLUSAO_REGISTROS_VOTACAO) garante_coluna_no_legado('proposicao', 'num_proposicao int(11) NULL') @@ -870,7 +870,6 @@ def get_models_a_migrar(): if model in field_renames] # retira reuniões quando não existe na base legada # (só existe no sapl 3.0) - tabelas_legado = [t for (t,) in exec_legado('show tables')] if not EXISTE_REUNIAO_NO_LEGADO: models.remove(Reuniao) # Devido à referência TipoProposicao.tipo_conteudo_related From 51eaff3d4617a4a72f65db531a954f9aa4fa281e Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 14 Aug 2018 14:14:07 -0300 Subject: [PATCH 40/45] =?UTF-8?q?Adciona=20script=20para=20ressucitar=20de?= =?UTF-8?q?pend=C3=AAncias=20de=20fks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/ressucita_dependencias.py | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 sapl/legacy/scripts/ressucita_dependencias.py diff --git a/sapl/legacy/scripts/ressucita_dependencias.py b/sapl/legacy/scripts/ressucita_dependencias.py new file mode 100644 index 000000000..793e51483 --- /dev/null +++ b/sapl/legacy/scripts/ressucita_dependencias.py @@ -0,0 +1,59 @@ +import yaml +from unipath import Path + +from sapl.legacy.migracao_dados import DIR_REPO, exec_legado + +fks_legado = ''' + autor cod_parlamentar parlamentar + autor tip_autor tipo_autor + autoria cod_autor autor + expediente_materia cod_materia materia_legislativa + ordem_dia cod_materia materia_legislativa + legislacao_citada cod_norma norma_juridica + oradores cod_parlamentar parlamentar + oradores_expediente cod_parlamentar parlamentar + ordem_dia_presenca cod_parlamentar parlamentar + protocolo cod_autor autor + registro_votacao tip_resultado_votacao tipo_resultado_votacao + registro_votacao_parlamentar cod_parlamentar parlamentar + registro_votacao_parlamentar cod_votacao registro_votacao + sessao_legislativa num_legislatura legislatura + sessao_plenaria_presenca cod_parlamentar parlamentar +''' +fks_legado = [l.split() for l in fks_legado.strip().splitlines()] +fks_legado = {(o, c): t for (o, c, t) in fks_legado} + + +def get_excluido(fk): + campo, valor, tabela_origem = [fk[k] for k in ('campo', 'valor', 'tabela')] + tabela_alvo = fks_legado[(tabela_origem, campo)] + sql = 'select ind_excluido, t.* from {} t where {} = {}'.format( + tabela_alvo, campo, valor) + res = list(exec_legado(sql)) + return tabela_origem, campo, valor, tabela_alvo, res + + +def get_dependencias_a_ressucitar(): + ocorrencias = yaml.load( + Path(DIR_REPO.child('ocorrencias.yaml').read_file())) + fks = ocorrencias['fk'] + excluidos = [get_excluido(fk) for fk in fks] + desexcluir, criar = [ + set([(tabela_alvo, campo, valor) + for tabela_origem, campo, valor, tabela_alvo, res in excluidos + if condicao(res)]) + for condicao in ( + # o registro existe e ind_excluido == 1 + lambda res: res and res[0][0] == 1, + # o registro não existe + lambda res: not res + )] + return desexcluir, criar + + +def get_sqls_desexcluir_criar(desexcluir, criar): + sqls_desexcluir = [ + 'update {} set ind_excluido = 0 where {} = {};'.format( + tabela_alvo, campo, valor) + for tabela_alvo, campo, valor in desexcluir] + return '\n'.join(sqls_desexcluir) From 131c8029d7fd7be18eb67ad25294d25e5cdc2987 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 15 Aug 2018 11:05:37 -0300 Subject: [PATCH 41/45] =?UTF-8?q?Protege=20refer=C3=AAncia=20de=20Autor=20?= =?UTF-8?q?para=20seu=20tipo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #2143 --- .../migrations/0019_auto_20180815_1025.py | 21 +++++++++++++++ sapl/base/models.py | 26 ++++++++----------- sapl/crud/base.py | 4 ++- 3 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 sapl/base/migrations/0019_auto_20180815_1025.py diff --git a/sapl/base/migrations/0019_auto_20180815_1025.py b/sapl/base/migrations/0019_auto_20180815_1025.py new file mode 100644 index 000000000..e96759e52 --- /dev/null +++ b/sapl/base/migrations/0019_auto_20180815_1025.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-08-15 13:25 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0018_auto_20180801_1652'), + ] + + operations = [ + migrations.AlterField( + model_name='autor', + name='tipo', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='base.TipoAutor', verbose_name='Tipo do Autor'), + ), + ] diff --git a/sapl/base/models.py b/sapl/base/models.py index fbfadd835..df8ae7c3f 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -5,6 +5,7 @@ from django.db import models from django.db.models.signals import post_migrate from django.db.utils import DEFAULT_DB_ALIAS from django.utils.translation import ugettext_lazy as _ + from sapl.utils import (LISTA_DE_UFS, YES_NO_CHOICES, get_settings_auth_user_model, models_with_gr_for_model) @@ -178,7 +179,8 @@ class Autor(models.Model): on_delete=models.SET_NULL, null=True) - tipo = models.ForeignKey(TipoAutor, verbose_name=_('Tipo do Autor')) + tipo = models.ForeignKey(TipoAutor, verbose_name=_('Tipo do Autor'), + on_delete=models.PROTECT) content_type = models.ForeignKey( ContentType, @@ -199,23 +201,17 @@ class Autor(models.Model): ordering = ('nome',) def __str__(self): - if self.autor_related: return str(self.autor_related) else: - if str(self.cargo): - return _('%(nome)s - %(cargo)s') % { - 'nome': self.nome, 'cargo': self.cargo} - else: - return str(self.nome) - """if str(self.tipo) == 'Parlamentar' and self.parlamentar: - return self.parlamentar.nome_parlamentar - elif str(self.tipo) == 'Comissao' and self.comissao: - return str(self.comissao) - elif str(self.tipo) == 'Partido' and self.partido: - return str(self.partido) - else: - """ + if self.nome: + if self.cargo: + return '{} - {}'.format(self.nome, self.cargo) + else: + return str(self.nome) + if self.user: + return str(self.user.username) + return '?' def cria_models_tipo_autor(app_config=None, verbosity=2, interactive=True, diff --git a/sapl/crud/base.py b/sapl/crud/base.py index 8bb8c3794..739fc4f37 100644 --- a/sapl/crud/base.py +++ b/sapl/crud/base.py @@ -851,7 +851,9 @@ class CrudDeleteView(PermissionRequiredContainerCrudMixin, é referenciado por outros registros:
\
    ' for i in err.protected_objects: - error_msg += '
  • ' + i.__str__() + '
  • ' + error_msg += '
  • {} - {}
  • '.format( + i._meta.verbose_name, i + ) error_msg += '
' messages.add_message(request, From 62c876fe35ba79e66cf8b9c24849f23478d9d2dc Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Wed, 15 Aug 2018 13:10:11 -0300 Subject: [PATCH 42/45] =?UTF-8?q?HOT-FIX=20-=20Teste=20audi=C3=AAncia=20(#?= =?UTF-8?q?2144)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adiciona mais um teste referente ao forms de audiencia * hotfix --- sapl/audiencia/tests/test_audiencia.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sapl/audiencia/tests/test_audiencia.py b/sapl/audiencia/tests/test_audiencia.py index f617d426a..5640b3d0d 100644 --- a/sapl/audiencia/tests/test_audiencia.py +++ b/sapl/audiencia/tests/test_audiencia.py @@ -3,6 +3,8 @@ from django.utils.translation import ugettext as _ from model_mommy import mommy from sapl.audiencia import forms +from sapl.audiencia.models import TipoAudienciaPublica +from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa @pytest.mark.django_db(transaction=False) def test_valida_campos_obrigatorios_audiencia_form(): @@ -19,3 +21,21 @@ def test_valida_campos_obrigatorios_audiencia_form(): assert errors['hora_inicio'] == [_('Este campo é obrigatório.')] assert len(errors) == 5 + + +@pytest.mark.django_db(transaction=False) +def test_audiencia_form_hora_invalida(): + tipo_materia = mommy.make(TipoMateriaLegislativa) + + tipo = mommy.make(TipoAudienciaPublica) + + form = forms.AudienciaForm(data={'nome': 'Nome da Audiencia', + 'tema': 'Tema da Audiencia', + 'tipo': tipo, + 'data': '2016-10-01', + 'hora_inicio': '10:00', + 'hora_fim': '9:00', + }) + assert not form.is_valid() + + \ No newline at end of file From 703fb0ceb30e5f42dbf2160e7ad869c409c4efdd Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Wed, 15 Aug 2018 14:48:32 -0300 Subject: [PATCH 43/45] =?UTF-8?q?Revert=20"hotfix=20-=20corrige=20duplica?= =?UTF-8?q?=C3=A7=C3=A3o=20de=20c=C3=B3digo=20(#2114)"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 9c2eb19762e7031812cf93b4118fa2d19cb2562a. --- sapl/comissoes/views.py | 21 +++++++++++-------- sapl/compilacao/models.py | 43 +++++++++++++++++---------------------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/sapl/comissoes/views.py b/sapl/comissoes/views.py index 699127409..78e639168 100644 --- a/sapl/comissoes/views.py +++ b/sapl/comissoes/views.py @@ -24,17 +24,18 @@ from .models import (CargoComissao, Comissao, Composicao, DocumentoAcessorio, Participacao, Periodo, Reuniao, TipoComissao) -def pegar_url(pk): +def pegar_url_composicao(pk): participacao = Participacao.objects.get(id=pk) - if participacao: - comp_pk = participacao.composicao.pk - url = reverse('sapl.comissoes:composicao_detail', kwargs={'pk': comp_pk}) - return url + comp_pk = participacao.composicao.pk + url = reverse('sapl.comissoes:composicao_detail', kwargs={'pk': comp_pk}) + return url + + +def pegar_url_reuniao(pk): documentoacessorio = DocumentoAcessorio.objects.get(id=pk) - if documentoacessorio: - r_pk = documentoacessorio.reuniao.pk - url = reverse('sapl.comissoes:reuniao_detail', kwargs={'pk': r_pk}) - return url + r_pk = documentoacessorio.reuniao.pk + url = reverse('sapl.comissoes:reuniao_detail', kwargs={'pk': r_pk}) + return url CargoCrud = CrudAux.build(CargoComissao, 'cargo_comissao') @@ -52,6 +53,8 @@ class PeriodoComposicaoCrud(CrudAux): class UpdateView(CrudAux.UpdateView): form_class = PeriodoForm + # class ListView(CrudAux.ListView): + class ParticipacaoCrud(MasterDetailCrud): model = Participacao diff --git a/sapl/compilacao/models.py b/sapl/compilacao/models.py index 4d7701529..6ffb738b1 100644 --- a/sapl/compilacao/models.py +++ b/sapl/compilacao/models.py @@ -1557,30 +1557,25 @@ class Dispositivo(BaseModel, TimestampedMixin): irmao.clean() irmao.save() - def get_niveis(self): - ## Próximo nível zero: - proxima_articulacao = Dispositivo.objects.order_by('ordem').filter( - ordem__gt=self.ordem, - nivel=0, - ta_id=self.ta_id).first() - if proxima_articulacao: - return proxima_articulacao - - ## Nível zero anterior: - anterior_articulacao = Dispositivo.objects.order_by('ordem').filter( - ordem__lt=self.ordem, - nivel=0, - ta_id=self.ta_id).last() - if anterior_articulacao: - return anterior_articulacao - - ## Nível zero: - niveis_zero = Dispositivo.objects.order_by('ordem').filter( - nivel=0, - ta_id=self.ta_id) - if niveis_zero: - return niveis_zero - + def get_proximo_nivel_zero(self): + proxima_articulacao = Dispositivo.objects.order_by('ordem').filter( + ordem__gt=self.ordem, + nivel=0, + ta_id=self.ta_id).first() + return proxima_articulacao + + def get_nivel_zero_anterior(self): + anterior_articulacao = Dispositivo.objects.order_by('ordem').filter( + ordem__lt=self.ordem, + nivel=0, + ta_id=self.ta_id).last() + return anterior_articulacao + + def get_niveis_zero(self): + niveis_zero = Dispositivo.objects.order_by('ordem').filter( + nivel=0, + ta_id=self.ta_id) + return niveis_zero # metodo obsoleto, foi acrescentado o campo auto_inserido no modelo def is_relative_auto_insert__obsoleto(self, perfil_pk=None): From 97fd7aeaabf963e79efc0a2f543c7a0a03abc9c0 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Wed, 15 Aug 2018 15:16:59 -0300 Subject: [PATCH 44/45] =?UTF-8?q?refatora=20sele=C3=A7=C3=A3o=20de=20dispo?= =?UTF-8?q?sitivos=20raizes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/compilacao/models.py | 30 +++++++------------ sapl/compilacao/views.py | 10 +++---- .../compilacao/dispositivo_form.html | 2 +- 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/sapl/compilacao/models.py b/sapl/compilacao/models.py index 6ffb738b1..28b963038 100644 --- a/sapl/compilacao/models.py +++ b/sapl/compilacao/models.py @@ -1465,7 +1465,7 @@ class Dispositivo(BaseModel, TimestampedMixin): tipo_dispositivo_id=self.tipo_dispositivo.pk)) else: # contagem continua restrita a articulacao - proxima_articulacao = self.get_proximo_nivel_zero() + proxima_articulacao = self.select_next_root() if proxima_articulacao is None: irmaos = list(Dispositivo.objects.filter( @@ -1557,25 +1557,15 @@ class Dispositivo(BaseModel, TimestampedMixin): irmao.clean() irmao.save() - def get_proximo_nivel_zero(self): - proxima_articulacao = Dispositivo.objects.order_by('ordem').filter( - ordem__gt=self.ordem, - nivel=0, - ta_id=self.ta_id).first() - return proxima_articulacao - - def get_nivel_zero_anterior(self): - anterior_articulacao = Dispositivo.objects.order_by('ordem').filter( - ordem__lt=self.ordem, - nivel=0, - ta_id=self.ta_id).last() - return anterior_articulacao - - def get_niveis_zero(self): - niveis_zero = Dispositivo.objects.order_by('ordem').filter( - nivel=0, - ta_id=self.ta_id) - return niveis_zero + def select_roots(self): + return Dispositivo.objects.order_by( + 'ordem').filter(nivel=0, ta_id=self.ta_id) + + def select_next_root(self): + return self.select_roots().filter(ordem__gt=self.ordem).first() + + def select_prev_root(self): + return self.select_roots().filter(ordem__lt=self.ordem).last() # metodo obsoleto, foi acrescentado o campo auto_inserido no modelo def is_relative_auto_insert__obsoleto(self, perfil_pk=None): diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index 0efa36be0..dac910cc2 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -1391,7 +1391,7 @@ class ActionsCommonsMixin: pkfilho = dp.pk dp = dp.dispositivo_pai - proxima_articulacao = dp.get_proximo_nivel_zero() + proxima_articulacao = dp.select_next_root() if proxima_articulacao is not None: parents = Dispositivo.objects.filter( @@ -1484,7 +1484,7 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin): data = {} if not base_anterior or base == base.get_raiz(): - base_anterior = base.get_nivel_zero_anterior() + base_anterior = base.select_prev_root() if not base_anterior: base_anterior = base data = self.get_json_for_refresh(base_anterior) @@ -1545,7 +1545,7 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin): print(e) base.delete() else: - proxima_articulacao = base.get_proximo_nivel_zero() + proxima_articulacao = base.select_next_root() if not bloco: # tranferir filhos para primeiro pai possível acima da base # de exclusão @@ -1703,7 +1703,7 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin): base_adicao = {} - nivel_zero_anterior = base.get_nivel_zero_anterior() + nivel_zero_anterior = base.select_prev_root() if nivel_zero_anterior: nivel_zero_anterior = nivel_zero_anterior.ordem else: @@ -2383,7 +2383,7 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin): if dp.nivel == 0: - proxima_articulacao = dp.get_proximo_nivel_zero() + proxima_articulacao = dp.select_next_root() if not proxima_articulacao: filhos_continuos = list(Dispositivo.objects.filter( diff --git a/sapl/templates/compilacao/dispositivo_form.html b/sapl/templates/compilacao/dispositivo_form.html index 0e1d1f0f0..15d383600 100644 --- a/sapl/templates/compilacao/dispositivo_form.html +++ b/sapl/templates/compilacao/dispositivo_form.html @@ -29,7 +29,7 @@