From 372690f56c226323ac0b99675bcbdb3ec06a7f89 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 18 Apr 2018 12:00:01 -0300 Subject: [PATCH 001/119] HOT-FIX: Fix #1872 --- sapl/sessao/forms.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index f05209229..aea3c5dbb 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -464,14 +464,13 @@ class OradorExpedienteForm(ModelForm): def __init__(self, *args, **kwargs): super(OradorExpedienteForm, self).__init__(*args, **kwargs) - legislatura_atual = [l for l in Legislatura.objects.all() if l.atual] + legislatura_vigente = SessaoPlenaria.objects.get(pk=kwargs['initial']['id_sessao']).legislatura - if legislatura_atual: - legislatura_atual = legislatura_atual[0] + if legislatura_vigente: self.fields['parlamentar'].queryset = \ Parlamentar.objects.filter(ativo=True, - mandato__legislatura=legislatura_atual - ).order_by('nome_parlamentar') + mandato__legislatura=legislatura_vigente + ).order_by('nome_parlamentar') class Meta: model = OradorExpediente From 997f87261af8f2d28c3ee77d6c749a9ebb8736cd Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 18 Apr 2018 12:13:33 -0300 Subject: [PATCH 002/119] Fixes #1897 --- sapl/sessao/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index b256db879..9f8f8aaa2 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -2596,7 +2596,7 @@ class PesquisarSessaoPlenariaView(FilterView): 'tipo', 'sessao_legislativa', 'legislatura') qs = qs.distinct().order_by( - '-legislatura__numero', '-data_inicio', '-numero') + '-legislatura__numero', '-data_inicio', '-hora_inicio') kwargs.update({ 'queryset': qs, From 7937b5480c3f099319ea92e2fd4cf516e2c262bd Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Wed, 18 Apr 2018 12:15:40 -0300 Subject: [PATCH 003/119] Fix #1895 (#1901) --- sapl/sessao/forms.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index aea3c5dbb..219e5b69b 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -472,6 +472,25 @@ class OradorExpedienteForm(ModelForm): mandato__legislatura=legislatura_vigente ).order_by('nome_parlamentar') + def clean(self): + super(OradorExpedienteForm, self).clean() + cleaned_data = self.cleaned_data + + if not self.is_valid(): + return self.cleaned_data + + sessao_id = self.initial['id_sessao'] + ordem = OradorExpediente.objects.filter( + sessao_plenaria_id=sessao_id, + numero_ordem=cleaned_data['numero_ordem'] + ).exists() + if ordem: + raise ValidationError(_( + 'Já existe orador nesta posição da ordem de pronunciamento')) + + return self.cleaned_data + + class Meta: model = OradorExpediente exclude = ['sessao_plenaria'] From 825e27c1dd44a041da729920a65a8ffde839d20e Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 5 Apr 2018 17:42:59 -0300 Subject: [PATCH 004/119] =?UTF-8?q?Adiciona=20mais=20propaga=C3=A7=C3=B5es?= =?UTF-8?q?=20de=20dele=C3=A7=C3=B5es=20pr=C3=A9-migra=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 9b2846fa7..6b10e51ee 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -201,7 +201,7 @@ class ForeignKeyFaltando(ObjectDoesNotExist): campo = campos_novos_para_antigos[self.field] _, tabela, campos_pk = get_estrutura_legado(self.field.model) pk = {c: getattr(self.old, c) for c in campos_pk} - sql = 'select * from {} where {}'.format( + sql = 'select * from {} where {};'.format( tabela, ' and '.join(['{} = {}'.format(k, v) for k, v in pk.items()])) return OrderedDict((('campo', campo), @@ -494,6 +494,8 @@ PROPAGACOES_DE_EXCLUSAO = [ ('parlamentar', 'dependente', 'cod_parlamentar'), ('parlamentar', 'filiacao', 'cod_parlamentar'), ('parlamentar', 'mandato', 'cod_parlamentar'), + ('parlamentar', 'composicao_mesa', 'cod_parlamentar'), + ('parlamentar', 'composicao_comissao', 'cod_parlamentar'), # comissao ('comissao', 'composicao_comissao', 'cod_comissao'), @@ -518,6 +520,11 @@ PROPAGACOES_DE_EXCLUSAO = [ ('materia_legislativa', 'anexada', 'cod_materia_principal'), ('materia_legislativa', 'anexada', 'cod_materia_anexada'), ('materia_legislativa', 'documento_acessorio', 'cod_materia'), + ('materia_legislativa', 'numeracao', 'cod_materia'), + + # norma + ('norma_juridica', 'vinculo_norma_juridica', 'cod_norma_referente'), + ('norma_juridica', 'vinculo_norma_juridica', 'cod_norma_referida'), # documento administrativo ('documento_administrativo', 'tramitacao_administrativo', 'cod_documento'), @@ -800,7 +807,7 @@ def migrar_dados(interativo=True): arq_ocorrencias = dir_ocorrencias.child( nome_banco_legado + '.yaml') with open(arq_ocorrencias, 'w') as arq: - dump = yaml.dump(dict(ocorrencias), allow_unicode=True) + dump = yaml.dump(dict(ocorrencias), allow_unicode=True, width=1000) arq.write(dump.replace('\n- ', '\n\n- ')) info('Ocorrências salvas em\n {}'.format(arq_ocorrencias)) From 09085b88a2780fc76ff9194d1298792812a65740 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 6 Apr 2018 12:55:08 -0300 Subject: [PATCH 005/119] Corrige rehash de senhas importadas do zope --- sapl/hashers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sapl/hashers.py b/sapl/hashers.py index e80642def..3e9cf6c5f 100644 --- a/sapl/hashers.py +++ b/sapl/hashers.py @@ -46,11 +46,12 @@ ZOPE_SHA1_PREFIX = '{SSHA}' def zope_encoded_password_to_django(encoded): "Migra um hash de senha do zope para uso com o ZopeSHA1PasswordHasher" - if encoded.startswith(ZOPE_SHA1_PREFIX): + if encoded and encoded.startswith(ZOPE_SHA1_PREFIX): data = encoded[len(ZOPE_SHA1_PREFIX):] salt = get_salt_from_zope_sha1(data) hasher = ZopeSHA1PasswordHasher() return super(ZopeSHA1PasswordHasher, hasher).encode(data, salt) else: # assume it's a plain password and use the default hashing + # a None password blocks login, forcing a password reset return make_password(encoded) From 1cf2f35def5025bcf9b3bd3ee9e1c184a5e317c5 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 6 Apr 2018 19:08:54 -0300 Subject: [PATCH 006/119] =?UTF-8?q?Corrige=20caminhos=20de=20arquivos=20na?= =?UTF-8?q?=20migra=C3=A7=C3=A3o=20de=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao.py | 6 -- sapl/legacy/migracao_documentos.py | 134 ++++++++--------------------- 2 files changed, 36 insertions(+), 104 deletions(-) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index 2690e9a53..be8830aa8 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -14,12 +14,6 @@ def migrar(interativo=False): migrar_documentos() -# fonte: https://stackoverflow.com/a/17081026/1877490 -def make_tarfile(output_filename, source_dir): - with tarfile.open(output_filename, "w:gz") as tar: - tar.add(source_dir, arcname=os.path.basename(source_dir)) - - def gerar_pacote(): banco = settings.DATABASES['legacy']['NAME'] diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index 9ae46ef5d..a94b9160a 100644 --- a/sapl/legacy/migracao_documentos.py +++ b/sapl/legacy/migracao_documentos.py @@ -1,12 +1,12 @@ -import mimetypes import os import re from glob import glob import yaml +from django.db import transaction from sapl.base.models import CasaLegislativa -from sapl.legacy.migracao_dados import exec_legado, warn +from sapl.legacy.migracao_dados import exec_legado from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa, Proposicao) from sapl.norma.models import NormaJuridica @@ -16,88 +16,26 @@ from sapl.protocoloadm.models import (DocumentoAcessorioAdministrativo, from sapl.sessao.models import SessaoPlenaria from sapl.settings import MEDIA_ROOT - # MIGRAÇÃO DE DOCUMENTOS ################################################### -def get_ano(obj): - return [obj.ano] - - -def ___(obj): - return [] - - DOCS = { - CasaLegislativa: [ - ('logotipo', - 'props_sapl/{}.*', - 'public/casa/logotipo/', - ___) - ], - Parlamentar: [ - ('fotografia', - 'parlamentar/fotos/{}_foto_parlamentar', - 'public/parlamentar/{0}/', - ___) - ], - MateriaLegislativa: [ - ('texto_original', - 'materia/{}_texto_integral', - 'public/materialegislativa/{1}/{0}/', - get_ano) - ], - DocumentoAcessorio: [ - ('arquivo', - 'materia/{}', - 'public/documentoacessorio/{1}/{0}/', - lambda obj: [obj.materia.ano]) - ], - NormaJuridica: [ - ('texto_integral', - 'norma_juridica/{}_texto_integral', - 'public/normajuridica/{1}/{0}/', - get_ano) - ], - SessaoPlenaria: [ - ('upload_pauta', - 'pauta_sessao/{}_pauta_sessao', - 'public/sessaoplenaria/{0}/pauta/', - ___), - ('upload_ata', - 'ata_sessao/{}_ata_sessao', - 'public/sessaoplenaria/{0}/ata/', - ___), - ('upload_anexo', - 'anexo_sessao/{}_texto_anexado', - 'public/sessaoplenaria/{0}/anexo/', - ___) - ], - Proposicao: [ - ('texto_original', - 'proposicao/{}', - 'private/proposicao/{0}/', - get_ano) - ], - DocumentoAdministrativo: [ - ('texto_integral', - 'administrativo/{}_texto_integral', - 'private/documentoadministrativo/{0}/', - get_ano) - ], - DocumentoAcessorioAdministrativo: [ - ('arquivo', - 'administrativo/{}', - 'private/documentoacessorioadministrativo/{0}/', - ___) - ], + CasaLegislativa: [('logotipo', 'props_sapl/{}.*')], + Parlamentar: [('fotografia', 'parlamentar/fotos/{}_foto_parlamentar')], + MateriaLegislativa: [('texto_original', 'materia/{}_texto_integral')], + DocumentoAcessorio: [('arquivo', 'materia/{}')], + NormaJuridica: [('texto_integral', 'norma_juridica/{}_texto_integral')], + SessaoPlenaria: [('upload_pauta', 'pauta_sessao/{}_pauta_sessao'), + ('upload_ata', 'ata_sessao/{}_ata_sessao'), + ('upload_anexo', 'anexo_sessao/{}_texto_anexado')], + Proposicao: [('texto_original', 'proposicao/{}')], + DocumentoAdministrativo: [('texto_integral', + 'administrativo/{}_texto_integral')], + DocumentoAcessorioAdministrativo: [('arquivo', 'administrativo/{}')], } -DOCS = {model: [(campo, - os.path.join('sapl_documentos', origem), - os.path.join('sapl', destino), - get_extra_args) - for campo, origem, destino, get_extra_args in campos] +DOCS = {model: [(campo, os.path.join('sapl_documentos', origem)) + for campo, origem, in campos] for model, campos in DOCS.items()} @@ -141,11 +79,13 @@ def migrar_propriedades_da_casa(): [(casa.municipio, casa.uf)] = exec_legado(sql_localidade) print('.... Migrando logotipo da casa ....') - [(_, origem, destino, __)] = DOCS[CasaLegislativa] + [(campo, origem)] = DOCS[CasaLegislativa] # a extensão do logo pode ter sido ajustada pelo tipo real do arquivo id_logo = os.path.splitext(propriedades['id_logo'])[0] [origem] = glob(em_media(origem.format(id_logo))) - destino = os.path.join(destino, os.path.basename(origem)) + destino = os.path.join( + CasaLegislativa._meta.get_field(campo).upload_to, + os.path.basename(origem)) mover_documento(origem, destino) casa.logotipo = destino casa.save() @@ -153,36 +93,36 @@ def migrar_propriedades_da_casa(): def migrar_docs_por_ids(model): - for campo, base_origem, base_destino, get_extra_args in DOCS[model]: + for campo, base_origem in DOCS[model]: print('#### Migrando {} de {} ####'.format(campo, model.__name__)) dir_origem, nome_origem = os.path.split(em_media(base_origem)) nome_origem = nome_origem.format('(\d+)') pat = re.compile('^{}\.\w+$'.format(nome_origem)) - if not os.path.isdir(dir_origem): print(' >>> O diretório {} não existe! Abortado.'.format( dir_origem)) continue - for arq in os.listdir(dir_origem): - match = pat.match(arq) - if match: + matches = [pat.match(arq) for arq in os.listdir(dir_origem)] + ids_origens = [(int(m.group(1)), + os.path.join(dir_origem, m.group(0))) + for m in matches if m] + objetos = {obj.id: obj for obj in model.objects.all()} + upload_to = model._meta.get_field(campo).upload_to + + with transaction.atomic(): + for id, origem in ids_origens: # associa documento ao objeto - origem = os.path.join(dir_origem, match.group(0)) - id = match.group(1) - try: - obj = model.objects.get(pk=id) - except model.DoesNotExist: - msg = ' {} (pk={}) não encontrado para documento em [{}]' - print(msg.format(model.__name__, id, origem)) - else: - destino = os.path.join( - base_destino.format(id, *get_extra_args(obj)), - os.path.basename(origem)) + obj = objetos.get(id) + if obj: + destino = upload_to(obj, os.path.basename(origem)) mover_documento(origem, destino) setattr(obj, campo, destino) obj.save() + else: + msg = ' {} (pk={}) não encontrado para documento em [{}]' + print(msg.format(model.__name__, id, origem)) def migrar_documentos(): @@ -215,5 +155,3 @@ def migrar_documentos(): print('\n#### Encerrado ####\n\n' '{} documentos sobraram sem ser migrados!!!'.format( len(sobrando))) - for doc in sobrando: - print(' {}'. format(doc)) From 500574a82044fcf410178d874c6206837e50e02c Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 9 Apr 2018 14:42:35 -0300 Subject: [PATCH 007/119] =?UTF-8?q?Usa=20pretty-yaml=20p=20registro=20de?= =?UTF-8?q?=20ocorr=C3=AAncias=20de=20migra=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements/migration-requirements.txt | 1 + sapl/legacy/migracao_dados.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/requirements/migration-requirements.txt b/requirements/migration-requirements.txt index d5793dad8..fbe9543e2 100644 --- a/requirements/migration-requirements.txt +++ b/requirements/migration-requirements.txt @@ -1,2 +1,3 @@ -r dev-requirements.txt mysqlclient==1.3.12 +pyaml diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 6b10e51ee..dd6e4f8d1 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -8,6 +8,7 @@ from operator import xor from subprocess import PIPE, call import pkg_resources +import pyaml import pytz import reversion import yaml @@ -807,8 +808,7 @@ def migrar_dados(interativo=True): arq_ocorrencias = dir_ocorrencias.child( nome_banco_legado + '.yaml') with open(arq_ocorrencias, 'w') as arq: - dump = yaml.dump(dict(ocorrencias), allow_unicode=True, width=1000) - arq.write(dump.replace('\n- ', '\n\n- ')) + pyaml.dump(ocorrencias, arq, vspacing=1) info('Ocorrências salvas em\n {}'.format(arq_ocorrencias)) # recria tipos de autor padrão que não foram criados pela migração From 70bc3148885f1c98fc8ec4beda7505b312733625 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 9 Apr 2018 14:57:02 -0300 Subject: [PATCH 008/119] Ignora app legacy no shell_plus --- sapl/legacy_migration_settings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/legacy_migration_settings.py b/sapl/legacy_migration_settings.py index 7d911bf7e..0d8844147 100644 --- a/sapl/legacy_migration_settings.py +++ b/sapl/legacy_migration_settings.py @@ -33,3 +33,5 @@ DEBUG = True # delisga indexação fulltext em tempo real HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.BaseSignalProcessor' + +SHELL_PLUS_DONT_LOAD = ['legacy'] From 5ef440685eda05e1052acd9d585b2b337fc76977 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 9 Apr 2018 18:05:11 -0300 Subject: [PATCH 009/119] Adiciona gravacao de marco da migracao --- sapl/legacy/migracao_dados.py | 44 ++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index dd6e4f8d1..ceaea8633 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -1,3 +1,4 @@ +import datetime import re import traceback from collections import OrderedDict, defaultdict, namedtuple @@ -19,6 +20,7 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.db import connections, transaction from django.db.models import Max, Q +from pyaml import UnsafePrettyYAMLDumper from unipath import Path from sapl.base.models import AppConfig as AppConf @@ -823,7 +825,7 @@ def move_para_depois_de(lista, movido, referencias): return lista -def migrar_todos_os_models(): +def get_models_a_migrar(): models = [model for app in appconfs for model in app.models.values() if model in field_renames] # Devido à referência TipoProposicao.tipo_conteudo_related @@ -836,7 +838,11 @@ def migrar_todos_os_models(): move_para_depois_de(models, Proposicao, [MateriaLegislativa, DocumentoAdministrativo]) - for model in models: + return models + + +def migrar_todos_os_models(): + for model in get_models_a_migrar(): migrar_model(model) @@ -1233,4 +1239,36 @@ AJUSTE_DEPOIS_SALVAR = { NormaJuridica: adjust_normajuridica_depois_salvar, } -# CHECKS #################################################################### + +# MARCO ###################################################################### + +TIME_FORMAT = '%H:%M:%S' + + +def time_representer(dumper, data): + return dumper.represent_scalar('!time', data.strftime(TIME_FORMAT)) +UnsafePrettyYAMLDumper.add_representer(datetime.time, time_representer) + + +def time_constructor(loader, node): + value = loader.construct_scalar(node) + return datetime.datetime.strptime(value, TIME_FORMAT).time() +yaml.add_constructor(u'!time', time_constructor) + + +DIR_MARCO = Path(DIR_DADOS_MIGRACAO, 'marcos', nome_banco_legado) + + +def grava_marco_base(): + user_model = get_user_model() + models = get_models_a_migrar() + [ + Composicao, user_model, Group, ContentType] + for model in models: + info('Gravando marco de [{}]'.format(model.__name__)) + dir_model = Path( + DIR_MARCO, 'dados', model._meta.app_label, model.__name__) + dir_model.mkdir(parents=True) + for data in model.objects.all().values(): + nome_arq = Path(dir_model, data['id']) + with open(nome_arq, 'w') as arq: + pyaml.dump(data, arq) From acc9cbe2626cd2469d94fd80531e2af310e369ac Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 9 Apr 2018 18:12:24 -0300 Subject: [PATCH 010/119] =?UTF-8?q?Move=20migrate=20p=20script=20de=20recr?= =?UTF-8?q?ia=C3=A7=C3=A3o=20de=20bancos=20postgres?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/migra_um_db.sh | 5 ----- sapl/legacy/scripts/recria_um_db_postgres.sh | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sapl/legacy/scripts/migra_um_db.sh b/sapl/legacy/scripts/migra_um_db.sh index ed4db9662..b5b336cd2 100755 --- a/sapl/legacy/scripts/migra_um_db.sh +++ b/sapl/legacy/scripts/migra_um_db.sh @@ -32,11 +32,6 @@ if [ $# -ge 2 ]; then echo "O banco legado foi restaurado" |& tee -a $LOG echo >> $LOG - echo "--- DJANGO MIGRATE ---" | tee -a $LOG - echo >> $LOG - DATABASE_NAME=$1 ./manage.py migrate --settings sapl.legacy_migration_settings - echo >> $LOG - echo "--- MIGRACAO ---" | tee -a $LOG echo >> $LOG DATABASE_NAME=$1 ./manage.py migracao_25_31 --force --dados --settings sapl.legacy_migration_settings 2>&1 | tee -a $LOG diff --git a/sapl/legacy/scripts/recria_um_db_postgres.sh b/sapl/legacy/scripts/recria_um_db_postgres.sh index 3ff66e8f3..98defaaa6 100755 --- a/sapl/legacy/scripts/recria_um_db_postgres.sh +++ b/sapl/legacy/scripts/recria_um_db_postgres.sh @@ -4,3 +4,8 @@ echo "Database $1" sudo -u postgres psql -c "drop DATABASE if exists $1" sudo -u postgres psql -c "CREATE DATABASE $1 WITH OWNER = sapl ENCODING = 'UTF8' TABLESPACE = pg_default LC_COLLATE = 'pt_BR.UTF-8' LC_CTYPE = 'pt_BR.UTF-8' CONNECTION LIMIT = -1 TEMPLATE template0;" + + +echo "--- DJANGO MIGRATE ---" | tee -a $LOG +DATABASE_NAME=$1 ./manage.py migrate --settings sapl.legacy_migration_settings + From 444e9dacad43b672975bc75e392dc6f0366b451c Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 9 Apr 2018 18:27:31 -0300 Subject: [PATCH 011/119] Atualiza assinatura de LegacyRouter.allow_migrate --- sapl/legacy/router.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/legacy/router.py b/sapl/legacy/router.py index 68b235059..1aa51a46b 100644 --- a/sapl/legacy/router.py +++ b/sapl/legacy/router.py @@ -16,7 +16,7 @@ class LegacyRouter: return True return None - def allow_migrate(self, db, model): - if model._meta.app_label == 'legacy': + def allow_migrate(self, db, app_label, model_name=None, **hints): + if app_label == 'legacy': return False return None From 27b4096f46c6b5df9be66d0e39eabbdbfef38777 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 10 Apr 2018 13:15:02 -0300 Subject: [PATCH 012/119] Corrige ajuste de tipo de proposicao antes de salvar --- sapl/legacy/migracao_dados.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index ceaea8633..f0bf710f0 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -146,6 +146,15 @@ CAMPOS_VIRTUAIS_PROPOSICAO = { for campo_virtual in CAMPOS_VIRTUAIS_PROPOSICAO.values(): campos_novos_para_antigos[campo_virtual] = 'cod_mat_ou_doc' + +CAMPOS_VIRTUAIS_TIPO_PROPOSICAO = { + 'M': CampoVirtual(TipoProposicao, TipoMateriaLegislativa), + 'D': CampoVirtual(TipoProposicao, TipoDocumento) +} +for campo_virtual in CAMPOS_VIRTUAIS_TIPO_PROPOSICAO.values(): + campos_novos_para_antigos[campo_virtual] = 'tip_mat_ou_doc' + + # campos virtuais de Autor para funcionar com get_fk_related CAMPOS_VIRTUAIS_AUTOR = {related: CampoVirtual(Autor, related) for related in (Parlamentar, Comissao, Partido)} @@ -1074,22 +1083,16 @@ def adjust_tipoafastamento(new, old): new.indicador = 'F' -TIPO_MATERIA_OU_TIPO_DOCUMENTO = {'M': TipoMateriaLegislativa, - 'D': TipoDocumento} +def set_generic_fk(new, campo_virtual, old): + new.content_type = content_types[campo_virtual.related_model] + new.object_id = get_fk_related(campo_virtual, old) def adjust_tipoproposicao(new, old): "Aponta para o tipo relacionado de matéria ou documento" - value = old.tip_mat_ou_doc - model_tipo = TIPO_MATERIA_OU_TIPO_DOCUMENTO[old.ind_mat_ou_doc] - tipo = model_tipo.objects.filter(pk=value) - if tipo: - new.tipo_conteudo_related = tipo[0] - else: - raise ForeignKeyFaltando( - field=TipoProposicao.tipo_conteudo_related, - value=(model_tipo.__name__, value), - label={'ind_mat_ou_doc': old.ind_mat_ou_doc}) + if old.tip_mat_ou_doc: + campo_virtual = CAMPOS_VIRTUAIS_TIPO_PROPOSICAO[old.ind_mat_ou_doc] + set_generic_fk(new, campo_virtual, old) def adjust_proposicao_antes_salvar(new, old): @@ -1098,8 +1101,7 @@ def adjust_proposicao_antes_salvar(new, old): if old.cod_mat_ou_doc: tipo_mat_ou_doc = type(new.tipo.tipo_conteudo_related) campo_virtual = CAMPOS_VIRTUAIS_PROPOSICAO[tipo_mat_ou_doc] - new.content_type = content_types[campo_virtual.related_model] - new.object_id = get_fk_related(campo_virtual, old) + set_generic_fk(new, campo_virtual, old) def adjust_statustramitacao(new, old): From dd8ac9203b728b20e12c0a3300ef97ea6f99b76f Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 10 Apr 2018 13:15:41 -0300 Subject: [PATCH 013/119] =?UTF-8?q?Executa=20ajustes=20pr=C3=A9-migra?= =?UTF-8?q?=C3=A7=C3=A3o=20se=20existirem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index f0bf710f0..9363e7464 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -782,6 +782,12 @@ def populate_renamed_fields(new, old): def migrar_dados(interativo=True): + # executa ajustes pré-migração, se existirem + arq_ajustes_pre_migracao = DIR_DADOS_MIGRACAO.child( + 'ajustes_pre_migracao', '{}.sql'.format(sigla_casa)) + if arq_ajustes_pre_migracao.exists(): + exec_legado(arq_ajustes_pre_migracao.read_file()) + uniformiza_banco() # excluindo database antigo. From d7af0598eebaa8a6678f153ff1a5566738cccb6f Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 10 Apr 2018 14:25:21 -0300 Subject: [PATCH 014/119] Garante coluna no legado materia_legislativa.txt_resultado --- sapl/legacy/migracao_dados.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 9363e7464..52adfd2f1 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -567,6 +567,9 @@ def uniformiza_banco(): garante_coluna_no_legado('tipo_materia_legislativa', 'quorum_minimo_votacao int(11) NULL') + garante_coluna_no_legado('materia_legislativa', + 'txt_resultado TEXT NULL') + # Cria campos cod_presenca_sessao (sendo a nova PK da tabela) # e dat_sessao em sessao_plenaria_presenca if not existe_coluna_no_legado('sessao_plenaria_presenca', From 5370641ceb1cf5809ba7fa3df41079c9e7be0d4d Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 10 Apr 2018 15:06:39 -0300 Subject: [PATCH 015/119] Aumenta tamanho de numero_origem_externa em MateriaLegislativa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Algumas bases do sapl 2.5 têm esse campo com tamanho 9 --- sapl/legacy/models.py | 2 +- .../migrations/0028_auto_20180418_1629.py | 20 +++++++++++++++++++ sapl/materia/models.py | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 sapl/materia/migrations/0028_auto_20180418_1629.py diff --git a/sapl/legacy/models.py b/sapl/legacy/models.py index 4c459c9dd..7d341624d 100644 --- a/sapl/legacy/models.py +++ b/sapl/legacy/models.py @@ -433,7 +433,7 @@ class MateriaLegislativa(models.Model): cod_regime_tramitacao = models.IntegerField() dat_publicacao = models.DateField(blank=True, null=True) tip_origem_externa = models.IntegerField(blank=True, null=True) - num_origem_externa = models.CharField(max_length=5, blank=True, null=True) + num_origem_externa = models.CharField(max_length=10, blank=True, null=True) ano_origem_externa = models.SmallIntegerField(blank=True, null=True) dat_origem_externa = models.DateField(blank=True, null=True) cod_local_origem_externa = models.IntegerField(blank=True, null=True) diff --git a/sapl/materia/migrations/0028_auto_20180418_1629.py b/sapl/materia/migrations/0028_auto_20180418_1629.py new file mode 100644 index 000000000..c082ce1e6 --- /dev/null +++ b/sapl/materia/migrations/0028_auto_20180418_1629.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-04-18 19:29 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0027_auto_20180409_1443'), + ] + + operations = [ + migrations.AlterField( + model_name='materialegislativa', + name='numero_origem_externa', + field=models.CharField(blank=True, max_length=10, verbose_name='Número'), + ), + ] diff --git a/sapl/materia/models.py b/sapl/materia/models.py index ce4690c39..a1571072a 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -167,7 +167,7 @@ class MateriaLegislativa(models.Model): on_delete=models.PROTECT, verbose_name=_('Tipo')) numero_origem_externa = models.CharField( - max_length=5, blank=True, verbose_name=_('Número')) + max_length=10, blank=True, verbose_name=_('Número')) ano_origem_externa = models.PositiveSmallIntegerField( blank=True, null=True, verbose_name=_('Ano'), choices=RANGE_ANOS) data_origem_externa = models.DateField( From 0e8ff2e9871d8c855b53a0478c05cf7b3a0bc6a8 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 11 Apr 2018 15:43:52 -0300 Subject: [PATCH 016/119] Exporta docs do zope como repo git --- .../scripts/exporta_zope/exporta_zope.py | 29 ++++++++++++++++--- .../scripts/exporta_zope/requirements.txt | 2 ++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 11ff1ecbb..b3a4622b2 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -12,10 +12,12 @@ from collections import defaultdict from contextlib import contextmanager from functools import partial +import git import magic import yaml import ZODB.DB import ZODB.FileStorage +from unipath import Path from ZODB.broken import Broken EXTENSOES = { @@ -270,7 +272,7 @@ def dump_usuarios(sapl, path): save_as_yaml(path, 'usuarios.yaml', users) -def dump_sapl(data_fs_path, destino='../../../../media'): +def _dump_sapl(data_fs_path, destino='../../../../media'): app, close_db = get_app(data_fs_path) try: sapl = find_sapl(app) @@ -288,9 +290,28 @@ def dump_sapl(data_fs_path, destino='../../../../media'): close_db() +DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() + + +def dump_sapl(sigla): + data_fs_path = DIR_DADOS_MIGRACAO.child('datafs', + 'Data_cm_{}.fs'.format(sigla)) + nome_banco_legado = 'sapl_cm_{}'.format(sigla) + destino = DIR_DADOS_MIGRACAO.child('repos', nome_banco_legado) + destino.mkdir(parents=True) + repo = git.Repo.init(destino) + assert not repo.index.diff(None) # o repo não tem mudanças pendentes + _dump_sapl(data_fs_path, destino) + # grava mundaças + repo.git.add(A=True) + if 'master' not in repo.heads or repo.index.diff('HEAD'): + # se de fato existe mudança + repo.index.commit('Exporta documentos do zope') + + if __name__ == "__main__": if len(sys.argv) == 2: - data_fs_path = sys.argv[1] - dump_sapl(data_fs_path) + sigla = sys.argv[1] + dump_sapl(sigla) else: - print('Uso: python exporta_zope ') + print('Uso: python exporta_zope ') diff --git a/sapl/legacy/scripts/exporta_zope/requirements.txt b/sapl/legacy/scripts/exporta_zope/requirements.txt index 4794267ae..421005181 100644 --- a/sapl/legacy/scripts/exporta_zope/requirements.txt +++ b/sapl/legacy/scripts/exporta_zope/requirements.txt @@ -1,3 +1,5 @@ # ZODB version 3.7.4 PyYAML==3.12 ZODB==5.3.0 +Unipath==1.1 +GitPython==2.1.9 From a9b8d4fbd42d283045b479ed0e2c28d3983bc0b8 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 11 Apr 2018 16:47:45 -0300 Subject: [PATCH 017/119] =?UTF-8?q?Adiciona=20tipo=20mp4=20=C3=A0=20export?= =?UTF-8?q?a=C3=A7=C3=A3o=20de=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index b3a4622b2..18a5bc3ef 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -40,6 +40,7 @@ EXTENSOES = { 'image/tiff': '.tiff', 'application/tiff': '.tiff', 'audio/x-wav': '.wav', + 'video/mp4': '.mp4', # TODO rever... 'text/richtext': '.rtf', @@ -273,6 +274,7 @@ def dump_usuarios(sapl, path): def _dump_sapl(data_fs_path, destino='../../../../media'): + assert Path(data_fs_path).exists() app, close_db = get_app(data_fs_path) try: sapl = find_sapl(app) @@ -296,6 +298,7 @@ DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() def dump_sapl(sigla): data_fs_path = DIR_DADOS_MIGRACAO.child('datafs', 'Data_cm_{}.fs'.format(sigla)) + assert data_fs_path.exists() nome_banco_legado = 'sapl_cm_{}'.format(sigla) destino = DIR_DADOS_MIGRACAO.child('repos', nome_banco_legado) destino.mkdir(parents=True) From a1a5dda83b7b73ac75ca9e8a9c67f37f2999178e Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 12 Apr 2018 15:23:12 -0300 Subject: [PATCH 018/119] Grava nomes dos docs exportados --- .../scripts/exporta_zope/exporta_zope.py | 22 ++++++++++++++++++- .../scripts/exporta_zope/requirements.txt | 7 +++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 18a5bc3ef..19186a170 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -14,6 +14,7 @@ from functools import partial import git import magic +import pyaml import yaml import ZODB.DB import ZODB.FileStorage @@ -78,6 +79,9 @@ def guess_extension(caminho): raise Exception(msg, e) +nomes_arquivos_exportados = {} + + def dump_file(doc, path): name = doc['__name__'] fullname = os.path.join(path, name) @@ -112,6 +116,7 @@ def dump_file(doc, path): # trocamos a extensão pela adivinhada final_name = base + extension os.rename(fullname, final_name) + nomes_arquivos_exportados[fullname] = final_name print(final_name) return name @@ -273,9 +278,23 @@ def dump_usuarios(sapl, path): save_as_yaml(path, 'usuarios.yaml', users) +def grava_nomes_arquivos_exportados(destino): + """Grava nomes dos arquivos exportados (originais -> definitivos) + """ + destino = Path(destino) + + def rel(caminho): + return str(destino.rel_path_to(caminho)) + + with open(destino.child('arquivos_exportados.yaml'), 'w') as arq: + nomes = {rel(k): rel(v) for k, v in nomes_arquivos_exportados.items()} + pyaml.dump(nomes, arq) + + def _dump_sapl(data_fs_path, destino='../../../../media'): assert Path(data_fs_path).exists() app, close_db = get_app(data_fs_path) + nomes_arquivos_exportados.clear() # apaga nomes dos arquivos migrados try: sapl = find_sapl(app) # extrai folhas XSLT @@ -288,6 +307,7 @@ def _dump_sapl(data_fs_path, destino='../../../../media'): with logando_nao_identificados(): dump_folder(docs, destino) dump_propriedades(docs, destino) + grava_nomes_arquivos_exportados(destino) finally: close_db() @@ -298,7 +318,7 @@ DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() def dump_sapl(sigla): data_fs_path = DIR_DADOS_MIGRACAO.child('datafs', 'Data_cm_{}.fs'.format(sigla)) - assert data_fs_path.exists() + assert data_fs_path.exists(), 'Origem não existe: {}'.format(data_fs_path) nome_banco_legado = 'sapl_cm_{}'.format(sigla) destino = DIR_DADOS_MIGRACAO.child('repos', nome_banco_legado) destino.mkdir(parents=True) diff --git a/sapl/legacy/scripts/exporta_zope/requirements.txt b/sapl/legacy/scripts/exporta_zope/requirements.txt index 421005181..c7aa86b4f 100644 --- a/sapl/legacy/scripts/exporta_zope/requirements.txt +++ b/sapl/legacy/scripts/exporta_zope/requirements.txt @@ -1,5 +1,6 @@ # ZODB version 3.7.4 -PyYAML==3.12 ZODB==5.3.0 -Unipath==1.1 -GitPython==2.1.9 +PyYAML +Unipath +GitPython +pyaml From d7e61137e0d72fe3d430369c2ffafa5b043b7c29 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 12 Apr 2018 19:31:48 -0300 Subject: [PATCH 019/119] =?UTF-8?q?Adiciona=20mais=20tipos=20de=20arquivo?= =?UTF-8?q?=20=C3=A0=20exporta=C3=A7=C3=A3o=20de=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 19186a170..3e7f20613 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -42,6 +42,8 @@ EXTENSOES = { 'application/tiff': '.tiff', 'audio/x-wav': '.wav', 'video/mp4': '.mp4', + 'image/x-icon': '.ico', + 'application/vnd.oasis.opendocument.text-template': '.ott', # TODO rever... 'text/richtext': '.rtf', From 1b26489baa191a59ef20f33401bfb17a88acf5ac Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 13 Apr 2018 10:55:28 -0300 Subject: [PATCH 020/119] =?UTF-8?q?Garante=20grava=C3=A7=C3=A3o=20de=20nom?= =?UTF-8?q?es=20de=20arqs=20exportados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 3e7f20613..e27ea974d 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -309,9 +309,9 @@ def _dump_sapl(data_fs_path, destino='../../../../media'): with logando_nao_identificados(): dump_folder(docs, destino) dump_propriedades(docs, destino) - grava_nomes_arquivos_exportados(destino) finally: close_db() + grava_nomes_arquivos_exportados(destino) DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() From d5bcea3ed9cfb588b24d19c3ef3d92e6433fc0e9 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 16 Apr 2018 16:17:26 -0300 Subject: [PATCH 021/119] Usa git annex --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index e27ea974d..ffcbc2d8c 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -317,6 +317,10 @@ def _dump_sapl(data_fs_path, destino='../../../../media'): DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() +def repo_execute(repo, cmd): + return repo.git.execute(cmd.split()) + + def dump_sapl(sigla): data_fs_path = DIR_DADOS_MIGRACAO.child('datafs', 'Data_cm_{}.fs'.format(sigla)) @@ -325,9 +329,10 @@ def dump_sapl(sigla): destino = DIR_DADOS_MIGRACAO.child('repos', nome_banco_legado) destino.mkdir(parents=True) repo = git.Repo.init(destino) - assert not repo.index.diff(None) # o repo não tem mudanças pendentes _dump_sapl(data_fs_path, destino) # grava mundaças + repo_execute(repo, 'git annex init') + repo_execute(repo, 'git annex add sapl_documentos') repo.git.add(A=True) if 'master' not in repo.heads or repo.index.diff('HEAD'): # se de fato existe mudança From 87c7e82fd2ac434ea0f4031538cf45d4114770d9 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 18 Apr 2018 13:52:34 -0300 Subject: [PATCH 022/119] Salva apenas arquivos diferentes para o annex --- .../scripts/exporta_zope/exporta_zope.py | 150 +++++++++--------- 1 file changed, 79 insertions(+), 71 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index ffcbc2d8c..2c687bc07 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -5,6 +5,8 @@ # Esse script precisa rodar em python 2 # e depende apenas do descrito no arquivo requiments.txt +import cStringIO +import hashlib import mimetypes import os import sys @@ -16,9 +18,10 @@ import git import magic import pyaml import yaml +from unipath import Path + import ZODB.DB import ZODB.FileStorage -from unipath import Path from ZODB.broken import Broken EXTENSOES = { @@ -62,29 +65,25 @@ def br(obj): return obj -def guess_extension(caminho): - mime = magic.from_file(caminho, mime=True) +def guess_extension(fullname, buffer): + mime = magic.from_buffer(buffer, mime=True) try: return EXTENSOES[mime] except KeyError as e: - msg = '\n'.join([ - 'Extensão não conhecida para o arquivo:', - caminho, - 'E mimetype:', - mime, - ' Algumas possibilidades são:', ] + + possibilidades = '\n'.join( [" '{}': '{}',".format(mime, ext) - for ext in mimetypes.guess_all_extensions(mime)] + - ['Atualize o código do dicionário EXTENSOES!'] - ) + for ext in mimetypes.guess_all_extensions(mime)]) + msg = '''Extensão não conhecida para o arquivo: {} + e mimetype: {} + Algumas possibilidades são: + {} + Atualize o código do dicionário EXTENSOES! + '''.format(fullname, mime, possibilidades) print(msg) raise Exception(msg, e) -nomes_arquivos_exportados = {} - - -def dump_file(doc, path): +def dump_file(doc, path, salvar): name = doc['__name__'] fullname = os.path.join(path, name) @@ -104,23 +103,11 @@ def dump_file(doc, path): doc['data'] = pdata pdata = doc - with open(fullname, 'w') as arq: - while pdata: - arq.write(pdata.pop('data')) - pdata = br(pdata.pop('next', None)) - - base, original_extension = os.path.splitext(fullname) - extension = guess_extension(fullname) - if extension == '.xml' and original_extension in ['.xsl', '.xslt']: - # não trocamos as extensões XSL e XSLT - final_name = fullname - else: - # trocamos a extensão pela adivinhada - final_name = base + extension - os.rename(fullname, final_name) - nomes_arquivos_exportados[fullname] = final_name - print(final_name) - + output = cStringIO.StringIO() + while pdata: + output.write(pdata.pop('data')) + pdata = br(pdata.pop('next', None)) + salvar(fullname, output.getvalue()) return name @@ -165,7 +152,7 @@ def logando_nao_identificados(): print('#' * 80) -def dump_folder(folder, path='', enum=enumerate_folder): +def dump_folder(folder, path, salvar, enum=enumerate_folder): name = folder['id'] path = os.path.join(path, name) if not os.path.exists(path): @@ -175,7 +162,7 @@ def dump_folder(folder, path='', enum=enumerate_folder): if dump == '?': nao_identificados[meta_type].append(path + '/' + id) elif dump: - id_interno = dump(obj, path) + id_interno = dump(obj, path, salvar) assert id == id_interno return name @@ -211,18 +198,16 @@ def read_sde(element): return data -def save_as_yaml(path, name, obj): +def save_as_yaml(path, name, obj, salvar): fullname = os.path.join(path, name) - with open(fullname, 'w') as arquivo: - yaml.safe_dump(obj, arquivo, allow_unicode=True) - print(fullname) - return fullname + conteudo = yaml.safe_dump(obj, allow_unicode=True) + salvar(fullname, conteudo) -def dump_sde(strdoc, path, tipo): +def dump_sde(strdoc, path, salvar, tipo): id = strdoc['id'] sde = read_sde(strdoc) - save_as_yaml(path, '{}.{}.yaml'.format(id, tipo), sde) + save_as_yaml(path, '{}.{}.yaml'.format(id, tipo), sde, salvar) return id @@ -243,7 +228,7 @@ DUMP_FUNCTIONS = { def get_app(data_fs_path): - storage = ZODB.FileStorage.FileStorage(data_fs_path) + storage = ZODB.FileStorage.FileStorage(data_fs_path, read_only=True) db = ZODB.DB(storage) connection = db.open() root = connection.root() @@ -265,60 +250,79 @@ def find_sapl(app): return sapl -def dump_propriedades(docs, path, encoding='iso-8859-1'): +def dump_propriedades(docs, path, salvar, encoding='iso-8859-1'): props_sapl = br(docs['props_sapl']) ids = [p['id'] for p in props_sapl['_properties']] props = {id: props_sapl[id] for id in ids} props = {id: p.decode(encoding) if isinstance(p, str) else p for id, p in props.items()} - save_as_yaml(path, 'sapl_documentos/propriedades.yaml', props) + save_as_yaml(path, 'sapl_documentos/propriedades.yaml', props, salvar) -def dump_usuarios(sapl, path): +def dump_usuarios(sapl, path, salvar): users = br(br(sapl['acl_users'])['data']) users = {k: br(v) for k, v in users['data'].items()} - save_as_yaml(path, 'usuarios.yaml', users) - - -def grava_nomes_arquivos_exportados(destino): - """Grava nomes dos arquivos exportados (originais -> definitivos) - """ - destino = Path(destino) - - def rel(caminho): - return str(destino.rel_path_to(caminho)) - - with open(destino.child('arquivos_exportados.yaml'), 'w') as arq: - nomes = {rel(k): rel(v) for k, v in nomes_arquivos_exportados.items()} - pyaml.dump(nomes, arq) + save_as_yaml(path, 'usuarios.yaml', users, salvar) -def _dump_sapl(data_fs_path, destino='../../../../media'): +def _dump_sapl(data_fs_path, destino, salvar): assert Path(data_fs_path).exists() app, close_db = get_app(data_fs_path) - nomes_arquivos_exportados.clear() # apaga nomes dos arquivos migrados try: sapl = find_sapl(app) # extrai folhas XSLT - dump_folder(br(sapl['XSLT']), destino) + dump_folder(br(sapl['XSLT']), destino, salvar) # extrai usuários com suas senhas e perfis - dump_usuarios(sapl, destino) + dump_usuarios(sapl, destino, salvar) # extrai documentos docs = br(sapl['sapl_documentos']) with logando_nao_identificados(): - dump_folder(docs, destino) - dump_propriedades(docs, destino) + dump_folder(docs, destino, salvar) + dump_propriedades(docs, destino, salvar) finally: close_db() - grava_nomes_arquivos_exportados(destino) DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() -def repo_execute(repo, cmd): - return repo.git.execute(cmd.split()) +def repo_execute(repo, cmd, *args): + return repo.git.execute(cmd.split() + list(args)) + + +def get_annex_hashes(repo): + hashes = repo_execute( + repo, 'git annex find', '--format=${keyname}\n', '--include=*') + return {os.path.splitext(h)[0] for h in hashes.splitlines()} + + +def ajusta_extensao(fullname, conteudo): + base, extensao = os.path.splitext(fullname) + if extensao not in ['.xsl', '.xslt', '.yaml']: + # não trocamos as extensões XSL, XSLT e YAML + extensao = guess_extension(fullname, conteudo) + return base + extensao + + +def build_salvar(repo): + """Constroi função salvar que pula arquivos que já estão no annex + """ + hashes = get_annex_hashes(repo) + + def salvar(fullname, conteudo): + sha = hashlib.sha256() + sha.update(conteudo) + if sha.hexdigest() not in hashes: + fullname = ajusta_extensao(fullname, conteudo) + if os.path.exists(fullname): + # destrava arquivo pré-existente (o conteúdo mudou) + repo_execute(repo, 'git annex unlock', fullname) + with open(fullname, 'w') as arq: + arq.write(conteudo) + print(fullname) + + return salvar def dump_sapl(sigla): @@ -329,9 +333,13 @@ def dump_sapl(sigla): destino = DIR_DADOS_MIGRACAO.child('repos', nome_banco_legado) destino.mkdir(parents=True) repo = git.Repo.init(destino) - _dump_sapl(data_fs_path, destino) - # grava mundaças repo_execute(repo, 'git annex init') + repo_execute(repo, 'git config annex.thin true') + + salvar = build_salvar(repo) + _dump_sapl(data_fs_path, destino, salvar) + + # grava mundaças repo_execute(repo, 'git annex add sapl_documentos') repo.git.add(A=True) if 'master' not in repo.heads or repo.index.diff('HEAD'): From 0b49930da0dfef6bc25d0a2399fc36967ed30096 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Wed, 18 Apr 2018 12:15:58 -0300 Subject: [PATCH 023/119] Fix #1899 (#1900) --- sapl/sessao/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 9f8f8aaa2..889f0ab8c 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -978,13 +978,12 @@ class MesaView(FormMixin, DetailView): return self.render_to_response(context) mesa = sessao.integrantemesa_set.all() if sessao else [] - cargos_ocupados = [m.cargo for m in mesa] cargos = CargoMesa.objects.all() cargos_vagos = list(set(cargos) - set(cargos_ocupados)) # FIX-ME: tem formas melhores de fazer isso, poupando linhas. - parlamentares = Legislatura.objects.first().mandato_set.all() + parlamentares = Legislatura.objects.get(id=sessao.legislatura_id).mandato_set.all() parlamentares_ocupados = [m.parlamentar for m in mesa] parlamentares_vagos = list( set( From 2806bf4d9bb8ad2f01d47d8b57b18c33541af0b5 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 18 Apr 2018 16:58:05 -0300 Subject: [PATCH 024/119] Fixes #1898 --- sapl/sessao/views.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 889f0ab8c..95785b6fb 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -6,7 +6,7 @@ from django.contrib.auth.decorators import permission_required from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.core.urlresolvers import reverse -from django.db.models import Max, Q +from django.db.models import Max, Q, Func from django.forms.utils import ErrorList from django.http import JsonResponse from django.http.response import Http404, HttpResponseRedirect @@ -393,8 +393,13 @@ def get_presencas_generic(model, sessao, legislatura): presentes = [p.parlamentar for p in presencas] + # COLLATION pt_BR.utf8 + nome_c = Func( + 'parlamentar__nome_parlamentar', + function='pt_BR.utf8', + template='(%(expressions)s) COLLATE "%(function)s"') mandato = Mandato.objects.filter( - legislatura=legislatura).order_by('parlamentar__nome_parlamentar') + legislatura=legislatura).order_by(nome_c.asc()) for m in mandato: if m.parlamentar in presentes: From 44150ef549a35f7ea9f58c0289328b79fa2075ec Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 19 Apr 2018 11:09:59 -0300 Subject: [PATCH 025/119] Fixes #1904 --- sapl/protocoloadm/forms.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index dc3d5280c..36baa8f3e 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -668,11 +668,12 @@ class DocumentoAdministrativoForm(ModelForm): numero_documento = self.cleaned_data['numero'] tipo_documento = self.data['tipo'] - documento = DocumentoAdministrativo.objects.filter(numero=numero_documento, - tipo=tipo_documento, ano=ano_protocolo) - - if documento: - raise ValidationError('Documento já existente') + if not self.instance.pk: + documento = DocumentoAdministrativo.objects.filter(numero=numero_documento, + tipo=tipo_documento, + ano=ano_protocolo) + if documento: + raise ValidationError('Documento já existente') # campos opcionais, mas que se informados devem ser válidos if numero_protocolo and ano_protocolo: From a78b1adf821941de823bbc695b743db87fad30d5 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 19 Apr 2018 11:17:59 -0300 Subject: [PATCH 026/119] Release: 3.1.73 --- 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 a3173316a..1c0fe8fd4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.72 + image: interlegis/sapl:3.1.73 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 33c6bf7e0..732fe70bd 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.72', + version='3.1.73', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From f2f00cb5b1e687f93063e5d76464fef091d0f494 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 19 Apr 2018 11:23:36 -0300 Subject: [PATCH 027/119] HOT-FIX: retira checagem duplicada --- sapl/protocoloadm/forms.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 36baa8f3e..b51b5facd 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -655,9 +655,6 @@ class DocumentoAdministrativoForm(ModelForm): def clean(self): super(DocumentoAdministrativoForm, self).clean() - if not self.is_valid(): - return self.cleaned_data - cleaned_data = self.cleaned_data if not self.is_valid(): From 4aad96c15f3739d732a6dbc337051be11e523b70 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 19 Apr 2018 11:38:54 -0300 Subject: [PATCH 028/119] =?UTF-8?q?N=C3=A3o=20permite=20atualizar=20doc=20?= =?UTF-8?q?adm=20para=20tipo-n=C3=BAmero-ano=20existente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/protocoloadm/forms.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index b51b5facd..1d5e84133 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -662,10 +662,17 @@ class DocumentoAdministrativoForm(ModelForm): numero_protocolo = self.data['numero_protocolo'] ano_protocolo = self.data['ano_protocolo'] - numero_documento = self.cleaned_data['numero'] - tipo_documento = self.data['tipo'] + numero_documento = int(self.cleaned_data['numero']) + tipo_documento = int(self.data['tipo']) + ano_documento = int(self.data['ano']) - if not self.instance.pk: + # não permite atualizar para numero/ano/tipo existente + if self.instance.pk: + mudanca_doc = numero_documento != self.instance.numero \ + or ano_documento != self.instance.ano \ + or tipo_documento != self.instance.tipo.pk + + if not self.instance.pk or mudanca_doc: documento = DocumentoAdministrativo.objects.filter(numero=numero_documento, tipo=tipo_documento, ano=ano_protocolo) From 1dfcd5462796be2d55bedc315d216b1753ebddf3 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 20 Apr 2018 15:21:41 -0300 Subject: [PATCH 029/119] Revert "Fixes #1898" This reverts commit 2806bf4d9bb8ad2f01d47d8b57b18c33541af0b5. --- sapl/sessao/views.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 95785b6fb..889f0ab8c 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -6,7 +6,7 @@ from django.contrib.auth.decorators import permission_required from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.core.urlresolvers import reverse -from django.db.models import Max, Q, Func +from django.db.models import Max, Q from django.forms.utils import ErrorList from django.http import JsonResponse from django.http.response import Http404, HttpResponseRedirect @@ -393,13 +393,8 @@ def get_presencas_generic(model, sessao, legislatura): presentes = [p.parlamentar for p in presencas] - # COLLATION pt_BR.utf8 - nome_c = Func( - 'parlamentar__nome_parlamentar', - function='pt_BR.utf8', - template='(%(expressions)s) COLLATE "%(function)s"') mandato = Mandato.objects.filter( - legislatura=legislatura).order_by(nome_c.asc()) + legislatura=legislatura).order_by('parlamentar__nome_parlamentar') for m in mandato: if m.parlamentar in presentes: From 8fc46b7260db3f8799f3347ab6a97ca04550f6c4 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 20 Apr 2018 15:22:23 -0300 Subject: [PATCH 030/119] Release: 3.1.74 --- 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 1c0fe8fd4..9a369d466 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.73 + image: interlegis/sapl:3.1.74 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 732fe70bd..33d1bd47e 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.73', + version='3.1.74', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 0707de627b13e8231a97972797cc5dd595c3947b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Sconetto?= Date: Mon, 23 Apr 2018 09:57:51 -0300 Subject: [PATCH 031/119] Fix #1908 (#1909) --- sapl/sessao/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index 219e5b69b..c35abf306 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -452,7 +452,7 @@ class OradorForm(ModelForm): sessao_plenaria_id=id_sessao)] self.fields['parlamentar'].queryset = Parlamentar.objects.filter( - id__in=ids).order_by('nome_completo') + id__in=ids).order_by('nome_parlamentar') class Meta: model = Orador From 959005532aa22eedc0af3adbf55f747341da8d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Sconetto?= Date: Fri, 20 Apr 2018 15:38:07 -0300 Subject: [PATCH 032/119] Fix #Fix #1785 --- sapl/materia/models.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sapl/materia/models.py b/sapl/materia/models.py index a1571072a..606fabbd7 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -325,9 +325,17 @@ class AcompanhamentoMateria(models.Model): verbose_name_plural = _('Acompanhamentos de Matéria') def __str__(self): - # FIXME str should be human readable, using hash is very strange - return _('%(materia)s - #%(hash)s') % { - 'materia': self.materia, 'hash': self.hash} + if self.data_cadastro is None: + return _('%(materia)s - %(email)s') % { + 'materia': self.materia, + 'email': self.email + } + else: + return _('%(materia)s - %(email)s - Registrado em: %(data)s') % { + 'materia': self.materia, + 'email': self.email, + 'data': str(self.data_cadastro.strftime('%d/%m/%Y')) + } @reversion.register() From a03ced746ed2fb8c7ec023571f95cbe551ff65d5 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 23 Apr 2018 13:08:08 -0300 Subject: [PATCH 033/119] Remove volumes pendentes --- scripts_docker/remove-all-containers.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts_docker/remove-all-containers.sh b/scripts_docker/remove-all-containers.sh index 64d41cd5c..a3d8fc624 100755 --- a/scripts_docker/remove-all-containers.sh +++ b/scripts_docker/remove-all-containers.sh @@ -1,4 +1,5 @@ #!/bin/bash -sudo docker stop $(docker ps -a -q) # Parar containers -sudo docker rm $(sudo docker ps -a -q) # Remover containers -sudo docker rmi -f $( sudo docker images -q ) # Remover imagens +sudo docker stop $(docker ps -a -q) # Para containers +sudo docker rm $(sudo docker ps -a -q) # Remove containers +sudo docker rmi -f $( sudo docker images -q ) # Remove imagens +sudo docker volume rm $(sudo docker volume ls -q -f dangling=true) # Remove volumes From 790cfd2aa99807105ca66f872e794ede0aaa124e Mon Sep 17 00:00:00 2001 From: Edward Date: Mon, 23 Apr 2018 13:32:35 -0300 Subject: [PATCH 034/119] Fix #1898 (#1910) --- sapl/sessao/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 889f0ab8c..4ad6178ab 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -393,6 +393,8 @@ def get_presencas_generic(model, sessao, legislatura): presentes = [p.parlamentar for p in presencas] + presentes = sorted(presentes, key=lambda x: x.nome_parlamentar) + mandato = Mandato.objects.filter( legislatura=legislatura).order_by('parlamentar__nome_parlamentar') From 6201c7f09284d4f94c9beca14f1892cc117118ea Mon Sep 17 00:00:00 2001 From: Edward Date: Wed, 25 Apr 2018 14:16:32 -0300 Subject: [PATCH 035/119] Fix #1913 (#1914) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #1913 * Remove import não utilizado --- sapl/sessao/views.py | 73 +++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 4ad6178ab..d7844b3ce 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -30,7 +30,6 @@ from sapl.materia.forms import filtra_tramitacao_status from sapl.materia.models import (Autoria, DocumentoAcessorio, TipoMateriaLegislativa, Tramitacao) from sapl.materia.views import MateriaLegislativaPesquisaView -from sapl.norma.models import NormaJuridica from sapl.parlamentares.models import (Filiacao, Legislatura, Mandato, Parlamentar, SessaoLegislativa) from sapl.sessao.apps import AppConfig @@ -1114,15 +1113,13 @@ def remove_parlamentar_composicao(request): if 'composicao_mesa' in request.POST: try: - composicao = IntegranteMesa.objects.get( - id=int(request.POST['composicao_mesa'])) + IntegranteMesa.objects.get( + id=int(request.POST['composicao_mesa'])).delete() except ObjectDoesNotExist: return JsonResponse( {'msg': ( 'Composição da Mesa não pôde ser removida!', 0)}) - composicao.delete() - return JsonResponse( {'msg': ( 'Parlamentar excluido com sucesso!', 1)}) @@ -1526,8 +1523,7 @@ class VotacaoEditView(SessaoPermissionMixin): ordem_id = kwargs['oid'] if(int(request.POST['anular_votacao']) == 1): - for r in RegistroVotacao.objects.filter(ordem_id=ordem_id): - r.delete() + RegistroVotacao.objects.filter(ordem_id=ordem_id).delete() ordem = OrdemDia.objects.get( sessao_plenaria_id=self.object.id, @@ -1558,9 +1554,8 @@ class VotacaoEditView(SessaoPermissionMixin): materia = {'materia': ordem.materia, 'ementa': ordem.materia.ementa} context.update({'materia': materia}) - votacao = RegistroVotacao.objects.filter( - materia_id=materia_id, - ordem_id=ordem_id).last() + votacao = RegistroVotacao.objects.filter(materia_id=materia_id, + ordem_id=ordem_id).last() votacao_existente = {'observacao': sub( ' ', ' ', strip_tags(votacao.observacao)), 'resultado': votacao.tipo_resultado_votacao.nome, @@ -1707,8 +1702,7 @@ def fechar_votacao_materia(materia): VotoParlamentar.objects.filter(ordem=materia).delete() elif type(materia) == ExpedienteMateria: - RegistroVotacao.objects.filter( - expediente=materia).delete() + RegistroVotacao.objects.filter(expediente=materia).delete() VotoParlamentar.objects.filter(expediente=materia).delete() if materia.resultado: @@ -1756,7 +1750,7 @@ class VotacaoNominalAbstract(SessaoPermissionMixin): elif self.expediente: expediente_id = kwargs['oid'] if (RegistroVotacao.objects.filter( - expediente_id=expediente_id).exists()): + expediente_id=expediente_id).exists()): msg = _('Esta matéria já foi votada!') messages.add_message(request, messages.ERROR, msg) return HttpResponseRedirect(reverse( @@ -1843,8 +1837,7 @@ class VotacaoNominalAbstract(SessaoPermissionMixin): return self.form_invalid(form) # Remove todas as votação desta matéria, caso existam if self.ordem: - RegistroVotacao.objects.filter( - ordem_id=ordem_id).delete() + RegistroVotacao.objects.filter(ordem_id=ordem_id).delete() elif self.expediente: RegistroVotacao.objects.filter( expediente_id=expediente_id).delete() @@ -1972,11 +1965,10 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin): if self.ordem: ordem_id = kwargs['oid'] - try: - ordem = OrdemDia.objects.get(id=ordem_id) - votacao = RegistroVotacao.objects.get( - ordem_id=ordem_id) - except ObjectDoesNotExist: + ordem = OrdemDia.objects.filter(id=ordem_id).last() + votacao = RegistroVotacao.objects.filter(ordem_id=ordem_id).last() + + if not ordem or not votacao: raise Http404() materia = ordem.materia @@ -1985,11 +1977,10 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin): elif self.expediente: expediente_id = kwargs['oid'] - try: - expediente = ExpedienteMateria.objects.get(id=expediente_id) - votacao = RegistroVotacao.objects.get( - expediente_id=expediente_id) - except ObjectDoesNotExist: + expediente = ExpedienteMateria.objects.filter(id=expediente_id).last() + votacao = RegistroVotacao.objects.filter(expediente_id=expediente_id).last() + + if not expediente or not votacao: raise Http404() materia = expediente.materia @@ -2106,9 +2097,9 @@ class VotacaoNominalTransparenciaDetailView(TemplateView): materia_votacao = self.request.GET.get('materia', None) if materia_votacao == 'ordem': - votacao = RegistroVotacao.objects.get(ordem=self.kwargs['oid']) + votacao = RegistroVotacao.objects.filter(ordem=self.kwargs['oid']).last() elif materia_votacao == 'expediente': - votacao = RegistroVotacao.objects.get(expediente=self.kwargs['oid']) + votacao = RegistroVotacao.objects.filter(expediente=self.kwargs['oid']).last() else: raise Http404() @@ -2142,10 +2133,9 @@ class VotacaoNominalExpedienteDetailView(DetailView): materia_id = kwargs['mid'] expediente_id = kwargs['oid'] - votacao = RegistroVotacao.objects.get( - materia_id=materia_id, - expediente_id=expediente_id) - expediente = ExpedienteMateria.objects.get(id=expediente_id) + votacao = RegistroVotacao.objects.filter(materia_id=materia_id, + expediente_id=expediente_id).last() + expediente = ExpedienteMateria.objects.filter(id=expediente_id).last() votos = VotoParlamentar.objects.filter(votacao_id=votacao.id) list_votos = [] @@ -2190,9 +2180,9 @@ class VotacaoSimbolicaTransparenciaDetailView(TemplateView): materia_votacao = self.request.GET.get('materia', None) if materia_votacao == 'ordem': - votacao = RegistroVotacao.objects.get(ordem=self.kwargs['oid']) + votacao = RegistroVotacao.objects.filter(ordem=self.kwargs['oid']).last() elif materia_votacao == 'expediente': - votacao = RegistroVotacao.objects.get(expediente=self.kwargs['oid']) + votacao = RegistroVotacao.objects.filter(expediente=self.kwargs['oid']).last() else: raise Http404() @@ -2378,14 +2368,9 @@ class VotacaoExpedienteEditView(SessaoPermissionMixin): 'ementa': expediente.materia.ementa} context.update({'materia': materia}) - try: - votacao = RegistroVotacao.objects.get( - materia_id=materia_id, - expediente_id=expediente_id) - except MultipleObjectsReturned: - votacao = RegistroVotacao.objects.filter( - materia_id=materia_id, - expediente_id=expediente_id).last() + votacao = RegistroVotacao.objects.filter(materia_id=materia_id, + expediente_id=expediente_id + ).last() votacao_existente = {'observacao': sub( ' ', ' ', strip_tags(votacao.observacao)), 'resultado': votacao.tipo_resultado_votacao.nome, @@ -2404,10 +2389,8 @@ class VotacaoExpedienteEditView(SessaoPermissionMixin): materia_id = kwargs['mid'] expediente_id = kwargs['oid'] - if(int(request.POST['anular_votacao']) == 1): - for r in RegistroVotacao.objects.filter( - expediente_id=expediente_id): - r.delete() + if int(request.POST['anular_votacao']) == 1: + RegistroVotacao.objects.filter(expediente_id=expediente_id).delete() expediente = ExpedienteMateria.objects.get( sessao_plenaria_id=self.object.id, From fc471d6972204b1e2b1fc6019c6090ba15bf5093 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 25 Apr 2018 15:53:00 -0300 Subject: [PATCH 036/119] =?UTF-8?q?Adiciona=20campo=20n=C3=BAmero=20extern?= =?UTF-8?q?o=20(opcional)=20para=20docs=20adm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/protocoloadm/forms.py | 15 ++++++++------ ..._documentoadministrativo_numero_externo.py | 20 +++++++++++++++++++ sapl/protocoloadm/models.py | 4 ++++ sapl/templates/protocoloadm/layouts.yaml | 1 + 4 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 sapl/protocoloadm/migrations/0004_documentoadministrativo_numero_externo.py diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 1d5e84133..06a2f7854 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -155,6 +155,7 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet): fields = ['tipo', 'numero', 'protocolo__numero', + 'numero_externo', 'data', 'tramitacaoadministrativo__unidade_tramitacao_destino', 'tramitacaoadministrativo__status'] @@ -173,7 +174,8 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet): row2 = to_row( [('ano', 4), - ('protocolo__numero', 4), + ('protocolo__numero', 2), + ('numero_externo', 2), ('data', 4)]) row3 = to_row( @@ -645,6 +647,7 @@ class DocumentoAdministrativoForm(ModelForm): 'tramitacao', 'dias_prazo', 'data_fim_prazo', + 'numero_externo', 'observacao', 'texto_integral', 'protocolo', @@ -673,10 +676,10 @@ class DocumentoAdministrativoForm(ModelForm): or tipo_documento != self.instance.tipo.pk if not self.instance.pk or mudanca_doc: - documento = DocumentoAdministrativo.objects.filter(numero=numero_documento, - tipo=tipo_documento, - ano=ano_protocolo) - if documento: + doc_exists = DocumentoAdministrativo.objects.filter(numero=numero_documento, + tipo=tipo_documento, + ano=ano_protocolo).exists() + if doc_exists: raise ValidationError('Documento já existente') # campos opcionais, mas que se informados devem ser válidos @@ -725,7 +728,7 @@ class DocumentoAdministrativoForm(ModelForm): [('texto_integral', 12)]) row6 = to_row( - [('dias_prazo', 6), ('data_fim_prazo', 6)]) + [('numero_externo', 4), ('dias_prazo', 6), ('data_fim_prazo', 2)]) row7 = to_row( [('observacao', 12)]) diff --git a/sapl/protocoloadm/migrations/0004_documentoadministrativo_numero_externo.py b/sapl/protocoloadm/migrations/0004_documentoadministrativo_numero_externo.py new file mode 100644 index 000000000..b3659efbb --- /dev/null +++ b/sapl/protocoloadm/migrations/0004_documentoadministrativo_numero_externo.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2018-04-25 18:40 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('protocoloadm', '0003_auto_20180103_1343'), + ] + + operations = [ + migrations.AddField( + model_name='documentoadministrativo', + name='numero_externo', + field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Número Externo'), + ), + ] diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py index d4d45b3ad..cf7616d7a 100644 --- a/sapl/protocoloadm/models.py +++ b/sapl/protocoloadm/models.py @@ -133,6 +133,10 @@ class DocumentoAdministrativo(models.Model): verbose_name=_('Em Tramitação?'), choices=YES_NO_CHOICES) assunto = models.TextField(verbose_name=_('Assunto')) + numero_externo = models.PositiveIntegerField( + blank=True, + null=True, + verbose_name=_('Número Externo')) observacao = models.TextField( blank=True, verbose_name=_('Observação')) texto_integral = models.FileField( diff --git a/sapl/templates/protocoloadm/layouts.yaml b/sapl/templates/protocoloadm/layouts.yaml index 76b80da18..b1bb2f31b 100644 --- a/sapl/templates/protocoloadm/layouts.yaml +++ b/sapl/templates/protocoloadm/layouts.yaml @@ -11,6 +11,7 @@ DocumentoAdministrativo: - interessado tramitacao - texto_integral {% trans 'Outras Informações' %}: + - numero_externo - dias_prazo data_fim_prazo - observacao From 7257c48fadbd0d8a818e39aa481932cbc0688b85 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 25 Apr 2018 15:54:48 -0300 Subject: [PATCH 037/119] Release: 3.1.75 --- 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 9a369d466..48e9a3b30 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.74 + image: interlegis/sapl:3.1.75 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 33d1bd47e..edf2dc502 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.74', + version='3.1.75', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From a502b90cc60b8123931831701d8d5a72bf0e3af5 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 19 Apr 2018 10:59:37 -0300 Subject: [PATCH 038/119] =?UTF-8?q?Adiciona=20depend=C3=AAncias=20faltando?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/legacy/scripts/exporta_zope/requirements.txt b/sapl/legacy/scripts/exporta_zope/requirements.txt index c7aa86b4f..69305576b 100644 --- a/sapl/legacy/scripts/exporta_zope/requirements.txt +++ b/sapl/legacy/scripts/exporta_zope/requirements.txt @@ -4,3 +4,5 @@ PyYAML Unipath GitPython pyaml +python-magic +ipython From 8997c91dfcbf252127ece602c066d00e14e34203 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 19 Apr 2018 11:58:43 -0300 Subject: [PATCH 039/119] Ignora aquivos vazios ao exportar docs --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 2c687bc07..a22c49b87 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -18,10 +18,9 @@ import git import magic import pyaml import yaml -from unipath import Path - import ZODB.DB import ZODB.FileStorage +from unipath import Path from ZODB.broken import Broken EXTENSOES = { @@ -107,7 +106,11 @@ def dump_file(doc, path, salvar): while pdata: output.write(pdata.pop('data')) pdata = br(pdata.pop('next', None)) - salvar(fullname, output.getvalue()) + + conteudo = output.getvalue() + if conteudo: + # pula arquivos vazios + salvar(fullname, conteudo) return name From b8fc7fcd2a8187704898a3cc0f84937ad204c524 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 19 Apr 2018 11:59:14 -0300 Subject: [PATCH 040/119] =?UTF-8?q?Adiciona=20mais=20tipos=20de=20arquivos?= =?UTF-8?q?=20=C3=A0=20exporta=C3=A7=C3=A3o=20de=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index a22c49b87..2d66d97c4 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -29,6 +29,9 @@ EXTENSOES = { 'application/vnd.oasis.opendocument.text': '.odt', 'application/vnd.ms-excel': '.xls', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx', # noqa + 'application/vnd.oasis.opendocument.text-template': '.ott', + 'application/vnd.ms-powerpoint': '.ppt', + 'application/xml': '.xml', 'text/xml': '.xml', 'application/zip': '.zip', @@ -45,7 +48,9 @@ EXTENSOES = { 'audio/x-wav': '.wav', 'video/mp4': '.mp4', 'image/x-icon': '.ico', - 'application/vnd.oasis.opendocument.text-template': '.ott', + 'image/x-ms-bmp': '.bmp', + 'video/x-ms-asf': '.asf', + 'audio/mpeg': '.mp3', # TODO rever... 'text/richtext': '.rtf', @@ -53,7 +58,9 @@ EXTENSOES = { # sem extensao 'application/octet-stream': '', # binário 'inode/x-empty': '', # vazio - 'text/x-unknown-content-type': '', + 'application/x-empty': '', # vazio + 'text/x-unknown-content-type': '', # desconhecido + 'application/CDFV2-unknown': '', # desconhecido } From 8cb44f0235b1a0cd24d9803499a2b36d31fac3ad Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 19 Apr 2018 13:42:37 -0300 Subject: [PATCH 041/119] Ajusta print para uso com pipe --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 2d66d97c4..545e10462 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -14,10 +14,11 @@ from collections import defaultdict from contextlib import contextmanager from functools import partial +import yaml + import git import magic import pyaml -import yaml import ZODB.DB import ZODB.FileStorage from unipath import Path @@ -155,8 +156,8 @@ def logando_nao_identificados(): if nao_identificados: print('#' * 80) print('#' * 80) - print(u'FORAM ENCONTRADOS ARQUIVOS DE FORMATO NÃO IDENTIFICADO!!!') - print(u'REFAÇA A EXPORTAÇÃO\n') + print('FORAM ENCONTRADOS ARQUIVOS DE FORMATO NÃO IDENTIFICADO!!!') + print('REFAÇA A EXPORTAÇÃO\n') print(nao_identificados) print('#' * 80) print('#' * 80) From 31cd0c83d07b780d9417d36a41676db0156e4ac5 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 19 Apr 2018 18:07:52 -0300 Subject: [PATCH 042/119] Migra usando repo git para marcos --- requirements/migration-requirements.txt | 1 + sapl/legacy/migracao.py | 7 ++- sapl/legacy/migracao_dados.py | 25 ++++++-- sapl/legacy/migracao_documentos.py | 81 ++++++++++++++----------- sapl/legacy/migracao_usuarios.py | 8 +-- 5 files changed, 74 insertions(+), 48 deletions(-) diff --git a/requirements/migration-requirements.txt b/requirements/migration-requirements.txt index fbe9543e2..e3f887b14 100644 --- a/requirements/migration-requirements.txt +++ b/requirements/migration-requirements.txt @@ -1,3 +1,4 @@ -r dev-requirements.txt +GitPython mysqlclient==1.3.12 pyaml diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index be8830aa8..a72bd9aaa 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -3,15 +3,16 @@ import tarfile from django.conf import settings -from sapl.legacy.migracao_dados import migrar_dados +from sapl.legacy.migracao_dados import REPO, gravar_marco, migrar_dados from sapl.legacy.migracao_documentos import migrar_documentos from sapl.legacy.migracao_usuarios import migrar_usuarios def migrar(interativo=False): migrar_dados(interativo=interativo) - migrar_usuarios() - migrar_documentos() + migrar_usuarios(REPO.working_dir) + migrar_documentos(REPO) + gravar_marco() def gerar_pacote(): diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 52adfd2f1..492a8e579 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -8,6 +8,7 @@ from itertools import groupby from operator import xor from subprocess import PIPE, call +import git import pkg_resources import pyaml import pytz @@ -1256,30 +1257,44 @@ AJUSTE_DEPOIS_SALVAR = { TIME_FORMAT = '%H:%M:%S' +# permite a gravação de tempos puros pelo pretty-yaml def time_representer(dumper, data): return dumper.represent_scalar('!time', data.strftime(TIME_FORMAT)) UnsafePrettyYAMLDumper.add_representer(datetime.time, time_representer) +# permite a leitura de tempos puros pelo pyyaml (no padrão gravado acima) def time_constructor(loader, node): value = loader.construct_scalar(node) return datetime.datetime.strptime(value, TIME_FORMAT).time() yaml.add_constructor(u'!time', time_constructor) -DIR_MARCO = Path(DIR_DADOS_MIGRACAO, 'marcos', nome_banco_legado) +REPO = git.Repo.init(Path(DIR_DADOS_MIGRACAO, 'repos', nome_banco_legado)) -def grava_marco_base(): +def gravar_marco(): + """Grava um dump de todos os dados como arquivos yaml no repo de marco + """ + # prepara ou localiza repositorio + dir_dados = Path(REPO.working_dir, 'dados') + + # exporta dados como arquivos yaml user_model = get_user_model() models = get_models_a_migrar() + [ Composicao, user_model, Group, ContentType] for model in models: info('Gravando marco de [{}]'.format(model.__name__)) - dir_model = Path( - DIR_MARCO, 'dados', model._meta.app_label, model.__name__) + dir_model = dir_dados.child(model._meta.app_label, model.__name__) dir_model.mkdir(parents=True) for data in model.objects.all().values(): - nome_arq = Path(dir_model, data['id']) + nome_arq = Path(dir_model, '{}.yaml'.format(data['id'])) with open(nome_arq, 'w') as arq: pyaml.dump(data, arq) + + # salva mudanças + REPO.git.add([dir_dados.name]) + if 'master' not in REPO.heads or REPO.index.diff('HEAD'): + # se de fato existe mudança + REPO.index.commit('Grava marco') + REPO.git.execute('git tag marco'.split()) diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index a94b9160a..57446f39c 100644 --- a/sapl/legacy/migracao_documentos.py +++ b/sapl/legacy/migracao_documentos.py @@ -1,6 +1,7 @@ import os import re from glob import glob +from os.path import join import yaml from django.db import transaction @@ -14,7 +15,6 @@ from sapl.parlamentares.models import Parlamentar from sapl.protocoloadm.models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo) from sapl.sessao.models import SessaoPlenaria -from sapl.settings import MEDIA_ROOT # MIGRAÇÃO DE DOCUMENTOS ################################################### @@ -34,25 +34,41 @@ DOCS = { DocumentoAcessorioAdministrativo: [('arquivo', 'administrativo/{}')], } -DOCS = {model: [(campo, os.path.join('sapl_documentos', origem)) +DOCS = {model: [(campo, join('sapl_documentos', origem)) for campo, origem, in campos] for model, campos in DOCS.items()} -def em_media(caminho): - return os.path.join(MEDIA_ROOT, caminho) - - -def mover_documento(origem, destino): - origem, destino = [em_media(c) if not os.path.isabs(c) else c +def mover_documento(repo, origem, destino): + origem, destino = [join(repo.working_dir, c) if not os.path.isabs(c) else c for c in (origem, destino)] os.makedirs(os.path.dirname(destino), exist_ok=True) - os.rename(origem, destino) + repo.git.mv(origem, destino) + # conserta link do git annex (antes do commit) + # em geral é o mais seguro a fazer, + # mas foi especificamente necessário pois o conteúdo das imagens + # é acessado antes do commit pelo cropping de imagem + repo.git.execute('git annex fix'.split() + [destino]) -def migrar_propriedades_da_casa(): +def migrar_logotipo(repo, casa, propriedades): + print('.... Migrando logotipo da casa ....') + [(campo, origem)] = DOCS[CasaLegislativa] + # a extensão do logo pode ter sido ajustada pelo tipo real do arquivo + nome_nas_propriedades = os.path.splitext(propriedades['id_logo'])[0] + arquivos = glob(join(repo.working_dir, origem.format(nome_nas_propriedades))) + if arquivos: + assert len(arquivos) == 1, 'Há mais de um logotipo para a casa' + [logo] = arquivos + destino = join(CasaLegislativa._meta.get_field(campo).upload_to, + os.path.basename(logo)) + mover_documento(repo, logo, destino) + casa.logotipo = destino + + +def migrar_propriedades_da_casa(repo): print('#### Migrando propriedades da casa ####') - caminho = em_media('sapl_documentos/propriedades.yaml') + caminho = join(repo.working_dir, 'sapl_documentos/propriedades.yaml') with open(caminho, 'r') as arquivo: propriedades = yaml.safe_load(arquivo) casa = CasaLegislativa.objects.first() @@ -72,31 +88,24 @@ def migrar_propriedades_da_casa(): for campo, prop in campos_para_propriedades: setattr(casa, campo, propriedades[prop]) - # Localidade + # localidade sql_localidade = ''' select nom_localidade, sgl_uf from localidade where cod_localidade = {}'''.format(propriedades['cod_localidade']) [(casa.municipio, casa.uf)] = exec_legado(sql_localidade) - print('.... Migrando logotipo da casa ....') - [(campo, origem)] = DOCS[CasaLegislativa] - # a extensão do logo pode ter sido ajustada pelo tipo real do arquivo - id_logo = os.path.splitext(propriedades['id_logo'])[0] - [origem] = glob(em_media(origem.format(id_logo))) - destino = os.path.join( - CasaLegislativa._meta.get_field(campo).upload_to, - os.path.basename(origem)) - mover_documento(origem, destino) - casa.logotipo = destino + # logotipo + migrar_logotipo(repo, casa, propriedades) + casa.save() - os.remove(caminho) + repo.git.rm(caminho) -def migrar_docs_por_ids(model): +def migrar_docs_por_ids(repo, model): for campo, base_origem in DOCS[model]: print('#### Migrando {} de {} ####'.format(campo, model.__name__)) - dir_origem, nome_origem = os.path.split(em_media(base_origem)) + dir_origem, nome_origem = os.path.split(join(repo.working_dir, base_origem)) nome_origem = nome_origem.format('(\d+)') pat = re.compile('^{}\.\w+$'.format(nome_origem)) if not os.path.isdir(dir_origem): @@ -106,7 +115,7 @@ def migrar_docs_por_ids(model): matches = [pat.match(arq) for arq in os.listdir(dir_origem)] ids_origens = [(int(m.group(1)), - os.path.join(dir_origem, m.group(0))) + join(dir_origem, m.group(0))) for m in matches if m] objetos = {obj.id: obj for obj in model.objects.all()} upload_to = model._meta.get_field(campo).upload_to @@ -117,7 +126,7 @@ def migrar_docs_por_ids(model): obj = objetos.get(id) if obj: destino = upload_to(obj, os.path.basename(origem)) - mover_documento(origem, destino) + mover_documento(repo, origem, destino) setattr(obj, campo, destino) obj.save() else: @@ -125,16 +134,15 @@ def migrar_docs_por_ids(model): print(msg.format(model.__name__, id, origem)) -def migrar_documentos(): - # aqui supomos que uma pasta chamada sapl_documentos está em MEDIA_ROOT - # com o conteúdo da pasta de mesmo nome do zope - # Os arquivos da pasta serão MOVIDOS para a nova estrutura! - # A pasta, após conferência do que não foi migrado, deve ser apagada. +def migrar_documentos(repo): + # aqui supomos que uma pasta chamada sapl_documentos está em + # com o conteúdo exportado do zope + # Os arquivos da pasta serão (git) MOVIDOS para a nova estrutura! # # Isto significa que para rodar novamente esta função é preciso # restaurar a pasta sapl_documentos ao estado inicial - migrar_propriedades_da_casa() + migrar_propriedades_da_casa(repo) for model in [ Parlamentar, @@ -146,10 +154,11 @@ def migrar_documentos(): DocumentoAdministrativo, DocumentoAcessorioAdministrativo, ]: - migrar_docs_por_ids(model) + migrar_docs_por_ids(repo, model) - sobrando = [os.path.join(dir, file) - for (dir, _, files) in os.walk(em_media('sapl_documentos')) + sobrando = [join(dir, file) + for (dir, _, files) in os.walk(join(repo.working_dir, + 'sapl_documentos')) for file in files] if sobrando: print('\n#### Encerrado ####\n\n' diff --git a/sapl/legacy/migracao_usuarios.py b/sapl/legacy/migracao_usuarios.py index 106a2def6..be0478c82 100644 --- a/sapl/legacy/migracao_usuarios.py +++ b/sapl/legacy/migracao_usuarios.py @@ -1,8 +1,8 @@ import yaml from django.contrib.auth.models import Group, User +from unipath import Path from sapl.hashers import zope_encoded_password_to_django -from sapl.settings import MEDIA_ROOT PERFIL_LEGADO_PARA_NOVO = {legado: Group.objects.get(name=novo) for legado, novo in [ @@ -44,9 +44,9 @@ def decode_nome(nome): return nome -def migrar_usuarios(): +def migrar_usuarios(dir_repo): """ - Lê o arquivo media/usuarios.yaml e importa os usuários nele listados, + Lê o arquivo /usuarios.yaml e importa os usuários nele listados, com senhas e perfis. Os usuários são criados se necessário e seus perfis ajustados. @@ -68,7 +68,7 @@ def migrar_usuarios(): Também podemos assumir que essa é uma tarefa de um administrador """ - ARQUIVO_USUARIOS = MEDIA_ROOT.child('usuarios.yaml') + ARQUIVO_USUARIOS = Path(dir_repo).child('usuarios.yaml') with open(ARQUIVO_USUARIOS, 'r') as f: usuarios = yaml.load(f) # conferimos de que só há um nome de usuário From d18c606c27fdcb7efd605dc57f58f6e3b3430568 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 19 Apr 2018 18:29:35 -0300 Subject: [PATCH 043/119] =?UTF-8?q?Adiciona=20mais=20tipos=20de=20arquivos?= =?UTF-8?q?=20=C3=A0=20exporta=C3=A7=C3=A3o=20de=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 545e10462..fe95aac31 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -14,14 +14,14 @@ from collections import defaultdict from contextlib import contextmanager from functools import partial -import yaml - import git import magic import pyaml +import yaml +from unipath import Path + import ZODB.DB import ZODB.FileStorage -from unipath import Path from ZODB.broken import Broken EXTENSOES = { @@ -32,10 +32,14 @@ EXTENSOES = { 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx', # noqa 'application/vnd.oasis.opendocument.text-template': '.ott', 'application/vnd.ms-powerpoint': '.ppt', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': '.xlsx', # noqa + 'application/vnd.oasis.opendocument.spreadsheet': '.ods', 'application/xml': '.xml', 'text/xml': '.xml', 'application/zip': '.zip', + 'application/x-rar': '.rar', + 'image/jpeg': '.jpeg', 'image/png': '.png', 'image/gif': '.gif', From 38e457620b5712db2ba526f2e1160fe917ef7edd Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 20 Apr 2018 13:41:19 -0300 Subject: [PATCH 044/119] =?UTF-8?q?Grava=20ocorrencias=20de=20migra=C3=A7?= =?UTF-8?q?=C3=A3o=20no=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 492a8e579..f1b6d0299 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -730,8 +730,8 @@ def reinicia_sequence(model, id): DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() -PATH_TABELA_TIMEZONES = DIR_DADOS_MIGRACAO.child('tabela_timezones.yaml') -DIR_RESULTADOS = DIR_DADOS_MIGRACAO.child('resultados') +NOME_BANCO_LEGADO = DATABASES['legacy']['NAME'] +REPO = git.Repo.init(Path(DIR_DADOS_MIGRACAO, 'repos', NOME_BANCO_LEGADO)) def dict_representer(dumper, data): @@ -740,9 +740,9 @@ yaml.add_representer(OrderedDict, dict_representer) # configura timezone de migração -nome_banco_legado = DATABASES['legacy']['NAME'] -match = re.match('sapl_cm_(.*)', nome_banco_legado) +match = re.match('sapl_cm_(.*)', NOME_BANCO_LEGADO) sigla_casa = match.group(1) +PATH_TABELA_TIMEZONES = DIR_DADOS_MIGRACAO.child('tabela_timezones.yaml') with open(PATH_TABELA_TIMEZONES, 'r') as arq: tabela_timezones = yaml.load(arq) municipio, uf, nome_timezone = tabela_timezones[sigla_casa] @@ -818,18 +818,16 @@ def migrar_dados(interativo=True): info('Começando migração: ...') try: ocorrencias.clear() - dir_ocorrencias = DIR_RESULTADOS.child(date.today().isoformat()) - dir_ocorrencias.mkdir(parents=True) migrar_todos_os_models() except Exception as e: ocorrencias['traceback'] = str(traceback.format_exc()) raise e finally: # grava ocorrências - arq_ocorrencias = dir_ocorrencias.child( - nome_banco_legado + '.yaml') + arq_ocorrencias = Path(REPO.working_dir, 'ocorrencias.yaml') with open(arq_ocorrencias, 'w') as arq: pyaml.dump(ocorrencias, arq, vspacing=1) + REPO.git.add([arq_ocorrencias.name]) info('Ocorrências salvas em\n {}'.format(arq_ocorrencias)) # recria tipos de autor padrão que não foram criados pela migração @@ -1270,9 +1268,6 @@ def time_constructor(loader, node): yaml.add_constructor(u'!time', time_constructor) -REPO = git.Repo.init(Path(DIR_DADOS_MIGRACAO, 'repos', nome_banco_legado)) - - def gravar_marco(): """Grava um dump de todos os dados como arquivos yaml no repo de marco """ From 8da14380928363dbce957bfe4ba23bed5905fa30 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 20 Apr 2018 14:05:41 -0300 Subject: [PATCH 045/119] =?UTF-8?q?Restaura=20dump=20mysql=20no=20come?= =?UTF-8?q?=C3=A7o=20da=20migra=C3=A7=C3=A3o=20de=20dados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 20 +++++++++++++++++++- sapl/legacy/scripts/migra_um_db.sh | 19 ++----------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index f1b6d0299..b7ce154a5 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -1,4 +1,5 @@ import datetime +import os import re import traceback from collections import OrderedDict, defaultdict, namedtuple @@ -27,6 +28,7 @@ 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 +from sapl.legacy import scripts from sapl.legacy.models import NormaJuridica as OldNormaJuridica from sapl.legacy.models import TipoNumeracaoProtocolo from sapl.materia.models import (AcompanhamentoMateria, MateriaLegislativa, @@ -785,7 +787,23 @@ def populate_renamed_fields(new, old): setattr(new, field.name, value) +def roda_comando_shell(cmd): + res = os.system(cmd) + assert res == 0, 'O comando falhou: {}'.format(cmd) + + def migrar_dados(interativo=True): + + # restaura dump + arq_dump = Path(DIR_DADOS_MIGRACAO.child( + 'dumps_mysql', '{}.sql'.format(NOME_BANCO_LEGADO))) + assert arq_dump.exists(), 'Dump do mysql faltando: {}'.format(arq_dump) + info('Restaurando dump mysql de [{}]'.format(arq_dump)) + normaliza_dump_mysql = Path(scripts.__file__).parent.child( + 'normaliza_dump_mysql.sh') + roda_comando_shell('{} {}'.format(normaliza_dump_mysql, arq_dump)) + roda_comando_shell('mysql -uroot < {}'.format(arq_dump)) + # executa ajustes pré-migração, se existirem arq_ajustes_pre_migracao = DIR_DADOS_MIGRACAO.child( 'ajustes_pre_migracao', '{}.sql'.format(sigla_casa)) @@ -1292,4 +1310,4 @@ def gravar_marco(): if 'master' not in REPO.heads or REPO.index.diff('HEAD'): # se de fato existe mudança REPO.index.commit('Grava marco') - REPO.git.execute('git tag marco'.split()) + REPO.git.execute('git tag -f marco'.split()) diff --git a/sapl/legacy/scripts/migra_um_db.sh b/sapl/legacy/scripts/migra_um_db.sh index b5b336cd2..dad480704 100755 --- a/sapl/legacy/scripts/migra_um_db.sh +++ b/sapl/legacy/scripts/migra_um_db.sh @@ -1,10 +1,7 @@ #!/bin/bash # rodar esse script na raiz do projeto -if [ $# -ge 2 ]; then - - # proteje pasta com dumps de alterações acidentais - # chmod -R -w ~/migracao_sapl/sapl_dumps +if [ $# -eq 1 ]; then DIR_MIGRACAO=~/migracao_sapl @@ -20,23 +17,11 @@ if [ $# -ge 2 ]; then echo "########################################" | tee -a $LOG echo >> $LOG - if [ $3 ]; then - # se há senha do mysql - mysql -u$2 -p"$3" -N -s -e "DROP DATABASE IF EXISTS $1; CREATE DATABASE $1;" - mysql -u$2 -p"$3" < $DIR_MIGRACAO/dumps_mysql/$1.sql - else - # se não há senha do mysql - mysql -u$2 -N -s -e "DROP DATABASE IF EXISTS $1; CREATE DATABASE $1;" - mysql -u$2 < $DIR_MIGRACAO/dumps_mysql/$1.sql - fi; - echo "O banco legado foi restaurado" |& tee -a $LOG - echo >> $LOG - echo "--- MIGRACAO ---" | tee -a $LOG echo >> $LOG DATABASE_NAME=$1 ./manage.py migracao_25_31 --force --dados --settings sapl.legacy_migration_settings 2>&1 | tee -a $LOG echo >> $LOG else echo "USO:" - echo " $0 [senha mysql]" + echo " $0 " fi; From 3feeb34db0e17d616b48ed20c26d3b59e94e5cc7 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 20 Apr 2018 14:28:34 -0300 Subject: [PATCH 046/119] =?UTF-8?q?Salva=20exporta=C3=A7=C3=A3o=20parcial?= =?UTF-8?q?=20no=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scripts/exporta_zope/exporta_zope.py | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index fe95aac31..6420517f6 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -18,10 +18,9 @@ import git import magic import pyaml import yaml -from unipath import Path - import ZODB.DB import ZODB.FileStorage +from unipath import Path from ZODB.broken import Broken EXTENSOES = { @@ -352,14 +351,20 @@ def dump_sapl(sigla): repo_execute(repo, 'git config annex.thin true') salvar = build_salvar(repo) - _dump_sapl(data_fs_path, destino, salvar) - - # grava mundaças - repo_execute(repo, 'git annex add sapl_documentos') - repo.git.add(A=True) - if 'master' not in repo.heads or repo.index.diff('HEAD'): - # se de fato existe mudança - repo.index.commit('Exporta documentos do zope') + try: + finalizado = False + _dump_sapl(data_fs_path, destino, salvar) + finalizado = True + finally: + # grava mundaças + repo_execute(repo, 'git annex add sapl_documentos') + repo.git.add(A=True) + if 'master' not in repo.heads or repo.index.diff('HEAD'): + # se de fato existe mudança + status = 'completa' if finalizado else 'parcial' + repo.index.commit(u'Exportação do zope {}'.format(status)) + if finalizado: + repo.git.execute('git tag -f zope'.split()) if __name__ == "__main__": From 3fd2ad5dab2f00fb714bd04ca54d5028119deec9 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 20 Apr 2018 14:51:22 -0300 Subject: [PATCH 047/119] =?UTF-8?q?Ignora=20prefixo=20da=20sigla=20na=20ex?= =?UTF-8?q?porta=C3=A7=C3=A3o=20do=20zope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 6420517f6..c115c7a09 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -340,6 +340,7 @@ def build_salvar(repo): def dump_sapl(sigla): + sigla = sigla[-3:] # ignora prefixo (por ex. 'sapl_cm_') data_fs_path = DIR_DADOS_MIGRACAO.child('datafs', 'Data_cm_{}.fs'.format(sigla)) assert data_fs_path.exists(), 'Origem não existe: {}'.format(data_fs_path) From 133641f27ddcab35fd3591c014a41116ee30e9cb Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 20 Apr 2018 17:36:35 -0300 Subject: [PATCH 048/119] =?UTF-8?q?Checa=20q=20exporta=C3=A7=C3=A3o=20do?= =?UTF-8?q?=20zope=20foi=20feita=20antes=20de=20migrar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao.py | 8 ++++++++ sapl/legacy/migracao_dados.py | 6 ++++-- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 10 ++++------ sapl/legacy/scripts/exporta_zope/variaveis_comuns.py | 4 ++++ 4 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 sapl/legacy/scripts/exporta_zope/variaveis_comuns.py diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index a72bd9aaa..3840b1106 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -6,9 +6,17 @@ from django.conf import settings from sapl.legacy.migracao_dados import REPO, gravar_marco, migrar_dados from sapl.legacy.migracao_documentos import migrar_documentos from sapl.legacy.migracao_usuarios import migrar_usuarios +from sapl.legacy.scripts.exporta_zope.variaveis_comuns import TAG_ZOPE + + +def adornar_msg(msg): + return '\n{1}\n{0}\n{1}'.format(msg, '#' * len(msg)) def migrar(interativo=False): + assert TAG_ZOPE in {t.name for t in REPO.tags}, adornar_msg( + 'Antes de migrar ' + 'é necessário fazer a exportação de documentos do zope') migrar_dados(interativo=interativo) migrar_usuarios(REPO.working_dir) migrar_documentos(REPO) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index b7ce154a5..922cc99a6 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -31,6 +31,8 @@ from sapl.comissoes.models import Comissao, Composicao, Participacao from sapl.legacy import scripts from sapl.legacy.models import NormaJuridica as OldNormaJuridica from sapl.legacy.models import TipoNumeracaoProtocolo +from sapl.legacy.scripts.exporta_zope.variaveis_comuns import \ + DIR_DADOS_MIGRACAO from sapl.materia.models import (AcompanhamentoMateria, MateriaLegislativa, Proposicao, StatusTramitacao, TipoDocumento, TipoMateriaLegislativa, TipoProposicao, @@ -731,9 +733,9 @@ def reinicia_sequence(model, id): sequence_name, id)) -DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() NOME_BANCO_LEGADO = DATABASES['legacy']['NAME'] -REPO = git.Repo.init(Path(DIR_DADOS_MIGRACAO, 'repos', NOME_BANCO_LEGADO)) +DIR_REPO = Path(DIR_DADOS_MIGRACAO, 'repos', NOME_BANCO_LEGADO) +REPO = git.Repo.init(DIR_REPO) def dict_representer(dumper, data): diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index c115c7a09..b2a3cfe83 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -16,11 +16,12 @@ from functools import partial import git import magic -import pyaml import yaml +from unipath import Path + import ZODB.DB import ZODB.FileStorage -from unipath import Path +from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE from ZODB.broken import Broken EXTENSOES = { @@ -298,9 +299,6 @@ def _dump_sapl(data_fs_path, destino, salvar): close_db() -DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() - - def repo_execute(repo, cmd, *args): return repo.git.execute(cmd.split() + list(args)) @@ -365,7 +363,7 @@ def dump_sapl(sigla): status = 'completa' if finalizado else 'parcial' repo.index.commit(u'Exportação do zope {}'.format(status)) if finalizado: - repo.git.execute('git tag -f zope'.split()) + repo.git.execute('git tag -f'.split() + [TAG_ZOPE]) if __name__ == "__main__": diff --git a/sapl/legacy/scripts/exporta_zope/variaveis_comuns.py b/sapl/legacy/scripts/exporta_zope/variaveis_comuns.py new file mode 100644 index 000000000..e773f0717 --- /dev/null +++ b/sapl/legacy/scripts/exporta_zope/variaveis_comuns.py @@ -0,0 +1,4 @@ +from unipath import Path + +DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() +TAG_ZOPE = 'zope' From b0e5162dcd439bb718bb58877b65559a7f42ad31 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 20 Apr 2018 17:42:20 -0300 Subject: [PATCH 049/119] =?UTF-8?q?Reaponta=20MEDIA=5FROOT=20para=20repo?= =?UTF-8?q?=20em=20migra=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 +++----- sapl/legacy_migration_settings.py | 8 ++++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 922cc99a6..301b11458 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -31,8 +31,9 @@ from sapl.comissoes.models import Comissao, Composicao, Participacao from sapl.legacy import scripts from sapl.legacy.models import NormaJuridica as OldNormaJuridica from sapl.legacy.models import TipoNumeracaoProtocolo -from sapl.legacy.scripts.exporta_zope.variaveis_comuns import \ - DIR_DADOS_MIGRACAO +from sapl.legacy_migration_settings import (DATABASES, DIR_DADOS_MIGRACAO, + DIR_REPO, NOME_BANCO_LEGADO, + PROJECT_DIR) from sapl.materia.models import (AcompanhamentoMateria, MateriaLegislativa, Proposicao, StatusTramitacao, TipoDocumento, TipoMateriaLegislativa, TipoProposicao, @@ -45,7 +46,6 @@ from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo, StatusTramitacaoAdministrativo) from sapl.sessao.models import (ExpedienteMateria, OrdemDia, RegistroVotacao, TipoResultadoVotacao) -from sapl.settings import DATABASES, PROJECT_DIR from sapl.utils import normalize from .timezonesbrasil import get_timezone @@ -733,8 +733,6 @@ def reinicia_sequence(model, id): sequence_name, id)) -NOME_BANCO_LEGADO = DATABASES['legacy']['NAME'] -DIR_REPO = Path(DIR_DADOS_MIGRACAO, 'repos', NOME_BANCO_LEGADO) REPO = git.Repo.init(DIR_REPO) diff --git a/sapl/legacy_migration_settings.py b/sapl/legacy_migration_settings.py index 0d8844147..96f6a83ad 100644 --- a/sapl/legacy_migration_settings.py +++ b/sapl/legacy_migration_settings.py @@ -3,6 +3,9 @@ import os from decouple import Config, RepositoryEnv from dj_database_url import parse as db_url +from sapl.legacy.scripts.exporta_zope.variaveis_comuns import \ + DIR_DADOS_MIGRACAO + from .settings import * # flake8: noqa config = Config(RepositoryEnv(BASE_DIR.child('legacy', '.env'))) @@ -35,3 +38,8 @@ DEBUG = True HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.BaseSignalProcessor' SHELL_PLUS_DONT_LOAD = ['legacy'] + +NOME_BANCO_LEGADO = DATABASES['legacy']['NAME'] +DIR_REPO = Path(DIR_DADOS_MIGRACAO, 'repos', NOME_BANCO_LEGADO) + +MEDIA_ROOT = DIR_REPO From 6f450820bc2c4ccbb90add6b5a59173a5bff89ed Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 20 Apr 2018 17:42:40 -0300 Subject: [PATCH 050/119] Simplifica comando de migracao --- .../management/commands/migracao_25_31.py | 24 ++----------------- sapl/legacy/scripts/migra_um_db.sh | 2 +- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/sapl/legacy/management/commands/migracao_25_31.py b/sapl/legacy/management/commands/migracao_25_31.py index 27591e058..4541425c4 100644 --- a/sapl/legacy/management/commands/migracao_25_31.py +++ b/sapl/legacy/management/commands/migracao_25_31.py @@ -1,33 +1,13 @@ from django.core import management from django.core.management.base import BaseCommand -from sapl.legacy.migracao import migrar, migrar_dados +from sapl.legacy.migracao import migrar 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( - '--force', - action='store_true', - default=False, - dest='force', - help='Não interativa: pula confirmação de exclusão dos dados', - ) - parser.add_argument( - '--dados', - action='store_true', - default=False, - dest='dados', - help='migra somente dados', - ) - def handle(self, *args, **options): management.call_command('migrate') - somente_dados, interativo = options['dados'], not options['force'] - if somente_dados: - migrar_dados(interativo=interativo) - else: - migrar(interativo=interativo) + migrar(interativo=False) diff --git a/sapl/legacy/scripts/migra_um_db.sh b/sapl/legacy/scripts/migra_um_db.sh index dad480704..613fd0a4d 100755 --- a/sapl/legacy/scripts/migra_um_db.sh +++ b/sapl/legacy/scripts/migra_um_db.sh @@ -19,7 +19,7 @@ if [ $# -eq 1 ]; then echo "--- MIGRACAO ---" | tee -a $LOG echo >> $LOG - DATABASE_NAME=$1 ./manage.py migracao_25_31 --force --dados --settings sapl.legacy_migration_settings 2>&1 | tee -a $LOG + DATABASE_NAME=$1 ./manage.py migracao_25_31 --settings sapl.legacy_migration_settings 2>&1 | tee -a $LOG echo >> $LOG else echo "USO:" From 2896a53c761868b7da5684016d058c18f26b9763 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 20 Apr 2018 18:21:57 -0300 Subject: [PATCH 051/119] Gera pacote de migracao no repo --- sapl/legacy/migracao.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index 3840b1106..4446324c4 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -1,12 +1,10 @@ import subprocess -import tarfile - -from django.conf import settings from sapl.legacy.migracao_dados import REPO, gravar_marco, migrar_dados from sapl.legacy.migracao_documentos import migrar_documentos from sapl.legacy.migracao_usuarios import migrar_usuarios from sapl.legacy.scripts.exporta_zope.variaveis_comuns import TAG_ZOPE +from sapl.legacy_migration_settings import DIR_REPO, NOME_BANCO_LEGADO def adornar_msg(msg): @@ -21,25 +19,23 @@ def migrar(interativo=False): migrar_usuarios(REPO.working_dir) migrar_documentos(REPO) gravar_marco() + gerar_pacote() def gerar_pacote(): - banco = settings.DATABASES['legacy']['NAME'] # backup do banco print('Gerando backup do banco... ', end='', flush=True) - arq_backup = settings.MEDIA_ROOT.child('{}.backup'.format(banco)) + arq_backup = DIR_REPO.child('{}.backup'.format(NOME_BANCO_LEGADO)) backup_cmd = ''' pg_dump --host localhost --port 5432 --username postgres --no-password --format custom --blobs --verbose --file {} {}'''.format( - arq_backup, banco) + arq_backup, NOME_BANCO_LEGADO) subprocess.check_output(backup_cmd.split(), stderr=subprocess.DEVNULL) print('SUCESSO') # tar de media/sapl print('Criando tar de media... ', end='', flush=True) - tar_media = settings.MEDIA_ROOT.child('{}.media.tgz'.format(banco)) - dir_media = settings.MEDIA_ROOT.child('sapl') - with tarfile.open(tar_media, "w:gz") as tar: - tar.add(dir_media, arcname=dir_media.name) + arq_tar = DIR_REPO.child('{}.media.tar'.format(NOME_BANCO_LEGADO)) + subprocess.check_output(['tar', 'cfh', arq_tar, '-C', DIR_REPO, 'sapl']) print('SUCESSO') From 8e3977b1abd7d31faae0f9ef2d89cac43e732109 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 23 Apr 2018 14:50:01 -0300 Subject: [PATCH 052/119] =?UTF-8?q?Corrige=20normaliza=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20dump=20mysql?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 21 +++++++---- sapl/legacy/scripts/normaliza_dump_mysql.py | 40 +++++++++++++++++++++ sapl/legacy/scripts/normaliza_dump_mysql.sh | 28 --------------- 3 files changed, 54 insertions(+), 35 deletions(-) create mode 100755 sapl/legacy/scripts/normaliza_dump_mysql.py delete mode 100755 sapl/legacy/scripts/normaliza_dump_mysql.sh diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 301b11458..3fc2fc2d9 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -12,9 +12,12 @@ from subprocess import PIPE, call import git import pkg_resources import pyaml +import yaml +from pyaml import UnsafePrettyYAMLDumper +from unipath import Path + import pytz import reversion -import yaml from django.apps import apps from django.contrib.auth import get_user_model from django.contrib.auth.models import Group @@ -22,9 +25,6 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.db import connections, transaction from django.db.models import Max, Q -from pyaml import UnsafePrettyYAMLDumper -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 @@ -48,6 +48,7 @@ from sapl.sessao.models import (ExpedienteMateria, OrdemDia, RegistroVotacao, TipoResultadoVotacao) from sapl.utils import normalize +from .scripts.normaliza_dump_mysql import normaliza_dump_mysql from .timezonesbrasil import get_timezone # BASE ###################################################################### @@ -144,6 +145,7 @@ for nome_novo, nome_antigo in (('comissao', 'cod_comissao'), class CampoVirtual(namedtuple('CampoVirtual', 'model related_model')): null = True + CAMPOS_VIRTUAIS_PROPOSICAO = { TipoMateriaLegislativa: CampoVirtual(Proposicao, MateriaLegislativa), TipoDocumento: CampoVirtual(Proposicao, DocumentoAdministrativo) @@ -176,6 +178,7 @@ for related, campo_antigo in [(Parlamentar, 'cod_parlamentar'), def info(msg): print('INFO: ' + msg) + ocorrencias = defaultdict(list) @@ -738,6 +741,8 @@ REPO = git.Repo.init(DIR_REPO) def dict_representer(dumper, data): return dumper.represent_dict(data.items()) + + yaml.add_representer(OrderedDict, dict_representer) @@ -799,9 +804,7 @@ def migrar_dados(interativo=True): 'dumps_mysql', '{}.sql'.format(NOME_BANCO_LEGADO))) assert arq_dump.exists(), 'Dump do mysql faltando: {}'.format(arq_dump) info('Restaurando dump mysql de [{}]'.format(arq_dump)) - normaliza_dump_mysql = Path(scripts.__file__).parent.child( - 'normaliza_dump_mysql.sh') - roda_comando_shell('{} {}'.format(normaliza_dump_mysql, arq_dump)) + normaliza_dump_mysql(arq_dump) roda_comando_shell('mysql -uroot < {}'.format(arq_dump)) # executa ajustes pré-migração, se existirem @@ -1276,6 +1279,8 @@ TIME_FORMAT = '%H:%M:%S' # permite a gravação de tempos puros pelo pretty-yaml def time_representer(dumper, data): return dumper.represent_scalar('!time', data.strftime(TIME_FORMAT)) + + UnsafePrettyYAMLDumper.add_representer(datetime.time, time_representer) @@ -1283,6 +1288,8 @@ UnsafePrettyYAMLDumper.add_representer(datetime.time, time_representer) def time_constructor(loader, node): value = loader.construct_scalar(node) return datetime.datetime.strptime(value, TIME_FORMAT).time() + + yaml.add_constructor(u'!time', time_constructor) diff --git a/sapl/legacy/scripts/normaliza_dump_mysql.py b/sapl/legacy/scripts/normaliza_dump_mysql.py new file mode 100755 index 000000000..a56d74b3a --- /dev/null +++ b/sapl/legacy/scripts/normaliza_dump_mysql.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +import re +import sys + +from unipath import Path + +cabecalho = ''' +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +/*!40000 DROP DATABASE IF EXISTS `{banco}`*/; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{banco}` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `{banco}`; + +''' + + +def normaliza_dump_mysql(nome_arquivo): + arquivo = Path(nome_arquivo).expand() + banco = arquivo.stem + conteudo = arquivo.read_file() + inicio = re.finditer('--\n-- Table structure for table .*\n--\n', conteudo) + inicio = next(inicio).start() + conteudo = cabecalho.format(banco=banco) + conteudo[inicio:] + arquivo.write_file(conteudo) + + +if __name__ == "__main__": + nome_aquivo = sys.argv[1] + normaliza_dump_mysql(nome_aquivo) diff --git a/sapl/legacy/scripts/normaliza_dump_mysql.sh b/sapl/legacy/scripts/normaliza_dump_mysql.sh deleted file mode 100755 index 75bd5435f..000000000 --- a/sapl/legacy/scripts/normaliza_dump_mysql.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -ARQUIVO=$1 -BANCO=`basename $1 | cut -f1 -d.` -TMP=__tmp.sql - -cat << EOF > $TMP - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - -/*!40000 DROP DATABASE IF EXISTS \`$BANCO\`*/; - -CREATE DATABASE /*!32312 IF NOT EXISTS*/ \`$BANCO\` /*!40100 DEFAULT CHARACTER SET latin1 */; - -USE \`$BANCO\`; -EOF - -sed 1,`grep -n '^USE ' $ARQUIVO |cut -f1 -d:`d $ARQUIVO >> $TMP -mv $TMP $ARQUIVO From 13bf1113da688ac6f4387cc944105465c07f4d6d Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 24 Apr 2018 14:45:37 -0300 Subject: [PATCH 053/119] =?UTF-8?q?Reinicia=20sequence=20pela=20pk=20m?= =?UTF-8?q?=C3=A1xima=20do=20legado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 3fc2fc2d9..4b0ad3120 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -12,12 +12,9 @@ from subprocess import PIPE, call import git import pkg_resources import pyaml -import yaml -from pyaml import UnsafePrettyYAMLDumper -from unipath import Path - import pytz import reversion +import yaml from django.apps import apps from django.contrib.auth import get_user_model from django.contrib.auth.models import Group @@ -25,6 +22,9 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.db import connections, transaction from django.db.models import Max, Q +from pyaml import UnsafePrettyYAMLDumper +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 @@ -725,11 +725,6 @@ def fill_dados_basicos(): appconf.save() -def get_last_pk(model): - last_value = model.objects.all().aggregate(Max('pk')) - return last_value['pk__max'] or 0 - - def reinicia_sequence(model, id): sequence_name = '%s_id_seq' % model._meta.db_table exec_sql('ALTER SEQUENCE %s RESTART WITH %s MINVALUE -1;' % ( @@ -903,10 +898,14 @@ def migrar_model(model): def get_id_do_legado(old): return getattr(old, nome_pk) + + ultima_pk_legado = model_legado.objects.all().aggregate( + Max('pk'))['pk__max'] or 0 else: # a pk no legado tem mais de um campo old_records = iter_sql_records(tabela_legado) get_id_do_legado = None + ultima_pk_legado = model_legado.objects.count() ajuste_antes_salvar = AJUSTE_ANTES_SALVAR.get(model) ajuste_depois_salvar = AJUSTE_DEPOIS_SALVAR.get(model) @@ -949,10 +948,13 @@ def migrar_model(model): if ajuste_depois_salvar: ajuste_depois_salvar() - # se configuramos ids explicitamente devemos reiniciar a sequence + # reiniciamos a sequence logo após a última pk do legado + # + # É importante que seja do legado (e não da nova base), + # pois numa nova versão da migração podemos inserir registros + # não migrados antes sem conflito com pks criadas até lá if get_id_do_legado: - last_pk = get_last_pk(model) - reinicia_sequence(model, last_pk + 1) + reinicia_sequence(model, ultima_pk_legado + 1) # apaga registros migrados do legado if sql_delete_legado: From fdbe2956baace4842a5bd5b67b38f8fc7d2c9a30 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 24 Apr 2018 14:53:54 -0300 Subject: [PATCH 054/119] =?UTF-8?q?Interrompe=20migra=C3=A7=C3=A3o=20j?= =?UTF-8?q?=C3=A1=20realizada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao.py | 8 ++++++-- sapl/legacy/migracao_dados.py | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index 4446324c4..4f0d27a08 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -1,6 +1,7 @@ import subprocess -from sapl.legacy.migracao_dados import REPO, gravar_marco, migrar_dados +from sapl.legacy.migracao_dados import (REPO, TAG_MARCO, gravar_marco, info, + migrar_dados) from sapl.legacy.migracao_documentos import migrar_documentos from sapl.legacy.migracao_usuarios import migrar_usuarios from sapl.legacy.scripts.exporta_zope.variaveis_comuns import TAG_ZOPE @@ -12,7 +13,10 @@ def adornar_msg(msg): def migrar(interativo=False): - assert TAG_ZOPE in {t.name for t in REPO.tags}, adornar_msg( + if TAG_MARCO in REPO.tags: + info('A migração já foi feita.') + return + assert TAG_ZOPE in REPO.tags, adornar_msg( 'Antes de migrar ' 'é necessário fazer a exportação de documentos do zope') migrar_dados(interativo=interativo) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 4b0ad3120..0efb9e52b 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -1294,6 +1294,8 @@ def time_constructor(loader, node): yaml.add_constructor(u'!time', time_constructor) +TAG_MARCO = 'marco' + def gravar_marco(): """Grava um dump de todos os dados como arquivos yaml no repo de marco @@ -1319,4 +1321,4 @@ def gravar_marco(): if 'master' not in REPO.heads or REPO.index.diff('HEAD'): # se de fato existe mudança REPO.index.commit('Grava marco') - REPO.git.execute('git tag -f marco'.split()) + REPO.git.execute('git tag -f'.split() + [TAG_MARCO]) From 8d7542b02b1b35199e9d569b38168908a4722e2d Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 24 Apr 2018 17:34:04 -0300 Subject: [PATCH 055/119] =?UTF-8?q?Reduz=20annex=20get=20apenas=20para=20o?= =?UTF-8?q?=20necess=C3=A1rio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit na migração de documentos --- sapl/legacy/migracao_documentos.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index 57446f39c..bfd333d40 100644 --- a/sapl/legacy/migracao_documentos.py +++ b/sapl/legacy/migracao_documentos.py @@ -5,6 +5,7 @@ from os.path import join import yaml from django.db import transaction +from image_cropping.fields import ImageCropField from sapl.base.models import CasaLegislativa from sapl.legacy.migracao_dados import exec_legado @@ -44,11 +45,6 @@ def mover_documento(repo, origem, destino): for c in (origem, destino)] os.makedirs(os.path.dirname(destino), exist_ok=True) repo.git.mv(origem, destino) - # conserta link do git annex (antes do commit) - # em geral é o mais seguro a fazer, - # mas foi especificamente necessário pois o conteúdo das imagens - # é acessado antes do commit pelo cropping de imagem - repo.git.execute('git annex fix'.split() + [destino]) def migrar_logotipo(repo, casa, propriedades): @@ -69,6 +65,7 @@ def migrar_logotipo(repo, casa, propriedades): def migrar_propriedades_da_casa(repo): print('#### Migrando propriedades da casa ####') caminho = join(repo.working_dir, 'sapl_documentos/propriedades.yaml') + repo.git.execute('git annex get'.split() + [caminho]) with open(caminho, 'r') as arquivo: propriedades = yaml.safe_load(arquivo) casa = CasaLegislativa.objects.first() @@ -105,7 +102,8 @@ def migrar_docs_por_ids(repo, model): for campo, base_origem in DOCS[model]: print('#### Migrando {} de {} ####'.format(campo, model.__name__)) - dir_origem, nome_origem = os.path.split(join(repo.working_dir, base_origem)) + dir_origem, nome_origem = os.path.split( + join(repo.working_dir, base_origem)) nome_origem = nome_origem.format('(\d+)') pat = re.compile('^{}\.\w+$'.format(nome_origem)) if not os.path.isdir(dir_origem): @@ -119,6 +117,7 @@ def migrar_docs_por_ids(repo, model): for m in matches if m] objetos = {obj.id: obj for obj in model.objects.all()} upload_to = model._meta.get_field(campo).upload_to + tem_cropping = isinstance(model._meta.get_field(campo), ImageCropField) with transaction.atomic(): for id, origem in ids_origens: @@ -128,6 +127,10 @@ def migrar_docs_por_ids(repo, model): destino = upload_to(obj, os.path.basename(origem)) mover_documento(repo, origem, destino) setattr(obj, campo, destino) + if tem_cropping: + # conserta link do git annex (antes do commit) + # pois o conteúdo das imagens é acessado pelo cropping + repo.git.execute('git annex fix'.split() + [destino]) obj.save() else: msg = ' {} (pk={}) não encontrado para documento em [{}]' @@ -144,6 +147,10 @@ def migrar_documentos(repo): migrar_propriedades_da_casa(repo) + # garante que o conteúdo das fotos dos parlamentares esteja presente + # (necessário para o cropping de imagem) + repo.git.execute('git annex get sapl_documentos/parlamentar'.split()) + for model in [ Parlamentar, MateriaLegislativa, From 6973d45dabad0d86197fa0917221620e365de8b1 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 24 Apr 2018 18:45:53 -0300 Subject: [PATCH 056/119] =?UTF-8?q?Adiciona=20exporta=C3=A7=C3=A3o=20de=20?= =?UTF-8?q?DTML=20Method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scripts/exporta_zope/exporta_zope.py | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index b2a3cfe83..2c595844d 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -17,13 +17,13 @@ from functools import partial import git import magic import yaml -from unipath import Path - import ZODB.DB import ZODB.FileStorage -from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE +from unipath import Path from ZODB.broken import Broken +from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE + EXTENSOES = { 'application/msword': '.doc', 'application/pdf': '.pdf', @@ -94,10 +94,7 @@ def guess_extension(fullname, buffer): raise Exception(msg, e) -def dump_file(doc, path, salvar): - name = doc['__name__'] - fullname = os.path.join(path, name) - +def get_conteudo_file(doc): # A partir daqui usamos dict.pop('...') nos __Broken_state__ # para contornar um "vazamento" de memória que ocorre # ao percorrer a árvore de objetos @@ -119,13 +116,23 @@ def dump_file(doc, path, salvar): output.write(pdata.pop('data')) pdata = br(pdata.pop('next', None)) - conteudo = output.getvalue() + return output.getvalue() + + +def dump_file(doc, path, salvar, get_conteudo=get_conteudo_file): + name = doc['__name__'] + fullname = os.path.join(path, name) + conteudo = get_conteudo(doc) if conteudo: # pula arquivos vazios salvar(fullname, conteudo) return name +def get_conteudo_dtml_method(doc): + return doc['raw'] + + def enumerate_by_key_list(folder, key_list, type_key): for entry in folder.get(key_list, []): id, meta_type = entry['id'], entry[type_key] @@ -229,6 +236,8 @@ def dump_sde(strdoc, path, salvar, tipo): DUMP_FUNCTIONS = { 'File': dump_file, 'Image': dump_file, + 'DTML Method': partial(dump_file, + get_conteudo=get_conteudo_dtml_method), 'Folder': partial(dump_folder, enum=enumerate_folder), 'BTreeFolder2': partial(dump_folder, enum=enumerate_btree), 'SDE-Document': partial(dump_sde, tipo='sde.document'), @@ -311,8 +320,7 @@ def get_annex_hashes(repo): def ajusta_extensao(fullname, conteudo): base, extensao = os.path.splitext(fullname) - if extensao not in ['.xsl', '.xslt', '.yaml']: - # não trocamos as extensões XSL, XSLT e YAML + if extensao not in ['.xsl', '.xslt', '.yaml', '.css']: extensao = guess_extension(fullname, conteudo) return base + extensao From 1924ead0875a4e4320d431b55f5ff5fdcd29c7e8 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 25 Apr 2018 16:04:51 -0300 Subject: [PATCH 057/119] =?UTF-8?q?Interrompe=20exporta=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20docs=20j=C3=A1=20realizada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao.py | 2 +- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index 4f0d27a08..92dd439e1 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -14,7 +14,7 @@ def adornar_msg(msg): def migrar(interativo=False): if TAG_MARCO in REPO.tags: - info('A migração já foi feita.') + info('A migração já está feita.') return assert TAG_ZOPE in REPO.tags, adornar_msg( 'Antes de migrar ' diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 2c595844d..c7442654e 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -354,6 +354,10 @@ def dump_sapl(sigla): destino = DIR_DADOS_MIGRACAO.child('repos', nome_banco_legado) destino.mkdir(parents=True) repo = git.Repo.init(destino) + if TAG_ZOPE in repo.tags: + info('A exportação de documentos já está feita.') + return + repo_execute(repo, 'git annex init') repo_execute(repo, 'git config annex.thin true') From a1a7d2865e94aca8d8d350b268a1291de1fc5617 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 25 Apr 2018 20:10:10 -0300 Subject: [PATCH 058/119] Corrige caminhos XSLT p docs exportados do zope Fix #1846 --- sapl/base/urls.py | 19 +++++++++++++++---- sapl/base/views.py | 25 +++++++++++++++++++------ sapl/legacy/migracao_documentos.py | 8 +++++--- sapl/urls.py | 5 +---- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/sapl/base/urls.py b/sapl/base/urls.py index 0f720071f..849c18131 100644 --- a/sapl/base/urls.py +++ b/sapl/base/urls.py @@ -1,20 +1,22 @@ +import os + from django.conf.urls import include, url from django.contrib.auth import views from django.contrib.auth.decorators import permission_required from django.contrib.auth.views import (password_reset, password_reset_complete, password_reset_confirm, password_reset_done) -from django.views.generic.base import TemplateView +from django.views.generic.base import RedirectView, TemplateView from sapl.base.views import AutorCrud, ConfirmarEmailView, TipoAutorCrud -from sapl.settings import EMAIL_SEND_USER +from sapl.settings import EMAIL_SEND_USER, MEDIA_URL from .apps import AppConfig from .forms import LoginForm, NovaSenhaForm, RecuperarSenhaForm from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud, CreateUsuarioView, DeleteUsuarioView, EditUsuarioView, - HelpTopicView, ListarUsuarioView, RelatorioAtasView, - RelatorioDataFimPrazoTramitacaoView, + HelpTopicView, ListarUsuarioView, LogotipoView, + RelatorioAtasView, RelatorioDataFimPrazoTramitacaoView, RelatorioHistoricoTramitacaoView, RelatorioMateriasPorAnoAutorTipoView, RelatorioMateriasPorAutorView, @@ -120,4 +122,13 @@ urlpatterns = [ url(r'^sistema/search/', SaplSearchView(), name='haystack_search'), + # Folhas XSLT e extras referenciadas por documentos migrados do sapl 2.5 + url(r'^sapl/XSLT/HTML/(?P.*)$', RedirectView.as_view( + url=os.path.join(MEDIA_URL, 'sapl/public/XSLT/HTML/%(path)s'), + permanent=False)), + # url do logotipo usada em documentos migrados do sapl 2.5 + url(r'^sapl/sapl_documentos/props_sapl/logo_casa', + LogotipoView.as_view(), name='logotipo'), + + ] + recuperar_senha + alterar_senha + admin_user diff --git a/sapl/base/views.py b/sapl/base/views.py index 4dbf50ae2..f0e7d2e1b 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -1,5 +1,6 @@ -from django.conf import settings -from django.contrib.auth import get_user_model, update_session_auth_hash +import os + +from django.contrib.auth import get_user_model from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.models import Group from django.contrib.auth.tokens import default_token_generator @@ -12,14 +13,15 @@ from django.template import TemplateDoesNotExist from django.template.loader import get_template from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode -from django.utils.translation import string_concat from django.utils.translation import ugettext_lazy as _ -from django.views.generic import (CreateView, DeleteView, DetailView, FormView, - ListView, UpdateView) -from django.views.generic.base import TemplateView +from django.utils.translation import string_concat +from django.views.generic import (CreateView, DeleteView, FormView, ListView, + UpdateView) +from django.views.generic.base import RedirectView, TemplateView from django_filters.views import FilterView from haystack.views import SearchView +from sapl import settings from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm from sapl.base.models import Autor, TipoAutor from sapl.crud.base import CrudAux, make_pagination @@ -759,3 +761,14 @@ class AlterarSenha(FormView): user.save() return super().form_valid(form) + + +STATIC_LOGO = os.path.join(settings.STATIC_URL, 'img/logo.png') + + +class LogotipoView(RedirectView): + + def get_redirect_url(self, *args, **kwargs): + casa = get_casalegislativa() + logo = casa and casa.logotipo and casa.logotipo.name + return os.path.join(settings.MEDIA_URL, logo) if logo else STATIC_LOGO diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index bfd333d40..2bb17c53e 100644 --- a/sapl/legacy/migracao_documentos.py +++ b/sapl/legacy/migracao_documentos.py @@ -138,12 +138,14 @@ def migrar_docs_por_ids(repo, model): def migrar_documentos(repo): - # aqui supomos que uma pasta chamada sapl_documentos está em + # aqui supomos que as pastas XSLT e sapl_documentos estão em # com o conteúdo exportado do zope - # Os arquivos da pasta serão (git) MOVIDOS para a nova estrutura! + # Os arquivos das pastas serão (git) MOVIDOS para a nova estrutura! # # Isto significa que para rodar novamente esta função é preciso - # restaurar a pasta sapl_documentos ao estado inicial + # restaurar o repo ao estado anterior + + mover_documento(repo, 'XSLT', 'sapl/public/XSLT') migrar_propriedades_da_casa(repo) diff --git a/sapl/urls.py b/sapl/urls.py index b6a5af3e4..07f382013 100644 --- a/sapl/urls.py +++ b/sapl/urls.py @@ -21,6 +21,7 @@ from django.views.generic.base import RedirectView, TemplateView from django.views.static import serve as view_static_server import sapl.api.urls +import sapl.audiencia.urls import sapl.base.urls import sapl.comissoes.urls import sapl.compilacao.urls @@ -33,7 +34,6 @@ import sapl.protocoloadm.urls import sapl.redireciona_urls.urls import sapl.relatorios.urls import sapl.sessao.urls -import sapl.audiencia.urls urlpatterns = [ url(r'^$', TemplateView.as_view(template_name='index.html'), @@ -62,9 +62,6 @@ urlpatterns = [ url(r'^favicon\.ico$', RedirectView.as_view( url='/static/img/favicon.ico', permanent=True)), - # Folhas XSLT e extras referenciadas por documentos migrados do sapl 2.5 - url(r'^XSLT/HTML/(?P.*)$', RedirectView.as_view( - url='/static/XSLT/HTML/%(path)s', permanent=False)), url(r'', include(sapl.redireciona_urls.urls)), ] From b5b528af2fcb673ea954d48ca2950c375c265770 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 25 Apr 2018 20:35:12 -0300 Subject: [PATCH 059/119] Corrige teste de prefixos de urls --- sapl/test_urls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/test_urls.py b/sapl/test_urls.py index 8423a98ed..115572a37 100644 --- a/sapl/test_urls.py +++ b/sapl/test_urls.py @@ -7,7 +7,6 @@ from django.contrib.contenttypes.models import ContentType from django.db import transaction from django.utils.translation import ugettext_lazy as _ from django.utils.translation import string_concat - from sapl.crud.base import PermissionRequiredForAppCrudMixin from sapl.rules.apps import AppConfig, update_groups from scripts.lista_urls import lista_urls @@ -164,7 +163,8 @@ apps_url_patterns_prefixs_and_users = { '/logout', '/ajuda', '/email', - '/recuperar-senha' + '/recuperar-senha', + '/sapl' ]}, 'comissoes': { 'users': {'operador_geral': ['/sistema', '/comissao'], From 499877255f82d14384c2565a28e74e7a1035e49e Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 26 Apr 2018 15:59:15 -0300 Subject: [PATCH 060/119] =?UTF-8?q?Retira=20c=C3=B3digo=20desnecess=C3=A1r?= =?UTF-8?q?io?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/static/XSLT/HTML/.objects | 11 -- sapl/static/XSLT/HTML/estilo.css | 95 ---------------- sapl/static/XSLT/HTML/indicacao.xsl | 51 --------- sapl/static/XSLT/HTML/mocao.xsl | 41 ------- sapl/static/XSLT/HTML/mocao2.xsl | 45 -------- sapl/static/XSLT/HTML/parecer.xsl | 41 ------- sapl/static/XSLT/HTML/pedido.xsl | 47 -------- sapl/static/XSLT/HTML/pedido2.xsl | 53 --------- sapl/static/XSLT/HTML/pl.xsl | 105 ------------------ sapl/static/XSLT/HTML/pl2.xsl | 100 ----------------- sapl/static/XSLT/HTML/requerimento.xsl | 52 --------- sapl/static/XSLT/HTML/requerimento2.xsl | 57 ---------- .../sessao/blocos_resumo/expedientes.html | 2 +- 13 files changed, 1 insertion(+), 699 deletions(-) delete mode 100644 sapl/static/XSLT/HTML/.objects delete mode 100644 sapl/static/XSLT/HTML/estilo.css delete mode 100644 sapl/static/XSLT/HTML/indicacao.xsl delete mode 100644 sapl/static/XSLT/HTML/mocao.xsl delete mode 100644 sapl/static/XSLT/HTML/mocao2.xsl delete mode 100644 sapl/static/XSLT/HTML/parecer.xsl delete mode 100644 sapl/static/XSLT/HTML/pedido.xsl delete mode 100644 sapl/static/XSLT/HTML/pedido2.xsl delete mode 100644 sapl/static/XSLT/HTML/pl.xsl delete mode 100644 sapl/static/XSLT/HTML/pl2.xsl delete mode 100644 sapl/static/XSLT/HTML/requerimento.xsl delete mode 100644 sapl/static/XSLT/HTML/requerimento2.xsl diff --git a/sapl/static/XSLT/HTML/.objects b/sapl/static/XSLT/HTML/.objects deleted file mode 100644 index ca1ce01f2..000000000 --- a/sapl/static/XSLT/HTML/.objects +++ /dev/null @@ -1,11 +0,0 @@ -estilo.css:DTML Method -indicacao.xsl:File -mocao.xsl:File -mocao2.xsl:File -parecer.xsl:File -pedido.xsl:File -pedido2.xsl:File -pl.xsl:File -pl2.xsl:File -requerimento.xsl:File -requerimento2.xsl:File diff --git a/sapl/static/XSLT/HTML/estilo.css b/sapl/static/XSLT/HTML/estilo.css deleted file mode 100644 index aac85f176..000000000 --- a/sapl/static/XSLT/HTML/estilo.css +++ /dev/null @@ -1,95 +0,0 @@ - body { - font-family: Times; - text-align: justify; - font-size: 12 pt; - margin: 5px 1cm 20px 2cm; -} - - p, - .p{ - font-family: Times; - text-align: justify; - font-size: 12pt; - text-indent: 1.5cm; - margin: 40px 0 20px 0; - } - - .pequeno { - font-family: Times; - text-align: left; - font-size: 13pt; - margin: 0px 0 0px 0; - } - - .cabecalho { - font-family: Times; - font-weight:bold; - text-align: left; - font-size: 15pt; - margin: 10px 0 0px 0; - } - - .texto { - font-family: Times; - text-align: justify; - font-size: 12pt; - margin: 0px 0px 0px 0px; - } - - .data { - text-align: right; - } - - .autor { - text-align: center; - } - - .center { - text-align: center; - } - - .semrecuo { - text-indent: 0; - } - - .ementa { - text-align: justify; - margin-left: 50%; - text-indent: 0; - } - - .titulos1 { - text-align: center; - margin: 10px 0 0px 0; - } - - .titulos2 { - text-align: center; - margin: 0px 0 0px 0; - } - - p.artigo { - text-align: justify; - text-indent: 1cm; - margin: 10px 0 0px 0; -} - - -#imagem { - float:left; - } - -#autores - { - -moz-column-count:3; /* Firefox */ - -webkit-column-count:3; /* Safari and Chrome */ - width:50px; - - } - -#col1 { width: 33%; float: left; center: 10px; } -#col2 { width: 33%; float: left; center: 10px; } -#col3 { width: 33%; float: left; center: 10px; } - - - diff --git a/sapl/static/XSLT/HTML/indicacao.xsl b/sapl/static/XSLT/HTML/indicacao.xsl deleted file mode 100644 index edb4575c7..000000000 --- a/sapl/static/XSLT/HTML/indicacao.xsl +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - -
-
-

-


-

Câmara Municipal de Agudo

-

Estado do Rio Grande do Sul





-
-

- -
- -

-
- - -

-
- - -

- -
- -

-
- - -

-
- -
diff --git a/sapl/static/XSLT/HTML/mocao.xsl b/sapl/static/XSLT/HTML/mocao.xsl deleted file mode 100644 index adb7ef3c9..000000000 --- a/sapl/static/XSLT/HTML/mocao.xsl +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/sapl/static/XSLT/HTML/mocao2.xsl b/sapl/static/XSLT/HTML/mocao2.xsl deleted file mode 100644 index 14f71c982..000000000 --- a/sapl/static/XSLT/HTML/mocao2.xsl +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - -
-
- -


-

Câmara Municipal de Agudo

-

Estado do Rio Grande do Sul





-
- - - -
- - -

-
- - -

-
- - -

-
- - -

-
- - -

-
- -
\ No newline at end of file diff --git a/sapl/static/XSLT/HTML/parecer.xsl b/sapl/static/XSLT/HTML/parecer.xsl deleted file mode 100644 index 14100320e..000000000 --- a/sapl/static/XSLT/HTML/parecer.xsl +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/sapl/static/XSLT/HTML/pedido.xsl b/sapl/static/XSLT/HTML/pedido.xsl deleted file mode 100644 index 9e5002d01..000000000 --- a/sapl/static/XSLT/HTML/pedido.xsl +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/sapl/static/XSLT/HTML/pedido2.xsl b/sapl/static/XSLT/HTML/pedido2.xsl deleted file mode 100644 index facc154c6..000000000 --- a/sapl/static/XSLT/HTML/pedido2.xsl +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - -
-
- -


-

Câmara Municipal de Agudo

-

Estado do Rio Grande do Sul





-
- - - -
- - -

-
- - -

-
- - -

-
- - -

-
- - -

-
- - -

-
- - -

-
- -
\ No newline at end of file diff --git a/sapl/static/XSLT/HTML/pl.xsl b/sapl/static/XSLT/HTML/pl.xsl deleted file mode 100644 index 0da6eddb4..000000000 --- a/sapl/static/XSLT/HTML/pl.xsl +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - <xsl:value-of select="@id"/> - - - - - - - - - -
-

PROPOSIÇÃO

-
- -
- -

- -

-
- -

- -

-
- -

- -

-
- -

- -

-
- -

- -

-
- -

- -

-
- -

- -

-
- -

- -

-
- -

- -

-
- -

- -

-
- -
-

JUSTIFICATIVA

-
-

- -

-
- -
-

MENSAGEM

-
-

- -

-
-
\ No newline at end of file diff --git a/sapl/static/XSLT/HTML/pl2.xsl b/sapl/static/XSLT/HTML/pl2.xsl deleted file mode 100644 index f68506f95..000000000 --- a/sapl/static/XSLT/HTML/pl2.xsl +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - -
-
- -


-

Câmara Municipal de Agudo

-

Estado do Rio Grande do Sul





-
- - - - -
- - -

-
- - -

-
- - -

-
- - -

-

-
- - -

-

-
- - -

-

-
- - -

-

-
- - -

-

-
- - -

-

-
- - -

-
- - -

-
- - -

-
- - -

-
- - -

-
- - -

-
- - -

-
- - -

-
- -
\ No newline at end of file diff --git a/sapl/static/XSLT/HTML/requerimento.xsl b/sapl/static/XSLT/HTML/requerimento.xsl deleted file mode 100644 index 58f202b09..000000000 --- a/sapl/static/XSLT/HTML/requerimento.xsl +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/sapl/static/XSLT/HTML/requerimento2.xsl b/sapl/static/XSLT/HTML/requerimento2.xsl deleted file mode 100644 index 3d63f6cf8..000000000 --- a/sapl/static/XSLT/HTML/requerimento2.xsl +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - -
-
- -


-

Câmara Municipal de Agudo

-

Estado do Rio Grande do Sul





-
- - - -
- - -

-
- - -

-
- - -

-
- - -

-
- - -

- -
- -

- -
- -

-
- - -

-
- -
\ No newline at end of file diff --git a/sapl/templates/sessao/blocos_resumo/expedientes.html b/sapl/templates/sessao/blocos_resumo/expedientes.html index e233fcb58..5462fd3f3 100644 --- a/sapl/templates/sessao/blocos_resumo/expedientes.html +++ b/sapl/templates/sessao/blocos_resumo/expedientes.html @@ -6,7 +6,7 @@ {{e.tipo}}:

-
+

{{e.conteudo|safe}}

From 68dd711d7f318e27f01f8a42358d38966a1b0a62 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 26 Apr 2018 15:59:42 -0300 Subject: [PATCH 061/119] Remove style ao migrar ExpedienteSessao Fix #1844 --- sapl/legacy/migracao_dados.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 0efb9e52b..e40406447 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -15,6 +15,7 @@ import pyaml import pytz import reversion import yaml +from bs4 import BeautifulSoup from django.apps import apps from django.contrib.auth import get_user_model from django.contrib.auth.models import Group @@ -44,8 +45,8 @@ from sapl.parlamentares.models import (Legislatura, Mandato, Parlamentar, Partido, TipoAfastamento) from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo, StatusTramitacaoAdministrativo) -from sapl.sessao.models import (ExpedienteMateria, OrdemDia, RegistroVotacao, - TipoResultadoVotacao) +from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao, OrdemDia, + RegistroVotacao, TipoResultadoVotacao) from sapl.utils import normalize from .scripts.normaliza_dump_mysql import normaliza_dump_mysql @@ -1245,6 +1246,21 @@ def adjust_tiporesultadovotacao(new, old): {'pk': new.pk, 'nome': new.nome}) +def remove_style(conteudo): + if 'style' not in conteudo: + return conteudo # atalho que acelera muito os casos sem style + + soup = BeautifulSoup(conteudo, 'html.parser') + for tag in soup.recursiveChildGenerator(): + if hasattr(tag, 'attrs'): + tag.attrs = {k: v for k, v in tag.attrs.items() if k != 'style'} + return str(soup) + + +def adjust_expediente_sessao(new, old): + new.conteudo = remove_style(new.conteudo) + + AJUSTE_ANTES_SALVAR = { Autor: adjust_autor, TipoAutor: adjust_tipo_autor, @@ -1266,6 +1282,7 @@ AJUSTE_ANTES_SALVAR = { StatusTramitacaoAdministrativo: adjust_statustramitacaoadm, Tramitacao: adjust_tramitacao, TipoResultadoVotacao: adjust_tiporesultadovotacao, + ExpedienteSessao: adjust_expediente_sessao, } AJUSTE_DEPOIS_SALVAR = { From 022c6f478d4ca5b87b979139fe35a46c36461c07 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 26 Apr 2018 17:35:45 -0300 Subject: [PATCH 062/119] Remover pacote de migracao antes de gerar --- sapl/legacy/migracao.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index 92dd439e1..66668a62f 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -31,6 +31,7 @@ def gerar_pacote(): # backup do banco print('Gerando backup do banco... ', end='', flush=True) arq_backup = DIR_REPO.child('{}.backup'.format(NOME_BANCO_LEGADO)) + arq_backup.remove() backup_cmd = ''' pg_dump --host localhost --port 5432 --username postgres --no-password --format custom --blobs --verbose --file {} {}'''.format( @@ -41,5 +42,6 @@ def gerar_pacote(): # tar de media/sapl print('Criando tar de media... ', end='', flush=True) arq_tar = DIR_REPO.child('{}.media.tar'.format(NOME_BANCO_LEGADO)) + arq_tar.remove() subprocess.check_output(['tar', 'cfh', arq_tar, '-C', DIR_REPO, 'sapl']) print('SUCESSO') From 4940f72194b6be3ae1ef149d4975b4f71d5ad4f1 Mon Sep 17 00:00:00 2001 From: Edward Date: Fri, 27 Apr 2018 13:08:03 -0300 Subject: [PATCH 063/119] Fixes #1915 (#1916) --- sapl/materia/forms.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 3d455ea29..e083e7fec 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -582,8 +582,18 @@ class AnexadaForm(ModelForm): msg = _('A matéria a ser anexada não existe no cadastro' ' de matérias legislativas.') raise ValidationError(msg) - else: - cleaned_data['materia_anexada'] = materia_anexada + + materia_principal = self.instance.materia_principal + if materia_principal == materia_anexada: + raise ValidationError(_('Matéria não pode ser anexada a si mesma')) + + is_anexada = Anexada.objects.filter(materia_principal=materia_principal, + materia_anexada=materia_anexada + ).exists() + if is_anexada: + raise ValidationError(_('Materia já se encontra anexada')) + + cleaned_data['materia_anexada'] = materia_anexada return cleaned_data From c5e9d8ab5e304f02af2b913bed4c2bc143aaddab Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 27 Apr 2018 14:53:31 -0300 Subject: [PATCH 064/119] =?UTF-8?q?HOT-FIX:=20melhora=20o=20desempenho=20d?= =?UTF-8?q?e=20pesquisas=20na=20tela=20de=20relat=C3=B3rios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/base/forms.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 1a0637a22..513c3a7ca 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -525,6 +525,11 @@ class RelatorioAtasFilterSet(django_filters.FilterSet): model = SessaoPlenaria fields = ['data_inicio'] + @property + def qs(self): + parent = super(RelatorioAtasFilterSet, self).qs + return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero') + def __init__(self, *args, **kwargs): super(RelatorioAtasFilterSet, self).__init__( *args, **kwargs) @@ -588,7 +593,7 @@ class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet): @property def qs(self): parent = super(RelatorioHistoricoTramitacaoFilterSet, self).qs - return parent.distinct().order_by('-ano', 'tipo', 'numero') + return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero') class Meta: model = MateriaLegislativa @@ -628,7 +633,7 @@ class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet): @property def qs(self): parent = super(RelatorioDataFimPrazoTramitacaoFilterSet, self).qs - return parent.distinct().order_by('-ano', 'tipo', 'numero') + return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero') class Meta: model = MateriaLegislativa From 47d295c90c8dbe09edf3d026fe2e25f1a6c6e2cf Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 27 Apr 2018 15:23:23 -0300 Subject: [PATCH 065/119] =?UTF-8?q?Adiciona=20scraping=20de=20proposi?= =?UTF-8?q?=C3=A7=C3=B5es=20do=20SDE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/base/urls.py | 4 ++-- sapl/legacy/migracao.py | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/sapl/base/urls.py b/sapl/base/urls.py index 849c18131..b52d46ad6 100644 --- a/sapl/base/urls.py +++ b/sapl/base/urls.py @@ -123,11 +123,11 @@ urlpatterns = [ url(r'^sistema/search/', SaplSearchView(), name='haystack_search'), # Folhas XSLT e extras referenciadas por documentos migrados do sapl 2.5 - url(r'^sapl/XSLT/HTML/(?P.*)$', RedirectView.as_view( + url(r'^(sapl/)?XSLT/HTML/(?P.*)$', RedirectView.as_view( url=os.path.join(MEDIA_URL, 'sapl/public/XSLT/HTML/%(path)s'), permanent=False)), # url do logotipo usada em documentos migrados do sapl 2.5 - url(r'^sapl/sapl_documentos/props_sapl/logo_casa', + url(r'^(sapl/)?sapl_documentos/props_sapl/logo_casa', LogotipoView.as_view(), name='logotipo'), diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index 66668a62f..4509d8ba6 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -1,4 +1,8 @@ import subprocess +from getpass import getpass + +import requests +from unipath import Path from sapl.legacy.migracao_dados import (REPO, TAG_MARCO, gravar_marco, info, migrar_dados) @@ -6,6 +10,7 @@ from sapl.legacy.migracao_documentos import migrar_documentos from sapl.legacy.migracao_usuarios import migrar_usuarios from sapl.legacy.scripts.exporta_zope.variaveis_comuns import TAG_ZOPE from sapl.legacy_migration_settings import DIR_REPO, NOME_BANCO_LEGADO +from sapl.materia.models import Proposicao def adornar_msg(msg): @@ -45,3 +50,38 @@ def gerar_pacote(): arq_tar.remove() subprocess.check_output(['tar', 'cfh', arq_tar, '-C', DIR_REPO, 'sapl']) print('SUCESSO') + + +PROPOSICAO_UPLOAD_TO = Proposicao._meta.get_field('texto_original').upload_to + + +def salva_conteudo_do_sde(proposicao, conteudo): + caminho_relativo = PROPOSICAO_UPLOAD_TO( + proposicao, 'proposicao_sde_{}.xml'.format(proposicao.pk)) + caminho_absoluto = Path(REPO.working_dir, caminho_relativo) + caminho_absoluto.parent.mkdir(parents=True) + with open(caminho_absoluto, 'wb') as arq: + arq.write(conteudo) + proposicao.texto_original = caminho_relativo + proposicao.save() + + +def scrap_sde(url, usuario, senha=None): + if not senha: + senha = getpass() + + # login + session = requests.session() + res = session.post('{}?retry=1'.format(url), + {'__ac_name': usuario, '__ac_password': senha}) + assert res.status_code == 200 + + url_proposicao = '{}/sapl_documentos/proposicao/{}/renderXML?xsl=__default__' # noqa + total = Proposicao.objects.count() + for num, proposicao in enumerate(Proposicao.objects.all()): + pk = proposicao.pk + res = session.get(url_proposicao.format(url, pk)) + print("pk: {} status: {} (progresso: {:.2%})".format( + pk, res.status_code, num / total)) + if res.status_code == 200: + salva_conteudo_do_sde(proposicao, res.content) From 0b4ead32702a033ca810c8d0c5bdf7df05671b09 Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Wed, 2 May 2018 14:17:40 -0300 Subject: [PATCH 066/119] fix #1898 (#1917) * Fix #1898 * Fix #1898 * Add "remover_acentos" to the sapl utils * Remove the import unicodedata --- sapl/sessao/views.py | 6 +++--- sapl/utils.py | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index d7844b3ce..5beec02ad 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -34,7 +34,7 @@ from sapl.parlamentares.models import (Filiacao, Legislatura, Mandato, Parlamentar, SessaoLegislativa) from sapl.sessao.apps import AppConfig from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm -from sapl.utils import show_results_filter_set +from sapl.utils import show_results_filter_set, remover_acentos from .forms import (AdicionarVariasMateriasFilterSet, BancadaForm, BlocoForm, ExpedienteForm, ListMateriaForm, MesaForm, @@ -385,14 +385,14 @@ def customize_link_materia(context, pk, has_permission, is_expediente): context['rows'][i][3] = (resultado, None) return context - + def get_presencas_generic(model, sessao, legislatura): presencas = model.objects.filter( sessao_plenaria=sessao) presentes = [p.parlamentar for p in presencas] - presentes = sorted(presentes, key=lambda x: x.nome_parlamentar) + presentes = sorted(presentes, key=lambda x: remover_acentos(x.nome_parlamentar)) mandato = Mandato.objects.filter( legislatura=legislatura).order_by('parlamentar__nome_parlamentar') diff --git a/sapl/utils.py b/sapl/utils.py index 0fa20f706..8045f0e0b 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -2,6 +2,7 @@ import hashlib import logging import os import re +import unicodedata from functools import wraps from operator import itemgetter from unicodedata import normalize as unicodedata_normalize @@ -732,3 +733,7 @@ def RemoveTag(texto): i += 1 return textoSaida + +def remover_acentos(string): + return ''.join([c for c in unicodedata.normalize('NFD', string) + if unicodedata.category(c) != 'Mn']) \ No newline at end of file From cfb218f5dab5e62ae6c966de0614c2b4b8ad76be Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 2 May 2018 14:35:29 -0300 Subject: [PATCH 067/119] Release: 3.1.76 --- 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 48e9a3b30..f721b66f0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.75 + image: interlegis/sapl:3.1.76 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index edf2dc502..da929d87c 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.75', + version='3.1.76', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 0c1ef242baee3b103c782c971a581703c8da8106 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 2 May 2018 15:34:37 -0300 Subject: [PATCH 068/119] =?UTF-8?q?Adiciona=20um=20script=20simples=20para?= =?UTF-8?q?=20gerar=20vers=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- release.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 release.sh diff --git a/release.sh b/release.sh new file mode 100755 index 000000000..78fee9187 --- /dev/null +++ b/release.sh @@ -0,0 +1,19 @@ +#/bin/bash + +VERSION=`git describe --tags --abbrev=0` +LAST_DIGIT=`echo $VERSION | cut -f 3 -d '.'` +MAIN_REV=`echo $VERSION | cut -f 1,2 -d '.'` +NEXT_NUMBER=$(($LAST_DIGIT + 1)) +NEXT_VERSION=$MAIN_REV'.'$NEXT_NUMBER + +sed -e s/$VERSION/$NEXT_VERSION/g docker-compose.yml > tmp1 +mv tmp1 docker-compose.yml + +sed -e s/$VERSION/$NEXT_VERSION/g setup.py > tmp2 +mv tmp2 setup.py + +git add docker-compose.yml setup.py +git commit -m "Release: $NEXT_VERSION" +git tag $NEXT_VERSION +git push origin $NEXT_VERSION +git push origin From fb38c73090f1a053755cba5dbc4f4f8c9d8d1440 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 3 May 2018 10:31:46 -0300 Subject: [PATCH 069/119] Fix #1921 --- sapl/parlamentares/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/parlamentares/views.py b/sapl/parlamentares/views.py index b56215648..093bb83bd 100644 --- a/sapl/parlamentares/views.py +++ b/sapl/parlamentares/views.py @@ -192,7 +192,7 @@ class ColigacaoCrud(CrudAux): help_topic = 'coligacao' class ListView(CrudAux.ListView): - ordering = ('-numero_votos', 'nome') + ordering = ('legislatura', '-nome') def get_context_data(self, **kwargs): context = super(ColigacaoCrud.ListView, self).get_context_data( From c2aea79ff5a80ae1eb733c511344d503c1084c33 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 3 May 2018 10:56:15 -0300 Subject: [PATCH 070/119] Fixes #1920 --- .../migrations/0014_auto_20180503_1055.py | 23 +++++++++++++++++++ sapl/comissoes/models.py | 2 ++ sapl/comissoes/views.py | 7 +++++- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 sapl/comissoes/migrations/0014_auto_20180503_1055.py diff --git a/sapl/comissoes/migrations/0014_auto_20180503_1055.py b/sapl/comissoes/migrations/0014_auto_20180503_1055.py new file mode 100644 index 000000000..7a2524fed --- /dev/null +++ b/sapl/comissoes/migrations/0014_auto_20180503_1055.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2018-05-03 13:55 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0013_auto_20180312_1533'), + ] + + operations = [ + migrations.AlterModelOptions( + name='composicao', + options={'ordering': ['periodo'], 'verbose_name': 'Composição de Comissão', 'verbose_name_plural': 'Composições de Comissão'}, + ), + migrations.AlterModelOptions( + name='periodo', + options={'ordering': ['-data_inicio', '-data_fim'], 'verbose_name': 'Período de composição de Comissão', 'verbose_name_plural': 'Períodos de composição de Comissão'}, + ), + ] diff --git a/sapl/comissoes/models.py b/sapl/comissoes/models.py index f0b1b8d8b..0c3240fc6 100644 --- a/sapl/comissoes/models.py +++ b/sapl/comissoes/models.py @@ -105,6 +105,7 @@ class Periodo(models.Model): # PeriodoCompComissao class Meta: verbose_name = _('Período de composição de Comissão') verbose_name_plural = _('Períodos de composição de Comissão') + ordering = ['-data_inicio', '-data_fim'] def __str__(self): if self.data_inicio and self.data_fim: @@ -140,6 +141,7 @@ class Composicao(models.Model): # IGNORE class Meta: verbose_name = _('Composição de Comissão') verbose_name_plural = _('Composições de Comissão') + ordering = ['periodo'] def __str__(self): return '%s: %s' % (self.comissao.sigla, self.periodo) diff --git a/sapl/comissoes/views.py b/sapl/comissoes/views.py index 82c3a79c1..c5870389e 100644 --- a/sapl/comissoes/views.py +++ b/sapl/comissoes/views.py @@ -51,6 +51,9 @@ class PeriodoComposicaoCrud(CrudAux): class UpdateView(CrudAux.UpdateView): form_class = PeriodoForm + # class ListView(CrudAux.ListView): + + class ParticipacaoCrud(MasterDetailCrud): model = Participacao parent_field = 'composicao__comissao' @@ -112,7 +115,9 @@ class ComposicaoCrud(MasterDetailCrud): composicao_pk = self.take_composicao_pk() if composicao_pk == 0: - ultima_composicao = context['composicao_list'].last() + # Composicao eh ordenada por Periodo, que por sua vez esta em + # ordem descrescente de data de inicio (issue #1920) + ultima_composicao = context['composicao_list'].first() if ultima_composicao: context['composicao_pk'] = ultima_composicao.pk else: From 2c034a84b393ff8a62504bf32fa4837e15c32d0c Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 3 May 2018 10:57:33 -0300 Subject: [PATCH 071/119] =?UTF-8?q?Imprime=20arquivos=20anteriores=20na=20?= =?UTF-8?q?exporta=C3=A7=C3=A3o=20de=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index c7442654e..e84a4d13b 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -333,7 +333,9 @@ def build_salvar(repo): def salvar(fullname, conteudo): sha = hashlib.sha256() sha.update(conteudo) - if sha.hexdigest() not in hashes: + if sha.hexdigest() in hashes: + print('- hash encontrado - {}'.format(fullname)) + else: fullname = ajusta_extensao(fullname, conteudo) if os.path.exists(fullname): # destrava arquivo pré-existente (o conteúdo mudou) @@ -355,7 +357,7 @@ def dump_sapl(sigla): destino.mkdir(parents=True) repo = git.Repo.init(destino) if TAG_ZOPE in repo.tags: - info('A exportação de documentos já está feita.') + print('A exportação de documentos já está feita -- abortando') return repo_execute(repo, 'git annex init') From 0690a77bab64901a3d95466c9c28ebee8c394af8 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 3 May 2018 11:51:32 -0300 Subject: [PATCH 072/119] =?UTF-8?q?Continua=20exporta=C3=A7=C3=A3o=20de=20?= =?UTF-8?q?docs=20mesmo=20c=20tipos=20n=C3=A3o=20reconhecidos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index e84a4d13b..a75200949 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -78,20 +78,21 @@ def br(obj): def guess_extension(fullname, buffer): mime = magic.from_buffer(buffer, mime=True) - try: - return EXTENSOES[mime] - except KeyError as e: + extensao = EXTENSOES.get(mime) + if extensao is not None: + return extensao + else: possibilidades = '\n'.join( [" '{}': '{}',".format(mime, ext) for ext in mimetypes.guess_all_extensions(mime)]) - msg = '''Extensão não conhecida para o arquivo: {} + print('''Extensão não conhecida para o arquivo: {} e mimetype: {} Algumas possibilidades são: {} Atualize o código do dicionário EXTENSOES! '''.format(fullname, mime, possibilidades) - print(msg) - raise Exception(msg, e) + ) + return '.DESCONHECIDO.{}'.format(mime.replace('/', '__')) def get_conteudo_file(doc): From 64716f175bd7427ec90581d6aa0408c0e28daf51 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 3 May 2018 13:52:11 -0300 Subject: [PATCH 073/119] =?UTF-8?q?HOT-FIX:=20desabilitando=20speedinfo=20?= =?UTF-8?q?na=20vers=C3=A3o=201.9=20do=20Django?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/settings.py b/sapl/settings.py index 22377226b..ca24b9f02 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -127,7 +127,7 @@ MIDDLEWARE_CLASSES = ( 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', - 'speedinfo.middleware.ProfilerMiddleware', + # 'speedinfo.middleware.ProfilerMiddleware', # Bug na versão 1.9 ) CACHES = { From 0226923a668070c767288b7cd9377f0fd77444ed Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 3 May 2018 17:55:58 -0300 Subject: [PATCH 074/119] Reporta contagens diferentes na btree ao exportar docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ao invés de lancçar exceção --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index a75200949..63d0ed09e 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -155,7 +155,11 @@ def enumerate_btree(folder): obj, meta_type = br(obj), type(obj).__name__ yield id, obj, meta_type # verificação de consistência - assert contagem_esperada == contagem_real + if contagem_esperada != contagem_real: + print('ATENÇÃO: contagens diferentes na btree: ' + '{} esperada: {} real: {}'.format(folder, + contagem_esperada, + contagem_real)) nao_identificados = defaultdict(list) From 71665929c558820e7ee5509228c55f4acc46a597 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 3 May 2018 19:14:58 -0300 Subject: [PATCH 075/119] Grava marco com dump do postgres --- sapl/legacy/migracao.py | 14 +------------- sapl/legacy/migracao_dados.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index 4509d8ba6..059e49164 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -28,21 +28,9 @@ def migrar(interativo=False): migrar_usuarios(REPO.working_dir) migrar_documentos(REPO) gravar_marco() - gerar_pacote() -def gerar_pacote(): - - # backup do banco - print('Gerando backup do banco... ', end='', flush=True) - arq_backup = DIR_REPO.child('{}.backup'.format(NOME_BANCO_LEGADO)) - arq_backup.remove() - backup_cmd = ''' - pg_dump --host localhost --port 5432 --username postgres --no-password - --format custom --blobs --verbose --file {} {}'''.format( - arq_backup, NOME_BANCO_LEGADO) - subprocess.check_output(backup_cmd.split(), stderr=subprocess.DEVNULL) - print('SUCESSO') +def compactar_media(): # tar de media/sapl print('Criando tar de media... ', end='', flush=True) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index e40406447..0f1e4d6dc 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -1,6 +1,7 @@ import datetime import os import re +import subprocess import traceback from collections import OrderedDict, defaultdict, namedtuple from datetime import date @@ -1333,6 +1334,17 @@ def gravar_marco(): with open(nome_arq, 'w') as arq: pyaml.dump(data, arq) + # backup do banco + print('Gerando backup do banco... ', end='', flush=True) + arq_backup = DIR_REPO.child('{}.backup'.format(NOME_BANCO_LEGADO)) + arq_backup.remove() + backup_cmd = ''' + pg_dump --host localhost --port 5432 --username postgres --no-password + --format custom --blobs --verbose --file {} {}'''.format( + arq_backup, NOME_BANCO_LEGADO) + subprocess.check_output(backup_cmd.split(), stderr=subprocess.DEVNULL) + print('SUCESSO') + # salva mudanças REPO.git.add([dir_dados.name]) if 'master' not in REPO.heads or REPO.index.diff('HEAD'): From 3470756fb383aaf87cb5cb0b330cb6e3d9a59b53 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 4 May 2018 11:46:59 -0300 Subject: [PATCH 076/119] Corrige teste de prefixos de urls --- sapl/test_urls.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sapl/test_urls.py b/sapl/test_urls.py index 115572a37..0f1671c98 100644 --- a/sapl/test_urls.py +++ b/sapl/test_urls.py @@ -7,6 +7,7 @@ from django.contrib.contenttypes.models import ContentType from django.db import transaction from django.utils.translation import ugettext_lazy as _ from django.utils.translation import string_concat + from sapl.crud.base import PermissionRequiredForAppCrudMixin from sapl.rules.apps import AppConfig, update_groups from scripts.lista_urls import lista_urls @@ -164,7 +165,8 @@ apps_url_patterns_prefixs_and_users = { '/ajuda', '/email', '/recuperar-senha', - '/sapl' + '/sapl', + '/XSLT', ]}, 'comissoes': { 'users': {'operador_geral': ['/sistema', '/comissao'], From 40da78b14aee86f47af07edf4da949a9190da06e Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 7 May 2018 14:17:35 -0300 Subject: [PATCH 077/119] Fix #1925 (#1926) --- sapl/sessao/views.py | 5 +++++ sapl/templates/sessao/expediente.html | 1 + 2 files changed, 6 insertions(+) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 5beec02ad..746bbfec1 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -1448,6 +1448,11 @@ class ExpedienteView(FormMixin, DetailView): self.object = self.get_object() form = ExpedienteForm(request.POST) + if 'apagar-expediente' in request.POST: + ExpedienteSessao.objects.filter( + sessao_plenaria_id=self.object.id).delete() + return self.form_valid(form) + if form.is_valid(): list_tipo = request.POST.getlist('tipo') list_conteudo = request.POST.getlist('conteudo') diff --git a/sapl/templates/sessao/expediente.html b/sapl/templates/sessao/expediente.html index 940d73d97..106840b88 100644 --- a/sapl/templates/sessao/expediente.html +++ b/sapl/templates/sessao/expediente.html @@ -28,6 +28,7 @@
+ {% endif %} From 605165f8caff02112a140dec4ee650a515759a11 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 7 May 2018 14:17:59 -0300 Subject: [PATCH 078/119] Fix 1918 (#1924) --- sapl/norma/views.py | 3 +-- sapl/templates/norma/normajuridica_detail.html | 2 +- sapl/templates/norma/subnav.yaml | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sapl/norma/views.py b/sapl/norma/views.py index d74bc8857..fd5396353 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -40,10 +40,9 @@ class NormaRelacionadaCrud(MasterDetailCrud): model = NormaRelacionada parent_field = 'norma_principal' help_topic = 'norma_juridica' - public = [RP_LIST, RP_DETAIL] class BaseMixin(MasterDetailCrud.BaseMixin): - list_field_names = ['norma_relacionada'] + list_field_names = ['norma_relacionada', 'tipo_vinculo'] class CreateView(MasterDetailCrud.CreateView): form_class = NormaRelacionadaForm diff --git a/sapl/templates/norma/normajuridica_detail.html b/sapl/templates/norma/normajuridica_detail.html index ed52564ed..6dcd3d592 100644 --- a/sapl/templates/norma/normajuridica_detail.html +++ b/sapl/templates/norma/normajuridica_detail.html @@ -35,7 +35,7 @@
-

Relacionamentos

+

Normas Relacionadas

{% if object.get_normas_relacionadas.0|length > 0 %} {% for p in object.get_normas_relacionadas.0 %} diff --git a/sapl/templates/norma/subnav.yaml b/sapl/templates/norma/subnav.yaml index 0599efdfb..d050a469f 100644 --- a/sapl/templates/norma/subnav.yaml +++ b/sapl/templates/norma/subnav.yaml @@ -2,8 +2,9 @@ - title: {% trans 'Início' %} url: normajuridica_detail -- title: {% trans 'Normas Relacionadas' %} +- title: {% trans 'Alterações em Outras Normas' %} url: normarelacionada_list + check_permission: norma.normarelacionada_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 05145d0d6e93ad5e860f13f5289592c5b4ece6e8 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 7 May 2018 14:28:59 -0300 Subject: [PATCH 079/119] Fix #1874 removendo acento (#1923) * Fix #1874 removendo acento * Fix #1874 sem remover acentos --- sapl/sessao/views.py | 10 ++++++---- sapl/templates/sessao/mesa.html | 2 +- sapl/utils.py | 3 +-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 746bbfec1..db3875677 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -4,7 +4,7 @@ from operator import itemgetter from django.contrib import messages from django.contrib.auth.decorators import permission_required from django.contrib.auth.mixins import PermissionRequiredMixin -from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist +from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse from django.db.models import Max, Q from django.forms.utils import ErrorList @@ -990,8 +990,8 @@ class MesaView(FormMixin, DetailView): set( [p.parlamentar for p in parlamentares]) - set( parlamentares_ocupados)) - - org_parlamentares_vagos = sorted(parlamentares_vagos, key=lambda x: x.nome_parlamentar) + org_parlamentares_vagos = parlamentares_vagos + org_parlamentares_vagos.sort(key=lambda x: remover_acentos(x.nome_parlamentar)) org_parlamentares_vagos = [p for p in org_parlamentares_vagos if p.ativo] # Se todos os cargos estiverem ocupados, a listagem de parlamentares # deve ser renderizada vazia @@ -1046,8 +1046,10 @@ def atualizar_mesa(request): lista_composicao = [(c.id, c.parlamentar.__str__(), c.cargo.__str__()) for c in composicao_mesa] lista_parlamentares = [( - p.id, p.__str__()) for p in parlamentares_vagos] + p.id, p.nome_parlamentar) + for p in parlamentares_vagos if p.ativo] lista_cargos = [(c.id, c.__str__()) for c in cargos_vagos] + lista_parlamentares.sort(key=lambda x: remover_acentos(x[1])) return JsonResponse( {'lista_composicao': lista_composicao, diff --git a/sapl/templates/sessao/mesa.html b/sapl/templates/sessao/mesa.html index 02f313656..56e7f9989 100644 --- a/sapl/templates/sessao/mesa.html +++ b/sapl/templates/sessao/mesa.html @@ -38,7 +38,7 @@
diff --git a/sapl/utils.py b/sapl/utils.py index 8045f0e0b..69ea53dfc 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -735,5 +735,4 @@ def RemoveTag(texto): return textoSaida def remover_acentos(string): - return ''.join([c for c in unicodedata.normalize('NFD', string) - if unicodedata.category(c) != 'Mn']) \ No newline at end of file + return unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode() \ No newline at end of file From 5c03a9f74fb4df6db9577d51bd0ab51636b66483 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 7 May 2018 14:34:03 -0300 Subject: [PATCH 080/119] =?UTF-8?q?Adiciona=20op=C3=A7=C3=A3o=20de=20n?= =?UTF-8?q?=C3=A3o=20enviar=20ao=20github?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- release.sh | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/release.sh b/release.sh index 78fee9187..437355e57 100755 --- a/release.sh +++ b/release.sh @@ -6,14 +6,40 @@ MAIN_REV=`echo $VERSION | cut -f 1,2 -d '.'` NEXT_NUMBER=$(($LAST_DIGIT + 1)) NEXT_VERSION=$MAIN_REV'.'$NEXT_NUMBER -sed -e s/$VERSION/$NEXT_VERSION/g docker-compose.yml > tmp1 -mv tmp1 docker-compose.yml -sed -e s/$VERSION/$NEXT_VERSION/g setup.py > tmp2 -mv tmp2 setup.py +function bump_version { + sed -e s/$VERSION/$NEXT_VERSION/g docker-compose.yml > tmp1 + mv tmp1 docker-compose.yml + + sed -e s/$VERSION/$NEXT_VERSION/g setup.py > tmp2 + mv tmp2 setup.py +} + +function commit_and_push { + echo "committing..." + git add docker-compose.yml setup.py + git commit -m "Release: $NEXT_VERSION" + git tag $NEXT_VERSION + + echo "sending to github..." + git push origin $NEXT_VERSION + git push origin + + echo "done." +} + +case "$1" in + --dryrun) + echo "Dry run" + bump_version + echo "done." + echo "Run git checkout -- docker-compose.yml setup.py to undo the files" + + exit 0 + ;; + --a) + echo "generating release" + bump_version + commit_and_push +esac -git add docker-compose.yml setup.py -git commit -m "Release: $NEXT_VERSION" -git tag $NEXT_VERSION -git push origin $NEXT_VERSION -git push origin From 69f9aa48e71df839357e29b1ef0430cf5a89de31 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Mon, 7 May 2018 14:37:10 -0300 Subject: [PATCH 081/119] Release: 3.1.77 --- 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 f721b66f0..55a6b2359 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.76 + image: interlegis/sapl:3.1.77 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index da929d87c..af5b2c7d2 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.76', + version='3.1.77', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From f3102a787da6ee2b48a539df0ca559aa3a0de3e1 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Tue, 8 May 2018 08:53:55 -0300 Subject: [PATCH 082/119] HOT-FIX: fix #1918 --- sapl/templates/norma/subnav.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/templates/norma/subnav.yaml b/sapl/templates/norma/subnav.yaml index d050a469f..a89326fd7 100644 --- a/sapl/templates/norma/subnav.yaml +++ b/sapl/templates/norma/subnav.yaml @@ -4,7 +4,7 @@ url: normajuridica_detail - title: {% trans 'Alterações em Outras Normas' %} url: normarelacionada_list - check_permission: norma.normarelacionada_list + check_permission: norma.list_normarelacionada # 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 80e91fc8cb2b956b81a1aaa92df8e8265bc011f2 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Tue, 8 May 2018 17:01:55 -0100 Subject: [PATCH 083/119] Fix #1922 (#1927) * Fix #1922 * Update forms.py --- sapl/materia/forms.py | 30 +++++++++++++++++++++++++----- sapl/protocoloadm/forms.py | 16 ++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index e083e7fec..e5ff928d7 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -36,7 +36,7 @@ from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto, from sapl.norma.models import (LegislacaoCitada, NormaJuridica, TipoNormaJuridica) from sapl.parlamentares.models import Legislatura -from sapl.protocoloadm.models import Protocolo +from sapl.protocoloadm.models import Protocolo, DocumentoAdministrativo from sapl.settings import MAX_DOC_UPLOAD_SIZE from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, ChoiceWithoutValidationField, @@ -182,19 +182,39 @@ class MateriaLegislativaForm(ModelForm): data_apresentacao = cleaned_data['data_apresentacao'] ano = cleaned_data['ano'] + protocolo = cleaned_data['numero_protocolo'] + protocolo_antigo = self.instance.numero_protocolo + + if protocolo: + if not Protocolo.objects.filter(numero=protocolo,ano=ano).exists(): + raise ValidationError(_('Protocolo %s/%s não' + ' existe' % (protocolo, ano))) + + if protocolo_antigo != protocolo: + exist_materia = MateriaLegislativa.objects.filter( + numero_protocolo=protocolo, + ano=ano).exists() + + exist_doc = DocumentoAdministrativo.objects.filter( + protocolo_id=protocolo, + ano=ano).exists() + if exist_materia or exist_doc: + raise ValidationError(_('Protocolo %s/%s ja possui' + ' documento vinculado' + % (protocolo, ano))) if data_apresentacao.year != ano: - raise ValidationError("O ano da matéria não pode ser " - "diferente do ano na data de apresentação") + raise ValidationError(_("O ano da matéria não pode ser " + "diferente do ano na data de apresentação")) ano_origem_externa = cleaned_data['ano_origem_externa'] data_origem_externa = cleaned_data['data_origem_externa'] if ano_origem_externa and data_origem_externa and \ ano_origem_externa != data_origem_externa.year: - raise ValidationError("O ano de origem externa da matéria não " + raise ValidationError(_("O ano de origem externa da matéria não " "pode ser diferente do ano na data de " - "origem externa") + "origem externa")) return cleaned_data diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 06a2f7854..e85e9ecf2 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -698,6 +698,22 @@ class DocumentoAdministrativoForm(ModelForm): numero_protocolo, ano_protocolo)) raise ValidationError(msg) + inst = self.instance.protocolo + protocolo_antigo = inst.numero if inst else None + + if str(protocolo_antigo) != numero_protocolo: + exist_materia = MateriaLegislativa.objects.filter( + numero_protocolo=numero_protocolo, + ano=ano_protocolo).exists() + + exist_doc = DocumentoAdministrativo.objects.filter( + protocolo_id=numero_protocolo, + ano=ano_protocolo).exists() + if exist_materia or exist_doc: + raise ValidationError(_('Protocolo %s/%s ja possui' + ' documento vinculado' + % (numero_protocolo, ano_protocolo))) + return self.cleaned_data def save(self, commit=True): From 7e2341ac78da87b58d9e56f95a8a4235b99fe907 Mon Sep 17 00:00:00 2001 From: Edward Date: Wed, 9 May 2018 18:18:49 -0300 Subject: [PATCH 084/119] Fixes #1931 (#1932) --- sapl/materia/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index a23932b42..74f2bd6b6 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -937,7 +937,8 @@ class RelatoriaCrud(MasterDetailCrud): except ObjectDoesNotExist: pass else: - composicao = comissao.composicao_set.last() + composicao = comissao.composicao_set.order_by( + '-periodo__data_inicio').first() participacao = Participacao.objects.filter( composicao=composicao) From d7f5bc8b7011c5fa0a79b0878a72c130d740ed64 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 9 May 2018 18:23:09 -0300 Subject: [PATCH 085/119] Release: 3.1.78 --- 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 55a6b2359..70bac470c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.77 + image: interlegis/sapl:3.1.78 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index af5b2c7d2..a8a329205 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.77', + version='3.1.78', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 95b0832d14eb5aebb789ea6228bd09c9a4fff4bc Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 9 May 2018 18:23:51 -0300 Subject: [PATCH 086/119] HOT-FIX: change option switches --- release.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release.sh b/release.sh index 437355e57..cc3a172b5 100755 --- a/release.sh +++ b/release.sh @@ -29,7 +29,7 @@ function commit_and_push { } case "$1" in - --dryrun) + --dry-run) echo "Dry run" bump_version echo "done." @@ -37,7 +37,7 @@ case "$1" in exit 0 ;; - --a) + --publish) echo "generating release" bump_version commit_and_push From 4d8ebeaf9d9b5eed2ed78137a5c85fdf710ad0e9 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Fri, 11 May 2018 12:25:26 -0300 Subject: [PATCH 087/119] HOT-FIX: mitiga registros duplicados fix #1913 --- sapl/sessao/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index db3875677..f1bb99e58 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -277,8 +277,8 @@ def customize_link_materia(context, pk, has_permission, is_expediente): else: resultado = '''Não há resultado''' else: - resultado = obj.registrovotacao_set.get( - materia_id=obj.materia_id) + resultado = obj.registrovotacao_set.filter( + materia_id=obj.materia_id).last() resultado_descricao = resultado.tipo_resultado_votacao.nome resultado_observacao = resultado.observacao From bd121986f508ea5f2b3fd120e170db0411e52f6c Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 14 May 2018 09:58:33 -0300 Subject: [PATCH 088/119] Release: 3.1.79 --- 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 70bac470c..bc5af45c9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.78 + image: interlegis/sapl:3.1.79 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index a8a329205..7261468e4 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.78', + version='3.1.79', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From a8084b72934e48cfb3068a7cac6b66a32cc6e9a1 Mon Sep 17 00:00:00 2001 From: Eliseu Egewarth Date: Mon, 14 May 2018 15:02:49 -0300 Subject: [PATCH 089/119] Move scripts para pasta scripts (#1933) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Aprimorando script check_migrations.sh para executa-lo de qualquer pasta do repositório Signed-off-by: Eliseu Egewarth * Movendo script check_migrations.sh para a pasta scripts Signed-off-by: Eliseu Egewarth * Atualizando caminho do arquivo check_migrations.sh em .travis.yml e hooks/pre-commit Signed-off-by: Eliseu Egewarth * Modificando script fix_qa.sh para executar sempre na raiz do repositório Signed-off-by: Eliseu Egewarth * Movendo script fix_qa.sh para a pasta scripts/django/ Signed-off-by: Eliseu Egewarth * Removendo caminho hard-coded do script redbaron Signed-off-by: Eliseu Egewarth * Adaptando script reset_all_migrations.sh. Sempre executará a partir da raiz do repositório Signed-off-by: Eliseu Egewarth * Adaptando script gerar_grafico_apps.sh Signed-off-by: Eliseu Egewarth * Alterando scripts de QA para executar sempre na raiz do projeto Signed-off-by: Eliseu Egewarth * Fix QA script auto reference Signed-off-by: Eliseu Egewarth --- .travis.yml | 6 +++--- .../django/check_migrations.sh | 10 ++++++---- check_qa.sh => scripts/django/check_qa.sh | 4 ++++ fix_qa.sh => scripts/django/fix_qa.sh | 2 ++ scripts/{ => django}/gerar_grafico_apps.sh | 3 +++ scripts/{ => django}/reset_all_migrations.sh | 5 +++++ .../django/test_and_check_qa.sh | 5 ++++- scripts/hooks/pre-commit | 2 +- scripts/redbaron.py | 14 +++++++++----- 9 files changed, 37 insertions(+), 14 deletions(-) rename check_migrations.sh => scripts/django/check_migrations.sh (61%) rename check_qa.sh => scripts/django/check_qa.sh (89%) rename fix_qa.sh => scripts/django/fix_qa.sh (88%) rename scripts/{ => django}/gerar_grafico_apps.sh (69%) rename scripts/{ => django}/reset_all_migrations.sh (57%) rename test_and_check_qa.sh => scripts/django/test_and_check_qa.sh (53%) diff --git a/.travis.yml b/.travis.yml index eb6abe0c3..f54ee6d20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: python python: - - 3.4.3 + - 3.5 services: - postgresql @@ -14,13 +14,13 @@ before_script: - cp sapl/.env_test sapl/.env - psql -c "CREATE USER sapl WITH PASSWORD 'sapl'" -U postgres; - psql -c "CREATE DATABASE sapl OWNER sapl;" -U postgres - - ./check_migrations.sh + - ./scripts/django/check_migrations.sh script: - ./manage.py migrate - ./manage.py bower install - py.test --create-db - # - ./test_and_check_qa.sh + # - ./scripts/django/test_and_check_qa.sh addons: hosts: diff --git a/check_migrations.sh b/scripts/django/check_migrations.sh similarity index 61% rename from check_migrations.sh rename to scripts/django/check_migrations.sh index 9db8143b2..dc78641cd 100755 --- a/check_migrations.sh +++ b/scripts/django/check_migrations.sh @@ -11,13 +11,15 @@ # A chamada do django 1.10 INVERTE ISSO. # # https://docs.djangoproject.com/en/1.10/ref/django-admin/#cmdoption-makemigrations-check -if python manage.py makemigrations --dry-run --exit > /dev/null; then + +git_project_root=$(git rev-parse --show-toplevel) +if python ${git_project_root}/manage.py makemigrations --dry-run --exit > /dev/null; then NC='\033[0m' RED='\033[0;31m' echo echo -e "${RED}ALGUMAS ALTERAÇÕES EXIGEM MIGRAÇÃO.${NC}" - echo -e "${RED}RODE 'python manage.py makemigrations' ANTES DE SUBMETER SEU CÓDIGO...${NC}" - echo -e "${RED}lembre de adicionar os arquivos criados ao git com 'git add .' ou semelhante.${NC}" + echo -e "${RED}Execute o comando 'python manage.py makemigrations' ANTES DE SUBMETER SEU CÓDIGO...${NC}" + echo -e "${RED}Lembre de adicionar os arquivos criados ao git com 'git add ' ou semelhante.${NC}" echo exit 1 -fi \ No newline at end of file +fi diff --git a/check_qa.sh b/scripts/django/check_qa.sh similarity index 89% rename from check_qa.sh rename to scripts/django/check_qa.sh index 47f2b56d3..a145bee7a 100755 --- a/check_qa.sh +++ b/scripts/django/check_qa.sh @@ -2,6 +2,10 @@ # Verifica se um breakpoint foi esquecido no código me=`basename "$0"` + +git_project_root=$(git rev-parse --show-toplevel) +cd ${git_project_root} + busca=`grep --color=auto --exclude=$me --exclude=ipython_log.py* -r -l "pdb.set_trace()" .` if [ ! -z "$busca" ] diff --git a/fix_qa.sh b/scripts/django/fix_qa.sh similarity index 88% rename from fix_qa.sh rename to scripts/django/fix_qa.sh index 264c01676..cb0f24001 100755 --- a/fix_qa.sh +++ b/scripts/django/fix_qa.sh @@ -8,5 +8,7 @@ # Uma forma simples de fazer isso é adicionando antes suas mudanças à # "staging area" do git, com `git add .` e após usar o script `git diff`. +git_project_root=$(git rev-parse --show-toplevel) +cd ${git_project_root} isort --recursive --skip='migrations' --skip='templates' --skip='ipython_log.py*' . autopep8 --in-place --recursive . --exclude='migrations,ipython_log.py*' diff --git a/scripts/gerar_grafico_apps.sh b/scripts/django/gerar_grafico_apps.sh similarity index 69% rename from scripts/gerar_grafico_apps.sh rename to scripts/django/gerar_grafico_apps.sh index 312f04b0c..ab6bf9a84 100755 --- a/scripts/gerar_grafico_apps.sh +++ b/scripts/django/gerar_grafico_apps.sh @@ -1,3 +1,6 @@ #!/bin/bash +git_project_root=$(git rev-parse --show-toplevel) +cd ${git_project_root} + python -c "from sapl.settings import SAPL_APPS; print(*[s.split('.')[-1] for s in SAPL_APPS])" | xargs -t ./manage.py graph_models -d -g -o zzz.png -l fdp diff --git a/scripts/reset_all_migrations.sh b/scripts/django/reset_all_migrations.sh similarity index 57% rename from scripts/reset_all_migrations.sh rename to scripts/django/reset_all_migrations.sh index 53e274fe9..d3f2cfbe4 100755 --- a/scripts/reset_all_migrations.sh +++ b/scripts/django/reset_all_migrations.sh @@ -3,6 +3,11 @@ # Sends all django migrations to the trash bin # Requires trash-cli. To install: # sudo apt-get install trash-cli +hash trash-put 2>/dev/null || { echo >&2 "I require trash-put but it's not installed. Aborting."; exit 1; } + +git_project_root=$(git rev-parse --show-toplevel) +cd ${git_project_root} + find -name 00*.py | grep /migrations/ | xargs trash-put # Make all migrations from scratch diff --git a/test_and_check_qa.sh b/scripts/django/test_and_check_qa.sh similarity index 53% rename from test_and_check_qa.sh rename to scripts/django/test_and_check_qa.sh index 14231ce80..024139bba 100755 --- a/test_and_check_qa.sh +++ b/scripts/django/test_and_check_qa.sh @@ -2,6 +2,9 @@ # QA checks: run this before every commit +git_project_root=$(git rev-parse --show-toplevel) +cd ${git_project_root} + py.test py.test --ds=sapl.crud.tests.settings sapl/crud/tests -./check_qa.sh +./scripts/django/check_qa.sh diff --git a/scripts/hooks/pre-commit b/scripts/hooks/pre-commit index de82032c1..d8efe2cf5 100644 --- a/scripts/hooks/pre-commit +++ b/scripts/hooks/pre-commit @@ -4,5 +4,5 @@ if git diff --cached --name-status | grep -q '^M.*models\.py$'; then # se a checagem de migrations falhar impedimos o commit set -e - ./check_migrations.sh + ./scripts/django/check_migrations.sh fi diff --git a/scripts/redbaron.py b/scripts/redbaron.py index 3229872bc..b02e4cdfa 100644 --- a/scripts/redbaron.py +++ b/scripts/redbaron.py @@ -1,10 +1,14 @@ import os import re +import subprocess from redbaron import RedBaron from redbaron.nodes import EndlNode, ReturnNode, StringNode -root = '/home/mazza/work/sapl' +git_project_root = subprocess.Popen( + ["git", "rev-parse", "--show-toplevel"], + stdout=subprocess.PIPE + ).communicate()[0].decode('utf-8').replace('\n', '') def ignorado(path, name): @@ -13,13 +17,13 @@ def ignorado(path, name): 'relatorios/templates.*', '.*/migrations', ]: - if re.match(os.path.join(root, pattern), path): + if re.match(os.path.join(git_project_root, pattern), path): return True return name.startswith('ipython_log.py') or name == 'manage.py' filenames = [os.path.join(path, name) - for path, subdirs, files in os.walk(root) + for path, subdirs, files in os.walk(git_project_root) for name in files if name.endswith('.py') and not ignorado(path, name)] @@ -37,7 +41,7 @@ def build_red(filename): def write(node): - red = node.root + red = node.git_project_root with open(red.__filename__, "w") as source_code: source_code.write(red.dumps()) @@ -82,7 +86,7 @@ def fix(n): def local(node): - res = '%s:%s' % (node.root.__filename__, + res = '%s:%s' % (node.git_project_root.__filename__, node.absolute_bounding_box.top_left.line) os.system("echo '%s' | xclip -selection c" % res) return res From 2a7d7ae1ded183f6280c2ef4db08a501b285800c Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Fri, 18 May 2018 09:20:14 -0300 Subject: [PATCH 090/119] Fix #1935 --- sapl/parlamentares/forms.py | 2 +- sapl/sessao/forms.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sapl/parlamentares/forms.py b/sapl/parlamentares/forms.py index e5b8d7d58..a7e042037 100644 --- a/sapl/parlamentares/forms.py +++ b/sapl/parlamentares/forms.py @@ -321,7 +321,7 @@ class FrenteForm(ModelForm): frente = super(FrenteForm, self).save(commit) content_type = ContentType.objects.get_for_model(Frente) object_id = frente.pk - tipo = TipoAutor.objects.get(descricao='Frente Parlamentar') + tipo = TipoAutor.objects.get(descricao__icontains='Frente') Autor.objects.create( content_type=content_type, object_id=object_id, diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index c35abf306..cd46fab84 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -124,7 +124,7 @@ class BancadaForm(ModelForm): bancada = super(BancadaForm, self).save(commit) content_type = ContentType.objects.get_for_model(Bancada) object_id = bancada.pk - tipo = TipoAutor.objects.get(descricao='Bancada Parlamentar') + tipo = TipoAutor.objects.get(descricao__icontains='Bancada') Autor.objects.create( content_type=content_type, object_id=object_id, @@ -159,7 +159,7 @@ class BlocoForm(ModelForm): bloco = super(BlocoForm, self).save(commit) content_type = ContentType.objects.get_for_model(Bloco) object_id = bloco.pk - tipo = TipoAutor.objects.get(descricao='Bloco Parlamentar') + tipo = TipoAutor.objects.get(descricao__icontains='Bloco') Autor.objects.create( content_type=content_type, object_id=object_id, From 93b531ad2b80b85bca31d6af2de0c8dbb80c81c8 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 22 May 2018 19:10:49 -0300 Subject: [PATCH 091/119] Corrige contagem de btree na exportacao de docs --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 63d0ed09e..749a521b1 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -151,13 +151,14 @@ enumerate_properties = partial(enumerate_by_key_list, def enumerate_btree(folder): contagem_esperada = folder['_count'].value tree = folder['_tree'] + contagem_real = 0 # para o caso em que não haja itens for contagem_real, (id, obj) in enumerate(tree.iteritems(), start=1): obj, meta_type = br(obj), type(obj).__name__ yield id, obj, meta_type # verificação de consistência if contagem_esperada != contagem_real: print('ATENÇÃO: contagens diferentes na btree: ' - '{} esperada: {} real: {}'.format(folder, + '{} esperada: {} real: {}'.format(folder['title'], contagem_esperada, contagem_real)) From d045f7a328da40138cb67f80f2f5960076e6e63e Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Wed, 23 May 2018 13:13:11 -0300 Subject: [PATCH 092/119] Fix #1941 --- sapl/protocoloadm/views.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index d4f7e96d9..733b7388e 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -451,10 +451,11 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): if not protocolo.numero: protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 - if protocolo.numero < (numero['numero__max'] + 1): - msg = _('Número de protocolo deve ser maior que {}').format(numero['numero__max']) - messages.add_message(self.request, messages.ERROR, msg) - return self.render_to_response(self.get_context_data()) + if numero['numero__max']: + if protocolo.numero < (numero['numero__max'] + 1): + msg = _('Número de protocolo deve ser maior que {}').format(numero['numero__max']) + messages.add_message(self.request, messages.ERROR, msg) + return self.render_to_response(self.get_context_data()) protocolo.ano = timezone.now().year protocolo.data = timezone.now().date() protocolo.hora = timezone.now().time() From c130f15266093b1dac53d8180706bf9197acf6e5 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Wed, 23 May 2018 13:37:47 -0300 Subject: [PATCH 093/119] Release: 3.1.80 --- 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 bc5af45c9..87c58f129 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.79 + image: interlegis/sapl:3.1.80 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 7261468e4..5bdbd8f99 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.79', + version='3.1.80', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From cfd5614170da2976e87748550e1e98d80ab66069 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 23 May 2018 15:21:14 -0300 Subject: [PATCH 094/119] =?UTF-8?q?Adiciona=20compacta=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20media=20ao=20comando=20de=20migra=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index 059e49164..ffd0d2a18 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -28,6 +28,7 @@ def migrar(interativo=False): migrar_usuarios(REPO.working_dir) migrar_documentos(REPO) gravar_marco() + compactar_media() def compactar_media(): From 6827a941eb885d48d86fc4fde818cb14b64a5b19 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 28 May 2018 14:33:14 -0300 Subject: [PATCH 095/119] =?UTF-8?q?Vincula=20autor=20a=20seu=20usu=C3=A1ri?= =?UTF-8?q?o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #1849 --- sapl/legacy/migracao_dados.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 0f1e4d6dc..88758c8b1 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -1210,10 +1210,9 @@ def adjust_autor(new, old): break if old.col_username: - user_model = get_user_model() - if not user_model.objects.filter(username=old.col_username).exists(): - # cria um novo ususaÅ•io para o autor - user = user_model(username=old.col_username) + user, created = get_user_model().objects.get_or_create( + username=old.col_username) + if created: # gera uma senha inutilizável, que precisará ser trocada user.set_password(None) with reversion.create_revision(): @@ -1221,8 +1220,9 @@ def adjust_autor(new, old): reversion.set_comment( 'Usuário criado pela migração para o autor {}'.format( old.cod_autor)) - grupo_autor = Group.objects.get(name="Autor") - user.groups.add(grupo_autor) + grupo_autor = Group.objects.get(name="Autor") + user.groups.add(grupo_autor) + new.user = user def adjust_comissao(new, old): From 8ec6e44ef3a344f4745a6eff1baad879df031381 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 28 May 2018 14:35:38 -0300 Subject: [PATCH 096/119] =?UTF-8?q?Exibe=20sigla=20em=20exporta=C3=A7?= =?UTF-8?q?=C3=A3o=20do=20zope=20abortada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 749a521b1..20c7d21e7 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -363,7 +363,7 @@ def dump_sapl(sigla): destino.mkdir(parents=True) repo = git.Repo.init(destino) if TAG_ZOPE in repo.tags: - print('A exportação de documentos já está feita -- abortando') + print('{}: A exportação de documentos já está feita -- abortando'.format(sigla)) return repo_execute(repo, 'git annex init') From b6645ea2aa75365ab29969fff8a3bc9274b1d062 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 4 Jun 2018 11:59:16 -0300 Subject: [PATCH 097/119] Fix 1955 (#1956) --- sapl/protocoloadm/forms.py | 60 +++++++++++++++++++ sapl/protocoloadm/urls.py | 5 +- sapl/protocoloadm/views.py | 19 +++++- .../protocoloadm/protocoloadm_detail.html | 1 + 4 files changed, 83 insertions(+), 2 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index e85e9ecf2..19d9d9b81 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -757,3 +757,63 @@ class DocumentoAdministrativoForm(ModelForm): row6, row7)) super(DocumentoAdministrativoForm, self).__init__( *args, **kwargs) + +class DesvincularDocumentoForm(ModelForm): + + numero = forms.CharField(required=True, + label=DocumentoAdministrativo._meta. + get_field('numero').verbose_name + ) + ano = forms.ChoiceField(required=True, + label=DocumentoAdministrativo._meta. + get_field('ano').verbose_name, + choices=RANGE_ANOS, + widget=forms.Select(attrs={'class': 'selector'})) + + def clean(self): + super(DesvincularDocumentoForm, self).clean() + + cleaned_data = self.cleaned_data + + if not self.is_valid(): + return cleaned_data + + numero = cleaned_data['numero'] + ano = cleaned_data['ano'] + tipo = cleaned_data['tipo'] + + try: + documento = DocumentoAdministrativo.objects.get(numero=numero, ano=ano, tipo=tipo) + if not documento.protocolo: + raise forms.ValidationError( + _("%s %s/%s não se encontra vinculado a nenhum protocolo" % (tipo, numero, ano))) + except ObjectDoesNotExist: + raise forms.ValidationError( + _("%s %s/%s não existe" % (tipo, numero, ano))) + + return cleaned_data + + class Meta: + model = DocumentoAdministrativo + fields = ['tipo', + 'numero', + 'ano', + ] + + def __init__(self, *args, **kwargs): + + row1 = to_row( + [('numero', 4), + ('ano', 4), + ('tipo', 4)]) + + self.helper = FormHelper() + self.helper.layout = Layout( + Fieldset(_('Identificação do Documento'), + row1, + HTML(" "), + form_actions(label='Desvincular') + ) + ) + super(DesvincularDocumentoForm, self).__init__( + *args, **kwargs) \ No newline at end of file diff --git a/sapl/protocoloadm/urls.py b/sapl/protocoloadm/urls.py index 46fec9980..de5c79b58 100644 --- a/sapl/protocoloadm/urls.py +++ b/sapl/protocoloadm/urls.py @@ -15,7 +15,8 @@ from sapl.protocoloadm.views import (AnularProtocoloAdmView, TipoDocumentoAdministrativoCrud, TramitacaoAdmCrud, atualizar_numero_documento, - doc_texto_integral) + doc_texto_integral, + DesvincularDocumentoView) from .apps import AppConfig @@ -61,6 +62,8 @@ urlpatterns_protocolo = [ url(r'^protocoloadm/anular-protocolo', AnularProtocoloAdmView.as_view(), name='anular_protocolo'), + url(r'^protocoloadm/desvincular-documento', + DesvincularDocumentoView.as_view(), name='desvincular_documento'), url(r'^protocoloadm/protocolar-mat', ProtocoloMateriaView.as_view(), name='protocolar_mat'), diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 733b7388e..8aa51d814 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -30,7 +30,7 @@ from .forms import (AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm, DocumentoAdministrativoFilterSet, DocumentoAdministrativoForm, ProtocoloDocumentForm, ProtocoloFilterSet, ProtocoloMateriaForm, - TramitacaoAdmEditForm, TramitacaoAdmForm) + TramitacaoAdmEditForm, TramitacaoAdmForm, DesvincularDocumentoForm) from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo, StatusTramitacaoAdministrativo, TipoDocumentoAdministrativo, TramitacaoAdministrativo) @@ -721,3 +721,20 @@ def atualizar_numero_documento(request): {'numero': 1, 'ano': ano}) return response + +class DesvincularDocumentoView(PermissionRequiredMixin, CreateView): + template_name = 'protocoloadm/anular_protocoloadm.html' + form_class = DesvincularDocumentoForm + form_valid_message = _('Documento desvinculado com sucesso!') + permission_required = ('protocoloadm.action_anular_protocolo', ) + + def get_success_url(self): + return reverse('sapl.protocoloadm:protocolo') + + def form_valid(self, form): + documento = DocumentoAdministrativo.objects.get(numero=form.cleaned_data['numero'], + ano=form.cleaned_data['ano'], + tipo=form.cleaned_data['tipo']) + documento.protocolo = None + documento.save() + return redirect(self.get_success_url()) diff --git a/sapl/templates/protocoloadm/protocoloadm_detail.html b/sapl/templates/protocoloadm/protocoloadm_detail.html index 5a3fe05d0..e9da072ec 100644 --- a/sapl/templates/protocoloadm/protocoloadm_detail.html +++ b/sapl/templates/protocoloadm/protocoloadm_detail.html @@ -5,5 +5,6 @@ {% trans 'Protocolar Matéria' %} {% trans 'Protocolar Documento' %} {% trans 'Anular Protocolo' %} + {% trans 'Desvincular Documentos' %}
{% endblock editions %} From 75ae87380ad51eb7a9741e576f3657eae56417eb Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Mon, 4 Jun 2018 11:59:25 -0300 Subject: [PATCH 098/119] Fix #1953 (#1954) --- .../templates/sessao/blocos_resumo/conteudo_multimidia.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html b/sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html index 4749f5ad2..b275ebd79 100644 --- a/sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html +++ b/sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html @@ -1,8 +1,8 @@
Conteúdo Multimídia
-
{{multimidia_audio}}
-
{{multimidia_video}}
+ +
-


\ No newline at end of file +


From 8057306e15cdc0b6f1f31afd95669957365f4c83 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 4 Jun 2018 11:59:34 -0300 Subject: [PATCH 099/119] Fix #1949 (#1950) --- sapl/relatorios/views.py | 3 ++- sapl/utils.py | 11 +++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py index 9f46450b8..0bad27889 100644 --- a/sapl/relatorios/views.py +++ b/sapl/relatorios/views.py @@ -795,7 +795,8 @@ def relatorio_sessao_plenaria(request, pk): for idx in range(len(lst_expedientes)): txt_expedientes = lst_expedientes[idx]['txt_expediente'] - txt_expedientes = TrocaTag(txt_expedientes, '', 6, 6, 'expedientes') + txt_expedientes = TrocaTag(txt_expedientes, '', 6, 6, + 'expedientes', '' + textoSaida += subinitiTag + styleName + '">' insideTag = 1 else: if (insideTag == 1): if (texto[i:i + sizeEnd] == endTag): - textoSaida += 'blockTable>' + textoSaida += subendTag insideTag = 0 i += sizeEnd else: @@ -735,4 +738,4 @@ def RemoveTag(texto): return textoSaida def remover_acentos(string): - return unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode() \ No newline at end of file + return unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode() From b90886e588ee0f666660b6ecc1b34c8c31b43074 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 4 Jun 2018 11:59:43 -0300 Subject: [PATCH 100/119] Fix #1946 (#1948) --- sapl/comissoes/forms.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index 3576873b7..05a0a97b9 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -241,6 +241,9 @@ class ComissaoForm(forms.ModelForm): if not self.is_valid(): return self.cleaned_data + if len(self.cleaned_data['nome']) > 50: + msg = _('Nome da Comissão deve ter no máximo 50 caracteres.') + raise ValidationError(msg) if self.cleaned_data['data_extincao']: if (self.cleaned_data['data_extincao'] < self.cleaned_data['data_criacao']): From 412a2f7bf68152d3835a9f251e80a218f3a09984 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 4 Jun 2018 11:59:52 -0300 Subject: [PATCH 101/119] Fix #1944 (#1945) --- sapl/templates/parlamentares/layouts.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sapl/templates/parlamentares/layouts.yaml b/sapl/templates/parlamentares/layouts.yaml index ba7767cd2..2c21ade8d 100644 --- a/sapl/templates/parlamentares/layouts.yaml +++ b/sapl/templates/parlamentares/layouts.yaml @@ -37,10 +37,10 @@ Parlamentar: - situacao_militar profissao - endereco_web - email - - numero_gab_parlamentar telefone fax + - numero_gab_parlamentar telefone - endereco_residencia cep_residencia - municipio_residencia uf_residencia - - telefone_residencia fax_residencia + - telefone_residencia - locais_atuacao - fotografia:5 - biografia @@ -54,10 +54,10 @@ ParlamentarUpdate: - situacao_militar profissao - endereco_web - email - - numero_gab_parlamentar telefone fax + - numero_gab_parlamentar telefone - endereco_residencia cep_residencia - municipio_residencia uf_residencia - - telefone_residencia fax_residencia + - telefone_residencia - locais_atuacao - fotografia cropping - biografia @@ -73,10 +73,10 @@ ParlamentarCreate: - situacao_militar profissao - endereco_web - email - - numero_gab_parlamentar telefone fax + - numero_gab_parlamentar telefone - endereco_residencia cep_residencia - municipio_residencia - - telefone_residencia fax_residencia + - telefone_residencia - locais_atuacao - fotografia - biografia From 116b053a709a8e2a1dee2d7e896ca49bac5a8056 Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Mon, 4 Jun 2018 12:00:03 -0300 Subject: [PATCH 102/119] FIX #1906 (#1943) * Fix #1906 * Fix #1906 --- sapl/base/forms.py | 3 + ...0017_appconfig_cronometro_consideracoes.py | 20 ++++ sapl/base/models.py | 5 + .../migrations/0002_auto_20180523_1430.py | 20 ++++ sapl/painel/models.py | 3 +- sapl/painel/views.py | 1 + sapl/sessao/views.py | 10 +- sapl/templates/base/layouts.yaml | 2 +- sapl/templates/painel/index.html | 30 +++++- sapl/templates/sessao/painel.html | 92 +++++++++++++++++++ 10 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 sapl/base/migrations/0017_appconfig_cronometro_consideracoes.py create mode 100644 sapl/painel/migrations/0002_auto_20180523_1430.py diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 513c3a7ca..5410ee3fe 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -834,6 +834,7 @@ class ConfiguracoesAppForm(ModelForm): 'cronometro_discurso', 'cronometro_aparte', 'cronometro_ordem', + 'cronometro_consideracoes', 'mostrar_brasao_painel', 'receber_recibo_proposicao'] @@ -842,6 +843,8 @@ class ConfiguracoesAppForm(ModelForm): self.fields['cronometro_discurso'].widget.attrs['class'] = 'cronometro' self.fields['cronometro_aparte'].widget.attrs['class'] = 'cronometro' self.fields['cronometro_ordem'].widget.attrs['class'] = 'cronometro' + self.fields['cronometro_consideracoes'].widget.attrs['class'] = 'cronometro' + def clean_mostrar_brasao_painel(self): mostrar_brasao_painel = self.cleaned_data.get( diff --git a/sapl/base/migrations/0017_appconfig_cronometro_consideracoes.py b/sapl/base/migrations/0017_appconfig_cronometro_consideracoes.py new file mode 100644 index 000000000..057344d9c --- /dev/null +++ b/sapl/base/migrations/0017_appconfig_cronometro_consideracoes.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-05-23 17:30 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0016_auto_20180326_1840'), + ] + + operations = [ + migrations.AddField( + model_name='appconfig', + name='cronometro_consideracoes', + field=models.TimeField(blank=True, null=True, verbose_name='Cronômetro de Considerações Finais'), + ), + ] diff --git a/sapl/base/models.py b/sapl/base/models.py index d2a6035a8..bbc03b6c7 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -113,6 +113,11 @@ class AppConfig(models.Model): blank=True, null=True) + cronometro_consideracoes = models.TimeField( + verbose_name=_('Cronômetro de Considerações Finais'), + blank=True, + null=True) + mostrar_brasao_painel = models.BooleanField( default=False, verbose_name=_('Mostrar brasão da Casa no painel?')) diff --git a/sapl/painel/migrations/0002_auto_20180523_1430.py b/sapl/painel/migrations/0002_auto_20180523_1430.py new file mode 100644 index 000000000..52074acd1 --- /dev/null +++ b/sapl/painel/migrations/0002_auto_20180523_1430.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-05-23 17:30 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('painel', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='cronometro', + name='tipo', + field=models.CharField(choices=[('A', 'Aparte'), ('D', 'Discurso'), ('O', 'Ordem do dia'), ('C', 'Considerações finais')], max_length=1, verbose_name='Tipo Cronômetro'), + ), + ] diff --git a/sapl/painel/models.py b/sapl/painel/models.py index 097981520..f999ca480 100644 --- a/sapl/painel/models.py +++ b/sapl/painel/models.py @@ -26,7 +26,8 @@ class Cronometro(models.Model): CRONOMETRO_TYPES = ( ('A', _('Aparte')), ('D', _('Discurso')), - ('O', _('Ordem do dia')) + ('O', _('Ordem do dia')), + ('C', _('Considerações finais')) ) CRONOMETRO_STATUS = ( diff --git a/sapl/painel/views.py b/sapl/painel/views.py index d3f7fc5cc..0cb151382 100644 --- a/sapl/painel/views.py +++ b/sapl/painel/views.py @@ -464,6 +464,7 @@ def get_dados_painel(request, pk): 'cronometro_aparte': get_cronometro_status(request, 'aparte'), 'cronometro_discurso': get_cronometro_status(request, 'discurso'), 'cronometro_ordem': get_cronometro_status(request, 'ordem'), + 'cronometro_consideracoes': get_cronometro_status(request, 'consideracoes'), 'status_painel': sessao.painel_aberto, 'brasao': brasao } diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index f1bb99e58..8700177c0 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -761,6 +761,7 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView): request.session['discurso'] = 'stop' request.session['aparte'] = 'stop' request.session['ordem'] = 'stop' + request.session['consideracoes'] = 'stop' return TemplateView.get(self, request, *args, **kwargs) @@ -768,9 +769,10 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView): cronometro_discurso = AppsAppConfig.attr('cronometro_discurso') cronometro_aparte = AppsAppConfig.attr('cronometro_aparte') cronometro_ordem = AppsAppConfig.attr('cronometro_ordem') + cronometro_consideracoes = AppsAppConfig.attr('cronometro_consideracoes') if (not cronometro_discurso or not cronometro_aparte - or not cronometro_ordem): + or not cronometro_ordem or not cronometro_consideracoes): msg = _( 'Você precisa primeiro configurar os cronômetros \ nas Configurações da Aplicação') @@ -786,6 +788,9 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView): m, s, x = cronometro_ordem.isoformat().split(':') cronometro_ordem = int(m) * 60 + int(s) + m, s, x = cronometro_consideracoes.isoformat().split(':') + cronometro_consideracoes = int(m) * 60 + int(s) + context = TemplateView.get_context_data(self, **kwargs) context.update({ 'head_title': str(_('Painel Plenário')), @@ -794,7 +799,8 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView): 'sessaoplenaria': SessaoPlenaria.objects.get(pk=kwargs['pk']), 'cronometro_discurso': cronometro_discurso, 'cronometro_aparte': cronometro_aparte, - 'cronometro_ordem': cronometro_ordem}) + 'cronometro_ordem': cronometro_ordem, + 'cronometro_consideracoes': cronometro_consideracoes}) return context diff --git a/sapl/templates/base/layouts.yaml b/sapl/templates/base/layouts.yaml index 3f066289b..c07c15036 100644 --- a/sapl/templates/base/layouts.yaml +++ b/sapl/templates/base/layouts.yaml @@ -21,7 +21,7 @@ AppConfig: - texto_articulado_proposicao texto_articulado_materia texto_articulado_norma {% trans 'Cronômetros do Painel' %}: - - cronometro_discurso cronometro_aparte cronometro_ordem + - cronometro_discurso cronometro_aparte cronometro_ordem cronometro_consideracoes {% trans 'Configurações do Painel' %}: - mostrar_brasao_painel diff --git a/sapl/templates/painel/index.html b/sapl/templates/painel/index.html index c50167161..621689ffe 100644 --- a/sapl/templates/painel/index.html +++ b/sapl/templates/painel/index.html @@ -28,7 +28,7 @@ ul, li { list-style-type: none; } - #date, #sessao_plenaria, #sessao_plenaria_data, #sessao_plenaria_hora_inicio, #message, #cronometro_discurso, #cronometro_aparte, #cronometro_ordem, #relogio, #parlamentares, #votacao, #materia_legislativa_texto, #observacao_materia, #resultado_votacao, #orador { + #date, #sessao_plenaria, #sessao_plenaria_data, #sessao_plenaria_hora_inicio, #message, #cronometro_discurso, #cronometro_aparte, #cronometro_ordem, #cronometro_consideracoes, #relogio, #parlamentares, #votacao, #materia_legislativa_texto, #observacao_materia, #resultado_votacao, #orador { font-family: Verdana; } } @@ -108,6 +108,9 @@ Questão de Ordem: + + Considerações Finais: +
@@ -195,9 +198,20 @@ audioAlertFinish.play(); }); + $('#cronometro_consideracoes').runner({ + autostart: false, + countdown: true, + startAt: {{ 'consideracoes'|cronometro_to_seconds }} * 1000, + stopAt: 0, + milliseconds: false + }).on('runnerFinish', function(eventObject, info){ + audioAlertFinish.play(); + }); + var discurso_previous; var ordem_previous; var aparte_previous; + var consideracoes_previous; var counter = 1; (function poll() { @@ -325,6 +339,16 @@ ordem_previous = ordem_current; } + var consideracoes_current = data["cronometro_consideracoes"]; + if (!consideracoes_previous){ + consideracoes_previous = '' + } + + if (consideracoes_current != consideracoes_previous) { + $('#cronometro_consideracoes').runner(consideracoes_current); + consideracoes_previous = consideracoes_current; + } + if($('#cronometro_discurso').runner('info').formattedTime == 30) { audioAlertFinish.play(); } @@ -337,6 +361,10 @@ audioAlertFinish.play(); } + if($('#cronometro_consideracoes').runner('info').formattedTime == 30) { + audioAlertFinish.play(); + } + if (data['materia_legislativa_texto']){ $("#materia_legislativa_texto").text(data["materia_legislativa_texto"]); } diff --git a/sapl/templates/sessao/painel.html b/sapl/templates/sessao/painel.html index 22dc62dda..d83c99e86 100644 --- a/sapl/templates/sessao/painel.html +++ b/sapl/templates/sessao/painel.html @@ -69,6 +69,20 @@


+
+

Cronômetro de Considerações Finais

+
+ +
+
+
+
+ +
+
+
+
+

@@ -102,6 +116,7 @@ $(function() { $('#discurso').prop('disabled', true); $('#aparte').prop('disabled', true); $('#ordem').prop('disabled', true); + $('#consideracoes').prop('disabled', true); $('#discurso').runner({ autostart: false, @@ -119,6 +134,8 @@ $(function() { $('#aparteReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); }); @@ -135,6 +152,8 @@ $(function() { $('#aparteReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } else { @@ -147,6 +166,8 @@ $(function() { $('#aparteReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } }); @@ -174,6 +195,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); }); @@ -189,6 +212,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } else { $.get('/painel/cronometro', { tipo: 'aparte', action: 'stop' } ); @@ -200,6 +225,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } }); @@ -227,6 +254,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#aparteStart').prop('disabled', false); $('#aparteReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); }); $('#ordemStart').click(function() { @@ -241,6 +270,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#aparteStart').prop('disabled', false); $('#aparteReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } else { @@ -253,6 +284,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#aparteStart').prop('disabled', false); $('#aparteReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } }); @@ -264,6 +297,65 @@ $(function() { $('#ordem').runner('reset'); }); + $('#consideracoes').runner({ + autostart: false, + countdown: true, + startAt: {{cronometro_consideracoes}} * 1000, + stopAt: 0, + milliseconds: false + }).on('runnerFinish', function(eventObject, info){ + $.get('/painel/cronometro', { tipo: 'consideracoes', action: 'stop' } ); + + $('#consideracoesReset').show(); + $('#consideracoes').runner('stop'); + $('#consideracoesStart').text('Iniciar'); + $('#discursoStart').prop('disabled', false); + $('#discursoReset').prop('disabled', false); + $('#ordemStart').prop('disabled', false); + $('#ordemReset').prop('disabled', false); + $('#aparteStart').prop('disabled', false); + $('#aparteReset').prop('disabled', false); + + }); + + $('#consideracoesStart').click(function(){ + if ($('#consideracoesStart').text() == 'Iniciar') { + + $.get('/painel/cronometro', { tipo: 'consideracoes', action: 'start' } ); + + $('#consideracoesReset').hide(); + $('#consideracoes').runner('start'); + $('#consideracoesStart').text('Parar'); + $('#discursoStart').prop('disabled', false); + $('#discursoReset').prop('disabled', false); + $('#ordemStart').prop('disabled', false); + $('#ordemReset').prop('disabled', false); + $('#aparteStart').prop('disabled', false); + $('#aparteReset').prop('disabled', false); + } else { + + $.get('/painel/cronometro', { tipo: 'consideracoes', action: 'stop' } ); + + $('#consideracoesReset').show(); + $('#consideracoes').runner('stop'); + $('#consideracoesStart').text('Iniciar'); + $('#discursoStart').prop('disabled', false); + $('#discursoReset').prop('disabled', false); + $('#ordemStart').prop('disabled', false); + $('#ordemReset').prop('disabled', false); + $('#aparteStart').prop('disabled', false); + $('#aparteReset').prop('disabled', false); + } + }); + + $('#consideracoesReset').click(function() { + + $.get('/painel/cronometro', { tipo: 'consideracoes', action: 'reset' } ); + + $('#consideracoes').runner('stop'); + $('#consideracoes').runner('reset'); + }); + }); function switch_painel(aberto) { From ec186c0bcb55494f425d71bfde564b00076919bc Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Mon, 4 Jun 2018 13:35:18 -0300 Subject: [PATCH 103/119] Release: 3.1.81 --- 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 87c58f129..68ab20687 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.80 + image: interlegis/sapl:3.1.81 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 5bdbd8f99..9e5c5315d 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.80', + version='3.1.81', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From acc619c13e00b270f116b266ae989926079d2ffe Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 4 Jun 2018 17:10:06 -0300 Subject: [PATCH 104/119] Fix #1960 (#1962) * Fix #1960 * Tira ipdb --- sapl/protocoloadm/forms.py | 57 ++++++++++++++++++- sapl/protocoloadm/urls.py | 5 +- sapl/protocoloadm/views.py | 22 ++++++- .../protocoloadm/protocoloadm_detail.html | 1 + 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 19d9d9b81..7d68ad9c3 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -758,6 +758,7 @@ class DocumentoAdministrativoForm(ModelForm): super(DocumentoAdministrativoForm, self).__init__( *args, **kwargs) + class DesvincularDocumentoForm(ModelForm): numero = forms.CharField(required=True, @@ -816,4 +817,58 @@ class DesvincularDocumentoForm(ModelForm): ) ) super(DesvincularDocumentoForm, self).__init__( - *args, **kwargs) \ No newline at end of file + *args, **kwargs) + + +class DesvincularMateriaForm(forms.Form): + + numero = forms.CharField(required=True, + label=_('Número da Matéria')) + ano = forms.ChoiceField(required=True, + label=_('Ano da Matéria'), + choices=RANGE_ANOS, + widget=forms.Select(attrs={'class': 'selector'})) + tipo = forms.ModelChoiceField(label=_('Tipo de Matéria'), + required=True, + queryset=TipoMateriaLegislativa.objects.all(), + empty_label='------') + + def clean(self): + super(DesvincularMateriaForm, self).clean() + + cleaned_data = self.cleaned_data + + if not self.is_valid(): + return cleaned_data + + numero = cleaned_data['numero'] + ano = cleaned_data['ano'] + tipo = cleaned_data['tipo'] + + try: + materia = MateriaLegislativa.objects.get(numero=numero, ano=ano, tipo=tipo) + if not materia.numero_protocolo: + raise forms.ValidationError( + _("%s %s/%s não se encontra vinculada a nenhum protocolo" % (tipo, numero, ano))) + except ObjectDoesNotExist: + raise forms.ValidationError( + _("%s %s/%s não existe" % (tipo, numero, ano))) + + return cleaned_data + + def __init__(self, *args, **kwargs): + super(DesvincularMateriaForm, self).__init__(*args, **kwargs) + + row1 = to_row( + [('numero', 4), + ('ano', 4), + ('tipo', 4)]) + + self.helper = FormHelper() + self.helper.layout = Layout( + Fieldset(_('Identificação da Matéria'), + row1, + HTML(" "), + form_actions(label='Desvincular') + ) + ) diff --git a/sapl/protocoloadm/urls.py b/sapl/protocoloadm/urls.py index de5c79b58..223c38014 100644 --- a/sapl/protocoloadm/urls.py +++ b/sapl/protocoloadm/urls.py @@ -16,7 +16,8 @@ from sapl.protocoloadm.views import (AnularProtocoloAdmView, TramitacaoAdmCrud, atualizar_numero_documento, doc_texto_integral, - DesvincularDocumentoView) + DesvincularDocumentoView, + DesvincularMateriaView) from .apps import AppConfig @@ -64,6 +65,8 @@ urlpatterns_protocolo = [ AnularProtocoloAdmView.as_view(), name='anular_protocolo'), url(r'^protocoloadm/desvincular-documento', DesvincularDocumentoView.as_view(), name='desvincular_documento'), + url(r'^protocoloadm/desvincular-materia', + DesvincularMateriaView.as_view(), name='desvincular_materia'), url(r'^protocoloadm/protocolar-mat', ProtocoloMateriaView.as_view(), name='protocolar_mat'), diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 8aa51d814..7dd7206c7 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -13,6 +13,7 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django.views.generic import CreateView, ListView from django.views.generic.base import RedirectView, TemplateView +from django.views.generic.edit import FormView from django_filters.views import FilterView import sapl @@ -30,7 +31,7 @@ from .forms import (AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm, DocumentoAdministrativoFilterSet, DocumentoAdministrativoForm, ProtocoloDocumentForm, ProtocoloFilterSet, ProtocoloMateriaForm, - TramitacaoAdmEditForm, TramitacaoAdmForm, DesvincularDocumentoForm) + TramitacaoAdmEditForm, TramitacaoAdmForm, DesvincularDocumentoForm, DesvincularMateriaForm) from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo, StatusTramitacaoAdministrativo, TipoDocumentoAdministrativo, TramitacaoAdministrativo) @@ -722,6 +723,7 @@ def atualizar_numero_documento(request): return response + class DesvincularDocumentoView(PermissionRequiredMixin, CreateView): template_name = 'protocoloadm/anular_protocoloadm.html' form_class = DesvincularDocumentoForm @@ -738,3 +740,21 @@ class DesvincularDocumentoView(PermissionRequiredMixin, CreateView): documento.protocolo = None documento.save() return redirect(self.get_success_url()) + + +class DesvincularMateriaView(PermissionRequiredMixin, FormView): + template_name = 'protocoloadm/anular_protocoloadm.html' + form_class = DesvincularMateriaForm + form_valid_message = _('Matéria desvinculado com sucesso!') + permission_required = ('protocoloadm.action_anular_protocolo', ) + + def get_success_url(self): + return reverse('sapl.protocoloadm:protocolo') + + def form_valid(self, form): + materia = MateriaLegislativa.objects.get(numero=form.cleaned_data['numero'], + ano=form.cleaned_data['ano'], + tipo=form.cleaned_data['tipo']) + materia.numero_protocolo = None + materia.save() + return redirect(self.get_success_url()) \ No newline at end of file diff --git a/sapl/templates/protocoloadm/protocoloadm_detail.html b/sapl/templates/protocoloadm/protocoloadm_detail.html index e9da072ec..3db9ea6d8 100644 --- a/sapl/templates/protocoloadm/protocoloadm_detail.html +++ b/sapl/templates/protocoloadm/protocoloadm_detail.html @@ -6,5 +6,6 @@ {% trans 'Protocolar Documento' %} {% trans 'Anular Protocolo' %} {% trans 'Desvincular Documentos' %} + {% trans 'Desvincular Matérias' %} {% endblock editions %} From ce7d9592e53514e2ad4b76fb8db40d74eb206602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Sconetto?= Date: Tue, 5 Jun 2018 17:19:05 -0300 Subject: [PATCH 105/119] =?UTF-8?q?Corre=C3=A7=C3=A3o=20no=20tutorial=20de?= =?UTF-8?q?=20instala=C3=A7=C3=A3o=20(#1967)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adiciona o psycopg2-binary aos requirements do projeto Corrige o tutorial de instalação com passos necessários --- docs/instalacao31.rst | 6 ++++-- requirements/requirements.txt | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/instalacao31.rst b/docs/instalacao31.rst index 0b159b91d..e904f8d6c 100644 --- a/docs/instalacao31.rst +++ b/docs/instalacao31.rst @@ -28,10 +28,10 @@ Instalar as seguintes dependências do sistema:: pkg-config postgresql postgresql-contrib pgadmin3 python-psycopg2 \ software-properties-common build-essential libxml2-dev libjpeg-dev \ libmysqlclient-dev libssl-dev libffi-dev libxslt1-dev python3-setuptools \ - python3-pip curl poppler-utils antiword default-jre + python3-pip curl poppler-utils antiword default-jre python3-venv sudo -i - curl -sL https://deb.nodesource.com/setup_6.x | bash - + curl -sL https://deb.nodesource.com/setup_8.x | bash - exit sudo apt-get install nodejs @@ -184,6 +184,8 @@ Copie a chave que aparecerá, edite o arquivo .env e altere o valor do parâmetr * Instalar as dependências do ``bower``:: eval $(echo "sudo chown -R $USER:$USER /home/$USER/") + sudo chown -R $USER:$GROUP ~/.npm + sudo chown -R $USER:$GROUP ~/.config ./manage.py bower install * Atualizar e/ou criar as tabelas da base de dados para refletir o modelo da versão clonada:: diff --git a/requirements/requirements.txt b/requirements/requirements.txt index fe2e139c8..4b80ad130 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -22,7 +22,7 @@ easy-thumbnails==2.3 django-image-cropping==1.1.0 git+git://github.com/interlegis/trml2pdf.git libsass==0.11.1 -psycopg2==2.7.3 +psycopg2-binary==2.7.4 python-decouple==3.0 pytz==2016.4 pyyaml==3.11 From e1df8e97259d840b144f5f765a790df1ccbcba67 Mon Sep 17 00:00:00 2001 From: Edward Date: Wed, 6 Jun 2018 11:45:05 -0300 Subject: [PATCH 106/119] Fixes #1969 (#1970) --- sapl/templates/protocoloadm/comprovante.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sapl/templates/protocoloadm/comprovante.html b/sapl/templates/protocoloadm/comprovante.html index 031b096c4..9bff567e1 100644 --- a/sapl/templates/protocoloadm/comprovante.html +++ b/sapl/templates/protocoloadm/comprovante.html @@ -61,13 +61,13 @@ Data / Horário {{ protocolo.data|date:"d/m/Y" }} - {{ protocolo.timestamp|date:"H:i:s" }} - {% if protocolo.tipo_processo == 0 %} + {% if protocolo.tipo_processo == 1 %} Ementa {{ protocolo.assunto_ementa }} - Interessado + Autor {{ protocolo.interessado }} {% endif %} @@ -85,5 +85,9 @@ Número Páginas {{ protocolo.numero_paginas }} + + Comprovante emitido por + {{ request.user.username }} + {% endblock detail_content %} From 6e1345d4fa1598b6ec30ef1747fbec0b047c017e Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 6 Jun 2018 11:49:47 -0300 Subject: [PATCH 107/119] HOT-FIX: Adiciona autor ao fix de #1969 --- sapl/templates/protocoloadm/comprovante.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/templates/protocoloadm/comprovante.html b/sapl/templates/protocoloadm/comprovante.html index 9bff567e1..1de22d402 100644 --- a/sapl/templates/protocoloadm/comprovante.html +++ b/sapl/templates/protocoloadm/comprovante.html @@ -68,7 +68,7 @@ Autor - {{ protocolo.interessado }} + {{ protocolo.autor }} {% endif %} From 780df53f33255c3d7ae72c938dadf290c43b08db Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Wed, 6 Jun 2018 14:48:49 -0300 Subject: [PATCH 108/119] Fix #1939 (#1971) --- sapl/parlamentares/forms.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/parlamentares/forms.py b/sapl/parlamentares/forms.py index a7e042037..36ce94c3a 100644 --- a/sapl/parlamentares/forms.py +++ b/sapl/parlamentares/forms.py @@ -261,6 +261,8 @@ class FiliacaoForm(ModelForm): fields = ['partido', 'data', 'data_desfiliacao'] + widgets = {'data': forms.DateInput(attrs={'autocomplete': 'off'}), + 'data_desfiliacao': forms.DateInput(attrs={'autocomplete': 'off'})} def clean(self): super(FiliacaoForm, self).clean() From 47beff90811c022992c44dd604d00adfb0b33417 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 6 Jun 2018 15:53:33 -0300 Subject: [PATCH 109/119] Release: 3.1.82 --- 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 68ab20687..8bc3df3e3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.81 + image: interlegis/sapl:3.1.82 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 9e5c5315d..0ce5a9de3 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.81', + version='3.1.82', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 97c1c7f76e8fb76008ba7320a06e7c46989c947f Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Thu, 7 Jun 2018 14:37:07 -0300 Subject: [PATCH 110/119] fix #1976 (#1977) * fix #1976 * Fix #1975 --- sapl/materia/forms.py | 21 +++++++++- sapl/templates/materia/layouts.yaml | 2 +- .../materia/materialegislativa_form.html | 38 +++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index e5ff928d7..bbfdd3536 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -162,6 +162,11 @@ class MateriaSimplificadaForm(ModelForm): class MateriaLegislativaForm(ModelForm): + tipo_autor = ModelChoiceField(label=_('Tipo Autor'), + required=False, + queryset=TipoAutor.objects.all(), + empty_label=_('------'), ) + autor = forms.ModelChoiceField(required=False, empty_label='------', queryset=Autor.objects.all() @@ -172,6 +177,15 @@ class MateriaLegislativaForm(ModelForm): exclude = ['texto_articulado', 'autores', 'proposicao', 'anexadas', 'data_ultima_atualizacao'] + def __init__(self, *args, **kwargs): + super(MateriaLegislativaForm, self).__init__(*args, **kwargs) + + if self.instance and self.instance.pk: + self.fields['tipo_autor'] = forms.CharField(required=False, + widget=forms.TextInput(attrs={'disabled': 'disabled'})) + self.fields['autor'] = forms.CharField(required=False, + widget=forms.TextInput(attrs={'disabled': 'disabled'})) + def clean(self): super(MateriaLegislativaForm, self).clean() @@ -219,12 +233,17 @@ class MateriaLegislativaForm(ModelForm): return cleaned_data def save(self, commit=False): + if not self.instance.pk: + primeiro_autor = True + else: + primeiro_autor = False + materia = super(MateriaLegislativaForm, self).save(commit) materia.save() if self.cleaned_data['autor']: autoria = Autoria() - autoria.primeiro_autor = True + autoria.primeiro_autor = primeiro_autor autoria.materia = materia autoria.autor = self.cleaned_data['autor'] autoria.save() diff --git a/sapl/templates/materia/layouts.yaml b/sapl/templates/materia/layouts.yaml index 74c11e6c8..d31817b94 100644 --- a/sapl/templates/materia/layouts.yaml +++ b/sapl/templates/materia/layouts.yaml @@ -23,7 +23,7 @@ MateriaLegislativa: {% trans 'Identificação Básica' %}: - tipo ano numero - data_apresentacao numero_protocolo tipo_apresentacao - - autor + - tipo_autor autor - texto_original {% trans 'Outras Informações' %}: - apelido dias_prazo polemica diff --git a/sapl/templates/materia/materialegislativa_form.html b/sapl/templates/materia/materialegislativa_form.html index 335350406..bb435be91 100644 --- a/sapl/templates/materia/materialegislativa_form.html +++ b/sapl/templates/materia/materialegislativa_form.html @@ -22,6 +22,44 @@ } } $("#id_tipo, #id_ano").change(recuperar_numero_ano); + + function compare(a, b) { + if (a.text < b.text) + return -1; + if (a.text > b.text) + return 1; + return 0; + } + + $(document).ready(function() { + $("#id_tipo_autor").change(function() { + var tipo_selecionado = $("#id_tipo_autor").val(); + var autor_selecionado = $("#id_autor").val(); + $("#id_autor option").remove() + if (tipo_selecionado !== undefined && tipo_selecionado !== null) { + var json_data = { + tipo : tipo_selecionado, + data_relativa : $("#id_data_apresentacao").val() + } + $.getJSON("/api/autor/possiveis", json_data, function(data){ + if (data) { + var results = data.sort(compare); + if (results.length > 1) { + $("#id_autor").append(""); + } + $.each(results, function(idx, obj) { + $("#id_autor") + .append($("") + .attr("value", obj.value) + .text(obj.text)); + }); + $("#id_autor").val(autor_selecionado); + } + }); + } + }); + $("#id_tipo_autor").trigger('change'); + }); {% endblock %} From 5bf1d336ff4cd7be5fec632a7d214db3326884e3 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Thu, 7 Jun 2018 14:37:19 -0300 Subject: [PATCH 111/119] Fix #1958 (#1972) --- sapl/norma/forms.py | 7 +++++-- sapl/sessao/forms.py | 8 +++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index affe07b87..81f487c79 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -83,16 +83,19 @@ class NormaJuridicaForm(ModelForm): label='Matéria', required=False, queryset=TipoMateriaLegislativa.objects.all(), - empty_label='Selecione' + empty_label='Selecione', + widget=forms.Select(attrs={'autocomplete': 'off'}) ) numero_materia = forms.CharField( label='Número Matéria', - required=False + required=False, + widget=forms.TextInput(attrs={'autocomplete': 'off'}) ) ano_materia = forms.ChoiceField( label='Ano Matéria', required=False, choices=ANO_CHOICES, + widget=forms.Select(attrs={'autocomplete': 'off'}) ) class Meta: diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index cd46fab84..fced15b7a 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -179,15 +179,17 @@ class ExpedienteMateriaForm(ModelForm): required=True, queryset=TipoMateriaLegislativa.objects.all(), empty_label='Selecione', - ) + widget=forms.Select(attrs={'autocomplete': 'off'})) numero_materia = forms.CharField( - label='Número Matéria', required=True) + label='Número Matéria', required=True, + widget=forms.TextInput(attrs={'autocomplete': 'off'})) ano_materia = forms.CharField( label='Ano Matéria', initial=int(data_atual.year), - required=True) + required=True, + widget=forms.TextInput(attrs={'autocomplete': 'off'})) data_ordem = forms.CharField( label='Data Sessão', From b8e3484ff53e9f7a47a170f5a4d7252b9415fbb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Sconetto?= Date: Thu, 7 Jun 2018 14:37:32 -0300 Subject: [PATCH 112/119] Fix #1939 #1958 (#1978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #1958 * Fix #1939 #1958 Corrige erro de inicialização em formulários Co-authored-by: edwardoliveira --- sapl/audiencia/views.py | 20 +++++++---------- sapl/materia/views.py | 46 +++++++++++++++++++++----------------- sapl/norma/views.py | 22 +++++++++--------- sapl/protocoloadm/views.py | 11 ++++----- sapl/sessao/views.py | 41 ++++++++++++++++++--------------- 5 files changed, 75 insertions(+), 65 deletions(-) diff --git a/sapl/audiencia/views.py b/sapl/audiencia/views.py index c0e353139..2c16b0919 100644 --- a/sapl/audiencia/views.py +++ b/sapl/audiencia/views.py @@ -1,15 +1,10 @@ -from django.shortcuts import render from django.http import HttpResponse -from django.core.urlresolvers import reverse -from django.db.models import F from django.views.decorators.clickjacking import xframe_options_exempt -from django.views.generic import ListView -from sapl.comissoes.forms import ParticipacaoCreateForm, ParticipacaoEditForm -from sapl.crud.base import RP_DETAIL, RP_LIST, Crud, CrudAux, MasterDetailCrud -from sapl.materia.models import MateriaLegislativa +from django.views.generic import UpdateView +from sapl.crud.base import RP_DETAIL, RP_LIST, Crud from .forms import AudienciaForm -from .models import (AudienciaPublica, TipoAudienciaPublica) +from .models import AudienciaPublica def index(request): return HttpResponse("Audiência Pública") @@ -36,10 +31,11 @@ class AudienciaCrud(Crud): form_class = AudienciaForm def get_initial(self): - self.initial['tipo_materia'] = self.object.materia.tipo.id - self.initial['numero_materia'] = self.object.materia.numero - self.initial['ano_materia'] = self.object.materia.ano - return self.initial + initial = super(UpdateView, self).get_initial() + initial['tipo_materia'] = self.object.materia.tipo.id + initial['numero_materia'] = self.object.materia.numero + initial['ano_materia'] = self.object.materia.ano + return initial class DeleteView(Crud.DeleteView): pass diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 74f2bd6b6..807db3d9c 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -17,7 +17,7 @@ from django.shortcuts import get_object_or_404, redirect from django.template import RequestContext, loader from django.utils import formats, timezone from django.utils.translation import ugettext_lazy as _ -from django.views.generic import CreateView, ListView, TemplateView, UpdateView +from django.views.generic import FormView, ListView, TemplateView, CreateView, UpdateView from django.views.generic.base import RedirectView from django.views.generic.edit import FormView from django_filters.views import FilterView @@ -1013,18 +1013,19 @@ class TramitacaoCrud(MasterDetailCrud): 'pk': self.kwargs['pk']}) def get_initial(self): + initial = super(CreateView, self).get_initial() local = MateriaLegislativa.objects.get( pk=self.kwargs['pk']).tramitacao_set.order_by( '-data_tramitacao', '-id').first() if local: - self.initial['unidade_tramitacao_local' + initial['unidade_tramitacao_local' ] = local.unidade_tramitacao_destino.pk else: - self.initial['unidade_tramitacao_local'] = '' - self.initial['data_tramitacao'] = timezone.now().date() - return self.initial + initial['unidade_tramitacao_local'] = '' + initial['data_tramitacao'] = timezone.now().date() + return initial def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -1154,9 +1155,10 @@ class DocumentoAcessorioCrud(MasterDetailCrud): super(MasterDetailCrud.CreateView, self).__init__(**kwargs) def get_initial(self): - self.initial['data'] = timezone.now().date() + initial = super(CreateView, self).get_initial() + initial['data'] = timezone.now().date() - return self.initial + return initial def get_context_data(self, **kwargs): context = super( @@ -1283,10 +1285,11 @@ class LegislacaoCitadaCrud(MasterDetailCrud): form_class = LegislacaoCitadaForm def get_initial(self): - self.initial['tipo'] = self.object.norma.tipo.id - self.initial['numero'] = self.object.norma.numero - self.initial['ano'] = self.object.norma.ano - return self.initial + initial = super(UpdateView, self).get_initial() + initial['tipo'] = self.object.norma.tipo.id + initial['numero'] = self.object.norma.numero + initial['ano'] = self.object.norma.ano + return initial class DetailView(MasterDetailCrud.DetailView): @@ -1319,10 +1322,11 @@ class AnexadaCrud(MasterDetailCrud): form_class = AnexadaForm def get_initial(self): - self.initial['tipo'] = self.object.materia_anexada.tipo.id - self.initial['numero'] = self.object.materia_anexada.numero - self.initial['ano'] = self.object.materia_anexada.ano - return self.initial + initial = super(UpdateView, self).get_initial() + initial['tipo'] = self.object.materia_anexada.tipo.id + initial['numero'] = self.object.materia_anexada.numero + initial['ano'] = self.object.materia_anexada.ano + return initial class DetailView(MasterDetailCrud.DetailView): @@ -1344,16 +1348,18 @@ class MateriaAssuntoCrud(MasterDetailCrud): form_class = MateriaAssuntoForm def get_initial(self): - self.initial['materia'] = self.kwargs['pk'] - return self.initial + initial = super(CreateView, self).get_initial() + initial['materia'] = self.kwargs['pk'] + return initial class UpdateView(MasterDetailCrud.UpdateView): form_class = MateriaAssuntoForm def get_initial(self): - self.initial['materia'] = self.get_object().materia - self.initial['assunto'] = self.get_object().assunto - return self.initial + initial = super(UpdateView, self).get_initial() + initial['materia'] = self.get_object().materia + initial['assunto'] = self.get_object().assunto + return initial class MateriaLegislativaCrud(Crud): diff --git a/sapl/norma/views.py b/sapl/norma/views.py index fd5396353..650442676 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -7,7 +7,7 @@ from django.http import HttpResponse, JsonResponse from django.template import RequestContext, loader from django.utils import timezone from django.utils.translation import ugettext_lazy as _ -from django.views.generic import CreateView, ListView, TemplateView, UpdateView +from django.views.generic import TemplateView, UpdateView from django.views.generic.base import RedirectView from django.views.generic.edit import FormView from django_filters.views import FilterView @@ -51,11 +51,12 @@ class NormaRelacionadaCrud(MasterDetailCrud): form_class = NormaRelacionadaForm def get_initial(self): - self.initial['tipo'] = self.object.norma_relacionada.tipo.id - self.initial['numero'] = self.object.norma_relacionada.numero - self.initial['ano'] = self.object.norma_relacionada.ano - self.initial['ementa'] = self.object.norma_relacionada.ementa - return self.initial + initial = super(UpdateView, self).get_initial() + initial['tipo'] = self.object.norma_relacionada.tipo.id + initial['numero'] = self.object.norma_relacionada.numero + initial['ano'] = self.object.norma_relacionada.ano + initial['ementa'] = self.object.norma_relacionada.ementa + return initial class DetailView(MasterDetailCrud.DetailView): @@ -171,12 +172,13 @@ class NormaCrud(Crud): layout_key = 'NormaJuridicaCreate' def get_initial(self): + initial = super(UpdateView, self).get_initial() norma = NormaJuridica.objects.get(id=self.kwargs['pk']) if norma.materia: - self.initial['tipo_materia'] = norma.materia.tipo - self.initial['ano_materia'] = norma.materia.ano - self.initial['numero_materia'] = norma.materia.numero - return self.initial.copy() + initial['tipo_materia'] = norma.materia.tipo + initial['ano_materia'] = norma.materia.ano + initial['numero_materia'] = norma.materia.numero + return initial def recuperar_norma(request): diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 7dd7206c7..c1a2b185a 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -11,7 +11,7 @@ from django.http.response import HttpResponseRedirect from django.shortcuts import redirect from django.utils import timezone from django.utils.translation import ugettext_lazy as _ -from django.views.generic import CreateView, ListView +from django.views.generic import ListView, CreateView from django.views.generic.base import RedirectView, TemplateView from django.views.generic.edit import FormView from django_filters.views import FilterView @@ -610,18 +610,19 @@ class TramitacaoAdmCrud(MasterDetailCrud): form_class = TramitacaoAdmForm def get_initial(self): + initial = super(CreateView, self).get_initial() local = DocumentoAdministrativo.objects.get( pk=self.kwargs['pk']).tramitacaoadministrativo_set.order_by( '-data_tramitacao', '-id').first() if local: - self.initial['unidade_tramitacao_local' + initial['unidade_tramitacao_local' ] = local.unidade_tramitacao_destino.pk else: - self.initial['unidade_tramitacao_local'] = '' - self.initial['data_tramitacao'] = timezone.now().date() - return self.initial + initial['unidade_tramitacao_local'] = '' + initial['data_tramitacao'] = timezone.now().date() + return initial def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 8700177c0..2f5a2c73f 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -16,7 +16,7 @@ from django.utils.decorators import method_decorator from django.utils.html import strip_tags from django.utils.translation import ugettext_lazy as _ from django.views.decorators.csrf import csrf_exempt -from django.views.generic import FormView, ListView, TemplateView +from django.views.generic import FormView, ListView, TemplateView, CreateView, UpdateView from django.views.generic.base import RedirectView from django.views.generic.detail import DetailView from django.views.generic.edit import FormMixin @@ -418,14 +418,15 @@ class MateriaOrdemDiaCrud(MasterDetailCrud): form_class = OrdemDiaForm def get_initial(self): - self.initial['data_ordem'] = SessaoPlenaria.objects.get( + initial = super(CreateView, self).get_inital() + initial['data_ordem'] = SessaoPlenaria.objects.get( pk=self.kwargs['pk']).data_inicio.strftime('%d/%m/%Y') max_numero_ordem = OrdemDia.objects.filter( sessao_plenaria=self.kwargs['pk']).aggregate( Max('numero_ordem'))['numero_ordem__max'] - self.initial['numero_ordem'] = ( + initial['numero_ordem'] = ( max_numero_ordem if max_numero_ordem else 0) + 1 - return self.initial + return initial def get_success_url(self): return reverse('sapl.sessao:ordemdia_list', @@ -435,10 +436,11 @@ class MateriaOrdemDiaCrud(MasterDetailCrud): form_class = OrdemDiaForm def get_initial(self): - self.initial['tipo_materia'] = self.object.materia.tipo.id - self.initial['numero_materia'] = self.object.materia.numero - self.initial['ano_materia'] = self.object.materia.ano - return self.initial + initial = super(UpdateView, self).get_initial() + initial['tipo_materia'] = self.object.materia.tipo.id + initial['numero_materia'] = self.object.materia.numero + initial['ano_materia'] = self.object.materia.ano + return initial class DetailView(MasterDetailCrud.DetailView): @@ -492,14 +494,15 @@ class ExpedienteMateriaCrud(MasterDetailCrud): form_class = ExpedienteMateriaForm def get_initial(self): - self.initial['data_ordem'] = SessaoPlenaria.objects.get( + initial = super(CreateView, self).get_initial() + initial['data_ordem'] = SessaoPlenaria.objects.get( pk=self.kwargs['pk']).data_inicio.strftime('%d/%m/%Y') max_numero_ordem = ExpedienteMateria.objects.filter( sessao_plenaria=self.kwargs['pk']).aggregate( Max('numero_ordem'))['numero_ordem__max'] - self.initial['numero_ordem'] = ( + initial['numero_ordem'] = ( max_numero_ordem if max_numero_ordem else 0) + 1 - return self.initial + return initial def get_success_url(self): return reverse('sapl.sessao:expedientemateria_list', @@ -509,10 +512,11 @@ class ExpedienteMateriaCrud(MasterDetailCrud): form_class = ExpedienteMateriaForm def get_initial(self): - self.initial['tipo_materia'] = self.object.materia.tipo.id - self.initial['numero_materia'] = self.object.materia.numero - self.initial['ano_materia'] = self.object.materia.ano - return self.initial + initial = super(UpdateView, self).get_initial() + initial['tipo_materia'] = self.object.materia.tipo.id + initial['numero_materia'] = self.object.materia.numero + initial['ano_materia'] = self.object.materia.ano + return initial class DetailView(MasterDetailCrud.DetailView): @@ -1146,9 +1150,10 @@ class ResumoOrdenacaoView(PermissionRequiredMixin, FormView): return reverse('sapl.base:sistema') def get_initial(self): + initial = super(ResumoOrdenacaoView, self).get_initial() ordenacao = ResumoOrdenacao.objects.first() if ordenacao: - return {'primeiro': ordenacao.primeiro, + initial.update({'primeiro': ordenacao.primeiro, 'segundo': ordenacao.segundo, 'terceiro': ordenacao.terceiro, 'quarto': ordenacao.quarto, @@ -1157,8 +1162,8 @@ class ResumoOrdenacaoView(PermissionRequiredMixin, FormView): 'setimo': ordenacao.setimo, 'oitavo': ordenacao.oitavo, 'nono': ordenacao.nono, - 'decimo': ordenacao.decimo} - return self.initial.copy() + 'decimo': ordenacao.decimo}) + return initial def form_valid(self, form): ordenacao = ResumoOrdenacao.objects.get_or_create()[0] From 8694a92a9d2482a818a4a48f4dbb2df1a452d189 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 7 Jun 2018 14:44:51 -0300 Subject: [PATCH 113/119] Release: 3.1.83 --- 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 8bc3df3e3..4439e1cf3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.82 + image: interlegis/sapl:3.1.83 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 0ce5a9de3..0fa8e63ec 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.82', + version='3.1.83', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 034c08491fbadedd30f34972c2c219bbeae574b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Sconetto?= Date: Thu, 7 Jun 2018 15:46:14 -0300 Subject: [PATCH 114/119] Fix #1964 (#1979) --- sapl/norma/forms.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index 81f487c79..2574edb20 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -125,7 +125,11 @@ class NormaJuridicaForm(ModelForm): if not self.is_valid(): return cleaned_data - + norma = NormaJuridica.objects.filter(ano=cleaned_data['ano'], + numero=cleaned_data['numero'], + tipo=cleaned_data['tipo']).exists() + if norma: + raise ValidationError("Já existe uma norma de mesmo Tipo, Ano e Número no sistema") if (cleaned_data['tipo_materia'] and cleaned_data['numero_materia'] and cleaned_data['ano_materia']): From bffeaa3f81323c7cbbfa367138cca19d2948ca1f Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Fri, 8 Jun 2018 14:36:57 -0300 Subject: [PATCH 115/119] FIX #1980 (#1984) --- sapl/sessao/views.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 2f5a2c73f..b50ab32f0 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -418,15 +418,14 @@ class MateriaOrdemDiaCrud(MasterDetailCrud): form_class = OrdemDiaForm def get_initial(self): - initial = super(CreateView, self).get_inital() - initial['data_ordem'] = SessaoPlenaria.objects.get( + self.initial['data_ordem'] = SessaoPlenaria.objects.get( pk=self.kwargs['pk']).data_inicio.strftime('%d/%m/%Y') max_numero_ordem = OrdemDia.objects.filter( sessao_plenaria=self.kwargs['pk']).aggregate( Max('numero_ordem'))['numero_ordem__max'] - initial['numero_ordem'] = ( + self.initial['numero_ordem'] = ( max_numero_ordem if max_numero_ordem else 0) + 1 - return initial + return self.initial def get_success_url(self): return reverse('sapl.sessao:ordemdia_list', From 136fa589d9f85e19598fd0d4a47f6c7fc542c752 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Fri, 8 Jun 2018 14:42:36 -0300 Subject: [PATCH 116/119] Release: 3.1.84 --- 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 4439e1cf3..3ca5f0f4e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.83 + image: interlegis/sapl:3.1.84 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 0fa8e63ec..fd4ed2708 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.83', + version='3.1.84', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 75ebef24cb697c9d0dddf8d979c004cc5b22d79b Mon Sep 17 00:00:00 2001 From: Edward Date: Fri, 8 Jun 2018 16:53:20 -0300 Subject: [PATCH 117/119] =?UTF-8?q?HOT-FIX:=20Limita=20a=20quantidade=20de?= =?UTF-8?q?=20requisi=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adiciona o parâmetro `--max-requests 1000` para limitar a quantidade de requisições que um worker atende antes de reiniciar (no caso para 1.000) --- gunicorn_start.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/gunicorn_start.sh b/gunicorn_start.sh index 6b5c98676..a6611eea7 100755 --- a/gunicorn_start.sh +++ b/gunicorn_start.sh @@ -41,6 +41,7 @@ test -d $RUNDIR || mkdir -p $RUNDIR exec gunicorn ${DJANGO_WSGI_MODULE}:application \ --name $NAME \ --workers $NUM_WORKERS \ + --max-requests 1000 --user $USER \ --access-logfile - \ --error-logfile - \ From e8c6a261279756fd0430baf5dc779f0fe106d3a1 Mon Sep 17 00:00:00 2001 From: Edward Date: Fri, 8 Jun 2018 16:59:09 -0300 Subject: [PATCH 118/119] =?UTF-8?q?HOT-FIX:=20atualiza=20n=C3=BAmero=20de?= =?UTF-8?q?=20workers=20e=20requests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gunicorn_start.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gunicorn_start.sh b/gunicorn_start.sh index a6611eea7..827aee378 100755 --- a/gunicorn_start.sh +++ b/gunicorn_start.sh @@ -16,8 +16,9 @@ DJANGODIR=/var/interlegis/sapl/ # Django project directory (* SOCKFILE=/var/interlegis/sapl/run/gunicorn.sock # we will communicate using this unix socket (*) USER=`whoami` # the user to run as (*) GROUP=`whoami` # the group to run as (*) -NUM_WORKERS=9 # how many worker processes should Gunicorn spawn (*) +NUM_WORKERS=5 # how many worker processes should Gunicorn spawn (*) # NUM_WORKERS = 2 * CPUS + 1 +MAX_REQUESTS=500 # number of requests before restarting worker DJANGO_SETTINGS_MODULE=sapl.settings # which settings file should Django use (*) DJANGO_WSGI_MODULE=sapl.wsgi # WSGI module name (*) @@ -41,7 +42,7 @@ test -d $RUNDIR || mkdir -p $RUNDIR exec gunicorn ${DJANGO_WSGI_MODULE}:application \ --name $NAME \ --workers $NUM_WORKERS \ - --max-requests 1000 + --max-requests $MAX_REQUESTS \ --user $USER \ --access-logfile - \ --error-logfile - \ From 08a388da34445264845fcf797096335ba20b946a Mon Sep 17 00:00:00 2001 From: Edward Date: Fri, 8 Jun 2018 17:54:21 -0300 Subject: [PATCH 119/119] =?UTF-8?q?Diminui=20max-requests=20e=20n=C3=BAmer?= =?UTF-8?q?o=20de=20workers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gunicorn_start.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gunicorn_start.sh b/gunicorn_start.sh index 827aee378..6247a0b27 100755 --- a/gunicorn_start.sh +++ b/gunicorn_start.sh @@ -16,9 +16,9 @@ DJANGODIR=/var/interlegis/sapl/ # Django project directory (* SOCKFILE=/var/interlegis/sapl/run/gunicorn.sock # we will communicate using this unix socket (*) USER=`whoami` # the user to run as (*) GROUP=`whoami` # the group to run as (*) -NUM_WORKERS=5 # how many worker processes should Gunicorn spawn (*) +NUM_WORKERS=4 # how many worker processes should Gunicorn spawn (*) # NUM_WORKERS = 2 * CPUS + 1 -MAX_REQUESTS=500 # number of requests before restarting worker +MAX_REQUESTS=100 # number of requests before restarting worker DJANGO_SETTINGS_MODULE=sapl.settings # which settings file should Django use (*) DJANGO_WSGI_MODULE=sapl.wsgi # WSGI module name (*)