From 2ad74d7e501ae88d59ebd56a87597028d885a029 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 23 Feb 2018 15:10:21 -0300 Subject: [PATCH 01/23] =?UTF-8?q?Adiciona=20valida=C3=A7=C3=A3o=20de=20Reg?= =?UTF-8?q?istroVotacao?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/sessao/models.py | 14 ++++++++++++++ sapl/sessao/tests/test_sessao.py | 28 ++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py index db7c50d9b..f4f25cc14 100644 --- a/sapl/sessao/models.py +++ b/sapl/sessao/models.py @@ -1,7 +1,11 @@ +from operator import xor + import reversion +from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import ugettext_lazy as _ from model_utils import Choices + from sapl.base.models import Autor from sapl.materia.models import MateriaLegislativa from sapl.parlamentares.models import (CargoMesa, Legislatura, Parlamentar, @@ -429,6 +433,16 @@ class RegistroVotacao(models.Model): 'votacao': self.tipo_resultado_votacao, 'materia': self.materia} + def clean(self): + """Exatamente um dos campos ordem ou expediente deve estar preenchido. + """ + # TODO remover esse método quando OrdemDia e ExpedienteMateria + # forem reestruturados e os campos ordem e expediente forem unificados + if not xor(bool(self.ordem), bool(self.expediente)): + raise ValidationError( + 'RegistroVotacao deve ter exatamente um dos campos ' + 'ordem ou expediente deve estar preenchido') + @reversion.register() class VotoParlamentar(models.Model): # RegistroVotacaoParlamentar diff --git a/sapl/sessao/tests/test_sessao.py b/sapl/sessao/tests/test_sessao.py index 37a17d1ed..d83c56e86 100644 --- a/sapl/sessao/tests/test_sessao.py +++ b/sapl/sessao/tests/test_sessao.py @@ -1,11 +1,13 @@ import pytest +from django.core.exceptions import ValidationError from django.utils.translation import ugettext_lazy as _ from model_mommy import mommy + from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.parlamentares.models import Legislatura, Partido, SessaoLegislativa from sapl.sessao import forms -from sapl.sessao.models import (ExpedienteMateria, SessaoPlenaria, - TipoSessaoPlenaria) +from sapl.sessao.models import (ExpedienteMateria, OrdemDia, RegistroVotacao, + SessaoPlenaria, TipoSessaoPlenaria) def test_valida_campos_obrigatorios_sessao_plenaria_form(): @@ -138,3 +140,25 @@ def test_expediente_materia_form_valido(): }, instance=instance) assert form.is_valid() + + +@pytest.mark.django_db(transaction=False) +def test_registro_votacao_tem_ordem_xor_expediente(): + + def registro_votacao_com(ordem, expediente): + return mommy.make(RegistroVotacao, ordem=ordem, expediente=expediente) + + ordem = mommy.make(OrdemDia) + expediente = mommy.make(ExpedienteMateria) + + # a validação funciona com exatamente um dos campos preenchido + registro_votacao_com(ordem, None).full_clean() + registro_votacao_com(None, expediente).full_clean() + + # a validação NÃO funciona quando nenhum deles é preenchido + with pytest.raises(ValidationError): + registro_votacao_com(None, None).full_clean() + + # a validação NÃO funciona quando ambos são preenchidos + with pytest.raises(ValidationError): + registro_votacao_com(ordem, expediente).full_clean() From 8e1af5765f2888a42fefe242dbcd486193a38c29 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 26 Feb 2018 12:31:33 -0300 Subject: [PATCH 02/23] =?UTF-8?q?Revisa=20migra=C3=A7=C3=A3o=20de=20Regist?= =?UTF-8?q?roVotacao?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Não exclui registro de votação duplicados. --- sapl/legacy/migration.py | 126 ++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 74 deletions(-) diff --git a/sapl/legacy/migration.py b/sapl/legacy/migration.py index e5d98147b..1ab22da4c 100644 --- a/sapl/legacy/migration.py +++ b/sapl/legacy/migration.py @@ -437,10 +437,10 @@ relatoria | tip_fim_relatoria = NULL | tip_fim_relatoria = 0 anula_tipos_origem_externa_invalidos() -def iter_sql_records(sql, db): +def iter_sql_records(sql): class Record: pass - cursor = exec_sql(sql, db) + cursor = exec_legado(sql) fieldnames = [name[0] for name in cursor.description] for row in cursor.fetchall(): record = Record() @@ -534,24 +534,6 @@ def excluir_registrovotacao_duplicados(): assert 0 -def delete_old(legacy_model, cols_values): - # ajuste necessário por conta de cósigos html em txt_expediente - if legacy_model.__name__ == 'ExpedienteSessaoPlenaria': - cols_values.pop('txt_expediente') - - def eq_clause(col, value): - if value is None: - return '{} IS NULL'.format(col) - else: - return '{}="{}"'.format(col, value) - - delete_sql = 'delete from {} where {}'.format( - legacy_model._meta.db_table, - ' and '.join([eq_clause(col, value) - for col, value in cols_values.items()])) - exec_sql(delete_sql, 'legacy') - - def get_last_pk(model): last_value = model.objects.all().aggregate(Max('pk')) return last_value['pk__max'] or 0 @@ -563,6 +545,12 @@ def reinicia_sequence(model, id): sequence_name, id)) +def get_pk_legado(tabela): + res = exec_legado( + 'show index from {} WHERE Key_name = "PRIMARY"'.format(tabela)) + return [r[4] for r in res] + + class DataMigrator: def __init__(self): @@ -648,8 +636,8 @@ class DataMigrator: info('Começando migração: %s...' % obj) self._do_migrate(obj) - info('Excluindo possíveis duplicações em RegistroVotacao...') - excluir_registrovotacao_duplicados() + # info('Excluindo possíveis duplicações em RegistroVotacao...') + # excluir_registrovotacao_duplicados() # recria tipos de autor padrão que não foram criados pela migração cria_models_tipo_autor() @@ -677,45 +665,29 @@ class DataMigrator: def migrate_model(self, model): print('Migrando %s...' % model.__name__) - legacy_model_name = self.model_renames.get(model, model.__name__) - legacy_model = legacy_app.get_model(legacy_model_name) - legacy_pk_name = legacy_model._meta.pk.name - - # setup migration strategy for tables with or without a pk - if legacy_pk_name == 'id': - deve_ajustar_sequence_ao_final = False - # There is no pk in the legacy table + nome_model = self.model_renames.get(model, model.__name__) + model_legado = legacy_app.get_model(nome_model) + tabela_legado = model_legado._meta.db_table + campos_pk = get_pk_legado(tabela_legado) - def save(new, old): - with reversion.create_revision(): - new.save() - reversion.set_comment('Objeto criado pela migração') + if len(campos_pk) == 1: + # a pk no legado tem um único campo + nome_pk = model_legado._meta.pk.name + old_records = model_legado.objects.all().order_by(nome_pk) - # apaga registro do legado - delete_old(legacy_model, old.__dict__) - - old_records = iter_sql_records( - 'select * from ' + legacy_model._meta.db_table, 'legacy') + def get_id_do_legado(old): + return getattr(old, nome_pk) else: - deve_ajustar_sequence_ao_final = True - - def save(new, old): - with reversion.create_revision(): - # salva new com id de old - new.id = getattr(old, legacy_pk_name) - new.save() - reversion.set_comment('Objeto criado pela migração') - - # apaga registro do legado - delete_old(legacy_model, {legacy_pk_name: new.id}) - - old_records = legacy_model.objects.all().order_by(legacy_pk_name) + # a pk no legado tem mais de um campo + old_records = iter_sql_records('select * from ' + tabela_legado) + get_id_do_legado = None ajuste_antes_salvar = AJUSTE_ANTES_SALVAR.get(model) ajuste_depois_salvar = AJUSTE_DEPOIS_SALVAR.get(model) # convert old records to new ones with transaction.atomic(): + sql_delete_legado = '' for old in old_records: if getattr(old, 'ind_excluido', False): # não migramos registros marcados como excluídos @@ -731,15 +703,35 @@ class DataMigrator: # então este é um objeo órfão: simplesmente ignoramos continue else: - save(new, old) + if get_id_do_legado: + new.id = get_id_do_legado(old) + # validação do model + new.clean() + # salva novo registro + with reversion.create_revision(): + new.save() + reversion.set_comment('Objeto criado pela migração') + + # acumula deleção do registro no legado + sql_delete_legado += 'delete from {} where {};\n'.format( + tabela_legado, + ' and '.join( + '{} = "{}"'.format(campo, + getattr(old, campo)) + for campo in campos_pk)) + if ajuste_depois_salvar: ajuste_depois_salvar(new, old) - # reinicia sequence - if deve_ajustar_sequence_ao_final: + # se configuramos ids explicitamente devemos reiniciar a sequence + if get_id_do_legado: last_pk = get_last_pk(model) reinicia_sequence(model, last_pk + 1) + # apaga registros migrados do legado + if sql_delete_legado: + exec_legado(sql_delete_legado) + def migrate(obj=appconfs, interativo=True): dm = DataMigrator() @@ -797,7 +789,7 @@ def adjust_ordemdia_antes_salvar(new, old): def adjust_ordemdia_depois_salvar(new, old): if old.num_ordem is None and new.numero_ordem == 999999999: with reversion.create_revision(): - problema = 'OrdemDia de PK %s tinha seu valor de numero ordem'\ + problema = 'OrdemDia de PK %s tinha seu valor de numero ordem' \ ' nulo.' % old.pk descricao = 'O valor %s foi colocado no lugar.' % new.numero_ordem warn(problema + ' => ' + descricao) @@ -882,19 +874,6 @@ def adjust_registrovotacao_antes_salvar(new, old): new.expediente = expediente_materia[0] -def adjust_registrovotacao_depois_salvar(new, old): - if not new.ordem and not new.expediente: - with reversion.create_revision(): - problema = 'RegistroVotacao de PK %s não possui nenhuma OrdemDia'\ - ' ou ExpedienteMateria.' % old.pk - descricao = 'RevistroVotacao deve ter no mínimo uma ordem do dia'\ - ' ou expediente vinculado.' - warn(problema + ' => ' + descricao) - save_relation(obj=new, problema=problema, - descricao=descricao, eh_stub=False) - reversion.set_comment('RegistroVotacao sem ordem ou expediente') - - def adjust_tipoafastamento(new, old): if old.ind_afastamento == 1: new.indicador = 'A' @@ -1010,8 +989,8 @@ def adjust_autor(new, old): def adjust_comissao(new, old): if not old.dat_extincao and not old.dat_fim_comissao: new.ativa = True - elif old.dat_extincao and date.today() < new.data_extincao or \ - old.dat_fim_comissao and date.today() < new.data_fim_comissao: + elif (old.dat_extincao and date.today() < new.data_extincao or + old.dat_fim_comissao and date.today() < new.data_fim_comissao): new.ativa = True else: new.ativa = False @@ -1043,15 +1022,14 @@ AJUSTE_DEPOIS_SALVAR = { NormaJuridica: adjust_normajuridica_depois_salvar, OrdemDia: adjust_ordemdia_depois_salvar, Protocolo: adjust_protocolo_depois_salvar, - RegistroVotacao: adjust_registrovotacao_depois_salvar, } # CHECKS #################################################################### def get_ind_excluido(new): - legacy_model = legacy_app.get_model(type(new).__name__) - old = legacy_model.objects.get(**{legacy_model._meta.pk.name: new.id}) + model_legado = legacy_app.get_model(type(new).__name__) + old = model_legado.objects.get(**{model_legado._meta.pk.name: new.id}) return getattr(old, 'ind_excluido', False) From 65354f0e20d9193d6fad117fc7a11a669e03e469 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 26 Feb 2018 17:01:06 -0300 Subject: [PATCH 03/23] =?UTF-8?q?Adicionado=20mimetype=20do=20excel=20?= =?UTF-8?q?=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 e31aa4d81..c097c1a1a 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -22,6 +22,7 @@ EXTENSOES = { 'application/msword': '.doc', 'application/pdf': '.pdf', 'application/vnd.oasis.opendocument.text': '.odt', + 'application/vnd.ms-excel': '.xls', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx', # noqa 'application/xml': '.xml', 'text/xml': '.xml', @@ -219,6 +220,7 @@ DUMP_FUNCTIONS = { 'Folder': partial(dump_folder, enum=enumerate_folder), 'BTreeFolder2': partial(dump_folder, enum=enumerate_btree), 'SDE-Document': partial(dump_sde, tipo='sde.document'), + 'StrDoc': partial(dump_sde, tipo='sde.document'), 'SDE-Template': partial(dump_sde, tipo='sde.template'), # explicitamente ignorados From 2fb499fedf6e47e7af21b913f2861ccc6858f5f7 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 27 Feb 2018 07:16:35 -0300 Subject: [PATCH 04/23] Migra documento adm mesmo sem protocolo --- sapl/legacy/migracao_usuarios.py | 1 + sapl/legacy/migration.py | 36 +++++++++++++++++++------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/sapl/legacy/migracao_usuarios.py b/sapl/legacy/migracao_usuarios.py index bd7d413e5..591f08b20 100644 --- a/sapl/legacy/migracao_usuarios.py +++ b/sapl/legacy/migracao_usuarios.py @@ -92,3 +92,4 @@ def migra_usuarios(): usuario.groups.add(PERFIL_LEGADO_PARA_NOVO[perfil]) # apaga arquivo (importante pois contém senhas) ARQUIVO_USUARIOS.remove() + print('Usuários migrados com sucesso.') diff --git a/sapl/legacy/migration.py b/sapl/legacy/migration.py index 1ab22da4c..b67501ab9 100644 --- a/sapl/legacy/migration.py +++ b/sapl/legacy/migration.py @@ -121,7 +121,9 @@ def warn(msg): class ForeignKeyFaltando(ObjectDoesNotExist): 'Uma FK aponta para um registro inexistente' - pass + + def __init__(self, msg=''): + self.msg = msg @lru_cache() @@ -697,10 +699,11 @@ class DataMigrator: self.populate_renamed_fields(new, old) if ajuste_antes_salvar: ajuste_antes_salvar(new, old) - except ForeignKeyFaltando: + except ForeignKeyFaltando as e: # tentamos preencher uma FK e o ojeto relacionado # não existe # então este é um objeo órfão: simplesmente ignoramos + warn(e.msg) continue else: if get_id_do_legado: @@ -749,19 +752,21 @@ def adjust_documentoadministrativo(new, old): protocolo = Protocolo.objects.filter( numero=old.num_protocolo, ano=new.ano) if not protocolo: + # tentamos encontrar o protocolo no ano seguinte protocolo = Protocolo.objects.filter( numero=old.num_protocolo, ano=new.ano + 1) - print('PROTOCOLO ENCONTRADO APENAS PARA O ANO SEGUINTE!!!!! ' - 'DocumentoAdministrativo: {}, numero_protocolo: {}, ' - 'ano doc adm: {}'.format( - old.cod_documento, old.num_protocolo, new.ano)) - if not protocolo: - raise ForeignKeyFaltando( - 'Protocolo {} faltando ' - '(referenciado no documento administrativo {}'.format( - old.num_protocolo, old.cod_documento)) - assert len(protocolo) == 1 - new.protocolo = protocolo[0] + if protocolo: + print('PROTOCOLO ENCONTRADO APENAS PARA O ANO SEGUINTE!!!!! ' + 'DocumentoAdministrativo: {}, numero_protocolo: {}, ' + 'ano doc adm: {}'.format( + old.cod_documento, old.num_protocolo, new.ano)) + else: + warn('Protocolo {} faltando ' + '(referenciado no documento administrativo {}'.format( + old.num_protocolo, old.cod_documento)) + if protocolo: + assert len(protocolo) == 1, 'mais de um protocolo encontrado' + [new.protocolo] = protocolo def adjust_mandato(new, old): @@ -954,8 +959,9 @@ def vincula_autor(new, old, model_relacionado, campo_relacionado, campo_nome): new.autor_related = model_relacionado.objects.get(pk=pk_rel) except ObjectDoesNotExist: # ignoramos o autor órfão - raise ForeignKeyFaltando('{} inexiste para autor'.format( - model_relacionado._meta.verbose_name)) + raise ForeignKeyFaltando( + '{} [pk={}] inexistente para autor'.format( + model_relacionado._meta.verbose_name, pk_rel)) else: new.nome = getattr(new.autor_related, campo_nome) return True From 2310316488e4d781326dbc35103c3fc28f43cd8d Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 27 Feb 2018 10:18:55 -0300 Subject: [PATCH 05/23] =?UTF-8?q?Checa=20registros=20de=20vota=C3=A7=C3=A3?= =?UTF-8?q?o=20na=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/migration.py | 42 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/sapl/legacy/migration.py b/sapl/legacy/migration.py index b67501ab9..abd232d47 100644 --- a/sapl/legacy/migration.py +++ b/sapl/legacy/migration.py @@ -352,9 +352,47 @@ def anula_tipos_origem_externa_invalidos(): where tip_origem_externa not in {};''', tipos_validos) +def get_ids_registros_votacao_para(tabela): + sql = ''' + select r.cod_votacao from {} o + inner join registro_votacao r on + o.cod_ordem = r.cod_ordem and o.cod_materia = r.cod_materia + where o.ind_excluido != 1 and r.ind_excluido != 1 + order by o.cod_sessao_plen, num_ordem + '''.format(tabela) + return set(primeira_coluna(exec_legado(sql))) + + +def checa_registros_votacao_ambiguos_e_remove_nao_usados(): + """Interrompe a migração caso restem registros de votação + que apontam para uma ordem_dia e um expediente_materia ao mesmo tempo. + + Remove do legado registros de votação que não têm + nem ordem_dia nem expediente_materia associados.""" + + ordem, expediente = [ + get_ids_registros_votacao_para(tabela) + for tabela in ('ordem_dia', 'expediente_materia')] + + # interrompe migração se houver registros ambíguos + ambiguos = ordem.intersection(expediente) + assert not ambiguos, '''Existe(m) RegistroVotacao ambíguo(s): {} + Corrija os dados originais antes de migrar!'''.format( + ambiguos) + + # exclui registros não usados (zumbis) + todos = set(primeira_coluna(exec_legado( + 'select cod_votacao from registro_votacao'))) + nao_usados = todos - ordem.union(expediente) + exec_legado_em_subconjunto(''' + update registro_votacao set ind_excluido = 1 + where cod_votacao in {}''', nao_usados) + + def uniformiza_banco(): - # desliga todas as checagens do mysql - exec_legado('SET SESSION sql_mode = "";') + exec_legado('SET SESSION sql_mode = "";') # desliga checagens do mysql + + checa_registros_votacao_ambiguos_e_remove_nao_usados() garante_coluna_no_legado('proposicao', 'num_proposicao int(11) NULL') From 505af2f13ef012ae28c1aff0610a78071ed08b31 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Tue, 27 Feb 2018 14:59:36 -0300 Subject: [PATCH 06/23] =?UTF-8?q?add=20menu=20de=20config=20de=20TAs=20nas?= =?UTF-8?q?=20Tabelas=20Auxili=C3=A1res?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compilacao/textoarticulado_menu_config.html | 5 ++++- sapl/templates/sistema.html | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/sapl/templates/compilacao/textoarticulado_menu_config.html b/sapl/templates/compilacao/textoarticulado_menu_config.html index 976f18148..0116ba667 100644 --- a/sapl/templates/compilacao/textoarticulado_menu_config.html +++ b/sapl/templates/compilacao/textoarticulado_menu_config.html @@ -1,5 +1,7 @@ {% load i18n %} {% load common_tags %} + +{% if user.is_superuser %} @@ -13,6 +15,7 @@ {% if user.is_superuser %}
  • {%model_verbose_name_plural 'sapl.compilacao.models.TipoDispositivo'%}
  • -
  • TODO: Perfil Estrutural de Textos Articulados
  • +
  • Relacionamento entre Dispositivos
  • {% endif %} +{% endif %} diff --git a/sapl/templates/sistema.html b/sapl/templates/sistema.html index cfc7ed82d..643c38a9b 100644 --- a/sapl/templates/sistema.html +++ b/sapl/templates/sistema.html @@ -74,6 +74,20 @@ + +
    +

    Módulo Textos Articulados

    + + +

    Módulo Sessão Plenária

    From 799f766935e7505b7f2f1bc49d839b0766da26d0 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Tue, 27 Feb 2018 15:25:31 -0300 Subject: [PATCH 07/23] =?UTF-8?q?refatora=20gera=C3=A7=C3=A3o=20de=20base?= =?UTF-8?q?=20inicial=20de=20compila=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/compilacao/apps.py | 96 +++++++++++++++++++++++++++++++++++++++- sapl/compilacao/views.py | 63 +------------------------- 2 files changed, 97 insertions(+), 62 deletions(-) diff --git a/sapl/compilacao/apps.py b/sapl/compilacao/apps.py index 85c8ba349..6b96175b5 100644 --- a/sapl/compilacao/apps.py +++ b/sapl/compilacao/apps.py @@ -1,8 +1,102 @@ +import logging + from django import apps -from django.utils.translation import ugettext_lazy as _ +from django.conf import settings +from django.db import models, connection +from django.db.utils import DEFAULT_DB_ALIAS, IntegrityError +from django.utils.translation import ugettext_lazy as _, string_concat + + +from sapl.settings import BASE_DIR + +logger = logging.getLogger(BASE_DIR.name) class AppConfig(apps.AppConfig): name = 'sapl.compilacao' label = 'compilacao' verbose_name = _('Compilação') + + @staticmethod + def import_pattern(): + + from sapl.compilacao.models import TipoTextoArticulado + from sapl.compilacao.utils import get_integrations_view_names + + from django.contrib.contenttypes.models import ContentType + from unipath import Path + + compilacao_app = Path(__file__).ancestor(1) + # print(compilacao_app) + with open(compilacao_app + '/compilacao_data_tables.sql', 'r') as f: + lines = f.readlines() + lines = [line.rstrip('\n') for line in lines] + + with connection.cursor() as cursor: + for line in lines: + line = line.strip() + if not line or line.startswith('#'): + continue + + try: + cursor.execute(line) + except IntegrityError as e: + if not settings.DEBUG: + logger.error( + string_concat( + _('Ocorreu erro na importação: '), + line, + str(e))) + except Exception as ee: + print(ee) + + integrations_view_names = get_integrations_view_names() + + def cria_sigla(verbose_name): + verbose_name = verbose_name.upper().split() + if len(verbose_name) == 1: + verbose_name = verbose_name[0] + sigla = '' + for letra in verbose_name: + if letra in 'BCDFGHJKLMNPQRSTVWXYZ': + sigla += letra + else: + sigla = ''.join([palavra[0] for palavra in verbose_name]) + return sigla[:3] + + for view in integrations_view_names: + try: + tipo = TipoTextoArticulado() + tipo.sigla = cria_sigla( + view.model._meta.verbose_name + if view.model._meta.verbose_name + else view.model._meta.model_name) + tipo.descricao = view.model._meta.verbose_name + tipo.content_type = ContentType.objects.get_by_natural_key( + view.model._meta.app_label, view.model._meta.model_name) + tipo.save() + except IntegrityError as e: + if not settings.DEBUG: + logger.error( + string_concat( + _('Ocorreu erro na criação tipo de ta: '), + str(e))) + + +def init_compilacao_base(app_config, verbosity=2, interactive=True, + using=DEFAULT_DB_ALIAS, **kwargs): + + if app_config != AppConfig and not isinstance(app_config, AppConfig): + return + from sapl.compilacao.models import TipoDispositivo + if not TipoDispositivo.objects.exists(): + + print('') + print(string_concat('\033[93m\033[1m', + _('Iniciando Textos Articulados...'), + '\033[0m')) + AppConfig.import_pattern() + + +models.signals.post_migrate.connect( + receiver=init_compilacao_base) diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index 523de19a2..b24bfd677 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -27,6 +27,7 @@ from django.views.generic.edit import (CreateView, DeleteView, FormView, UpdateView) from django.views.generic.list import ListView +from sapl.compilacao.apps import AppConfig from sapl.compilacao.forms import (DispositivoDefinidorVigenciaForm, DispositivoEdicaoAlteracaoForm, DispositivoEdicaoBasicaForm, @@ -107,7 +108,7 @@ class IntegracaoTaView(TemplateView): try: if settings.DEBUG or not TipoDispositivo.objects.exists(): - self.import_pattern() + AppConfig.import_pattern() if hasattr(self, 'map_funcs'): tipo_ta = TipoTextoArticulado.objects.get( @@ -195,66 +196,6 @@ class IntegracaoTaView(TemplateView): return redirect(to=reverse_lazy('sapl.compilacao:ta_text', kwargs={'ta_id': ta.pk})) - def import_pattern(self): - - from unipath import Path - - compilacao_app = Path(__file__).ancestor(1) - # print(compilacao_app) - with open(compilacao_app + '/compilacao_data_tables.sql', 'r') as f: - lines = f.readlines() - lines = [line.rstrip('\n') for line in lines] - - with connection.cursor() as cursor: - for line in lines: - line = line.strip() - if not line or line.startswith('#'): - continue - - try: - cursor.execute(line) - except IntegrityError as e: - if not settings.DEBUG: - logger.error( - string_concat( - _('Ocorreu erro na importação: '), - line, - str(e))) - except Exception as ee: - print(ee) - - integrations_view_names = get_integrations_view_names() - - def cria_sigla(verbose_name): - verbose_name = verbose_name.upper().split() - if len(verbose_name) == 1: - verbose_name = verbose_name[0] - sigla = '' - for letra in verbose_name: - if letra in 'BCDFGHJKLMNPQRSTVWXYZ': - sigla += letra - else: - sigla = ''.join([palavra[0] for palavra in verbose_name]) - return sigla[:3] - - for view in integrations_view_names: - try: - tipo = TipoTextoArticulado() - tipo.sigla = cria_sigla( - view.model._meta.verbose_name - if view.model._meta.verbose_name - else view.model._meta.model_name) - tipo.descricao = view.model._meta.verbose_name - tipo.content_type = ContentType.objects.get_by_natural_key( - view.model._meta.app_label, view.model._meta.model_name) - tipo.save() - except IntegrityError as e: - if not settings.DEBUG: - logger.error( - string_concat( - _('Ocorreu erro na criação tipo de ta: '), - str(e))) - class Meta: abstract = True From 150180166f341aa7a91c7695b2fe114270fdbb80 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Tue, 27 Feb 2018 16:02:41 -0300 Subject: [PATCH 08/23] remove teste do form de tipos de texto articulado --- .../tests/test_tipo_texto_articulado_form.py | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/sapl/compilacao/tests/test_tipo_texto_articulado_form.py b/sapl/compilacao/tests/test_tipo_texto_articulado_form.py index 84593650f..b682307c9 100644 --- a/sapl/compilacao/tests/test_tipo_texto_articulado_form.py +++ b/sapl/compilacao/tests/test_tipo_texto_articulado_form.py @@ -1,6 +1,7 @@ -import pytest from django.utils.translation import ugettext as _ from model_mommy import mommy +import pytest + from sapl.compilacao import forms from sapl.compilacao.models import PerfilEstruturalTextoArticulado, TipoNota from sapl.compilacao.views import choice_models_in_extenal_views @@ -21,25 +22,6 @@ def test_valida_campos_obrigatorios_tipo_texto_articulado_form(): assert len(errors) == 4 -_content_types = choice_models_in_extenal_views() - - -@pytest.mark.parametrize('content_type', _content_types) -@pytest.mark.django_db(transaction=False) -def test_tipo_texto_articulado_form_valid(content_type): - perfil = mommy.make(PerfilEstruturalTextoArticulado) - - form = forms.TipoTaForm(data={'sigla': 'si', - 'descricao': 'teste', - 'content_type': content_type[0], - 'participacao_social': True, - 'publicacao_func': True, - 'perfis': [perfil.pk, ] - }) - - assert form.is_valid(), form.errors - - def test_valida_campos_obrigatorios_nota_form(): form = forms.NotaForm(data={}) From 345da6ddccfb5e97915e81df418da80dfafab9e8 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Wed, 28 Feb 2018 11:59:07 -0300 Subject: [PATCH 09/23] add thumbnail generator customizado MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit assim como a os broswer para rendenderizar a tag desconsideram a informação de EXIF.orientation, um thumbnail_generator customizado é necessário para manter a comportamento... para haver reflexo, as imagens secundárias devem ser apagadas de MEDIA_ROOT, não sendo necessário pois, reenviar as imagens primárias. --- sapl/settings.py | 3 +++ sapl/utils.py | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/sapl/settings.py b/sapl/settings.py index 31905aa07..2e6b7c7ff 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -188,6 +188,9 @@ THUMBNAIL_PROCESSORS = ( 'image_cropping.thumbnail_processors.crop_corners', ) + thumbnail_settings.THUMBNAIL_PROCESSORS +THUMBNAIL_SOURCE_GENERATORS = ( + 'sapl.utils.pil_image', +) # troque no caso de reimplementação da classe User conforme # https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#substituting-a-custom-user-model diff --git a/sapl/utils.py b/sapl/utils.py index 01f0f5f2b..3a3cb3fad 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -1,13 +1,11 @@ +from functools import wraps +from operator import itemgetter +from unicodedata import normalize as unicodedata_normalize import hashlib import logging import os import re -from functools import wraps -from operator import itemgetter -from unicodedata import normalize as unicodedata_normalize -import django_filters -import magic from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML, Button from django import forms @@ -21,14 +19,23 @@ from django.db.models import Q from django.utils import six, timezone from django.utils.translation import ugettext_lazy as _ from django_filters.filterset import STRICTNESS +from easy_thumbnails import source_generators from floppyforms import ClearableFileInput from reversion.admin import VersionAdmin +import django_filters +import magic + from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row from sapl.settings import BASE_DIR + sapl_logger = logging.getLogger(BASE_DIR.name) +def pil_image(source, exif_orientation=False, **options): + return source_generators.pil_image(source, exif_orientation, **options) + + def normalize(txt): return unicodedata_normalize( 'NFKD', txt).encode('ASCII', 'ignore').decode('ASCII') From 956d6a5a3a80e5083ef3879ec10513c2c3a41079 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Wed, 28 Feb 2018 13:04:13 -0300 Subject: [PATCH 10/23] =?UTF-8?q?add=20limp=20de=20varia=C3=A7=C3=B5es=20d?= =?UTF-8?q?e=20arq=20em=20camp=20baseados=20em=20FileField?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0021_clear_thumbnails_cache.py | 23 +++++++++++++++++++ sapl/utils.py | 18 +++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 sapl/parlamentares/migrations/0021_clear_thumbnails_cache.py diff --git a/sapl/parlamentares/migrations/0021_clear_thumbnails_cache.py b/sapl/parlamentares/migrations/0021_clear_thumbnails_cache.py new file mode 100644 index 000000000..b3581816f --- /dev/null +++ b/sapl/parlamentares/migrations/0021_clear_thumbnails_cache.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + + +from django.db import migrations +from sapl.utils import clear_thumbnails_cache + + +def clear_thumbnails_cache_migrate(apps, schema_editor): + Parlamentar = apps.get_model("parlamentares", "Parlamentar") + parlamentares = Parlamentar.objects.all() + clear_thumbnails_cache(parlamentares, 'fotografia') + + +class Migration(migrations.Migration): + + dependencies = [ + ('parlamentares', '0020_fix_inicio_mandato'), + ] + + operations = [ + migrations.RunPython(clear_thumbnails_cache_migrate), + ] diff --git a/sapl/utils.py b/sapl/utils.py index 3a3cb3fad..488b2d8d6 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -22,6 +22,7 @@ from django_filters.filterset import STRICTNESS from easy_thumbnails import source_generators from floppyforms import ClearableFileInput from reversion.admin import VersionAdmin +from unipath.path import Path import django_filters import magic @@ -36,6 +37,23 @@ def pil_image(source, exif_orientation=False, **options): return source_generators.pil_image(source, exif_orientation, **options) +def clear_thumbnails_cache(queryset, field): + + for r in queryset: + assert hasattr(r, field), _( + 'Objeto da listagem não possui o campo informado') + + if not getattr(r, field): + continue + + path = Path(getattr(r, field).path) + cache_files = path.parent.walk() + + for cf in cache_files: + if cf != path: + cf.remove() + + def normalize(txt): return unicodedata_normalize( 'NFKD', txt).encode('ASCII', 'ignore').decode('ASCII') From 46b9a5adf0cef6299681006720afc45e605c53ae Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Wed, 28 Feb 2018 13:20:41 -0300 Subject: [PATCH 11/23] add clear thumbnails cache --- .../legacy/migracao_documentos_via_request.py | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 sapl/legacy/migracao_documentos_via_request.py diff --git a/sapl/legacy/migracao_documentos_via_request.py b/sapl/legacy/migracao_documentos_via_request.py new file mode 100644 index 000000000..c49958b60 --- /dev/null +++ b/sapl/legacy/migracao_documentos_via_request.py @@ -0,0 +1,212 @@ +import mimetypes +import os +import re + +from django.core.files.base import File +from django.core.files.temp import NamedTemporaryFile +import magic +import urllib3 + +from sapl.base.models import CasaLegislativa +from sapl.legacy.migration import warn +from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa, + Proposicao) +from sapl.norma.models import NormaJuridica +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 ################################################### +EXTENSOES = { + 'application/msword': '.doc', + 'application/pdf': '.pdf', + 'application/vnd.oasis.opendocument.text': '.odt', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx', # noqa + 'application/xml': '.xml', + 'text/xml': '.xml', + 'application/zip': '.zip', + 'image/jpeg': '.jpeg', + 'image/png': '.png', + 'text/html': '.html', + 'image/gif': '.gif', + 'text/rtf': '.rtf', + 'text/x-python': '.py', + 'text/plain': '.ksh', + 'text/plain': '.c', + 'text/plain': '.h', + 'text/plain': '.txt', + 'text/plain': '.bat', + 'text/plain': '.pl', + 'text/plain': '.asc', + 'text/plain': '.text', + 'text/plain': '.pot', + 'text/plain': '.brf', + 'text/plain': '.srt', + 'image/tiff': '.tiff', + + # sem extensao + 'application/octet-stream': '', # binário + 'inode/x-empty': '', # vazio +} + +DOCS = { + CasaLegislativa: [( + 'logotipo', + 'props_sapl/logo_casa.gif', + 'casa/logotipo/logo_casa.gif')], + Parlamentar: [( + 'fotografia', + 'parlamentar/fotos/{}_foto_parlamentar', + 'public/parlamentar/{0}/{0}_foto_parlamentar{1}')], + MateriaLegislativa: [( + 'texto_original', + 'materia/{}_texto_integral', + 'public/materialegislativa/{2}/{0}/{0}_texto_integral{1}')], + DocumentoAcessorio: [( + 'arquivo', + 'materia/{}', + 'public/documentoacessorio/{2}/{0}/{0}{1}')], + NormaJuridica: [( + 'texto_integral', + 'norma_juridica/{}_texto_integral', + 'public/normajuridica/{2}/{0}/{0}_texto_integral{1}')], + SessaoPlenaria: [ + ('upload_ata', + 'ata_sessao/{}_ata_sessao', + 'public/sessaoplenaria/{0}/ata/{0}_ata_sessao{1}'), + ('upload_anexo', + 'anexo_sessao/{}_texto_anexado', + 'public/sessaoplenaria/{0}/anexo/{0}_texto_anexado{1}') + ], + Proposicao: [( + 'texto_original', + 'proposicao/{}', + 'private/proposicao/{0}/{0}{1}')], + DocumentoAdministrativo: [( + 'texto_integral', + 'administrativo/{}_texto_integral', + 'private/documentoadministrativo/{0}/{0}_texto_integral{1}') + ], + DocumentoAcessorioAdministrativo: [( + 'arquivo', + 'administrativo/{}', + 'private/documentoacessorioadministrativo/{0}/' + '{0}_acessorio_administrativo{1}') + ], +} + +DOCS = {model: [(campo, + os.path.join('sapl_documentos', origem), + os.path.join('sapl', destino)) + for campo, origem, destino 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 + for c in (origem, destino)] + os.makedirs(os.path.dirname(destino), exist_ok=True) + os.rename(origem, destino) + + +def get_casa_legislativa(): + casa = CasaLegislativa.objects.first() + if not casa: + casa = CasaLegislativa.objects.create(**{k: 'PREENCHER...' for k in [ + 'codigo', 'nome', 'sigla', 'endereco', 'cep', 'municipio', 'uf', + ]}) + return casa + + +def migrar_docs_logo(): + print('#### Migrando logotipo da casa ####') + [(_, origem, destino)] = DOCS[CasaLegislativa] + props_sapl = os.path.dirname(origem) + + # a pasta props_sapl deve conter apenas o origem e metadatas! + # Edit: Aparentemente há diretório que contém properties ao invés de + # metadata. O assert foi modificado para essa situação. + sobrando = set(os.listdir(em_media(props_sapl))) - { + 'logo_casa.gif', '.metadata', 'logo_casa.gif.metadata', + '.properties', 'logo_casa.gif.properties', '.objects'} + + if sobrando: + warn('Os seguintes arquivos da pasta props_sapl foram ignorados: ' + + ', '.join(sobrando)) + + mover_documento(origem, destino) + casa = get_casa_legislativa() + casa.logotipo = destino + casa.save() + + +def get_extensao(mime): + try: + return EXTENSOES[mime] + except KeyError as e: + raise Exception('\n'.join([ + 'mimetype:', + mime, + ' Algumas possibilidades são:', ] + + [" '{}': '{}',".format(mime, ext) + for ext in mimetypes.guess_all_extensions(mime)] + + ['Atualize o código do dicionário EXTENSOES!'] + )) from e + + +http = urllib3.PoolManager() + + +def migrar_docs_por_ids(model): + for campo, base_origem, base_destino in DOCS[model]: + print('#### Migrando {} de {} ####'.format(campo, model.__name__)) + + registros = model.objects.all() + + for item in registros: + + campo_file = getattr(item, campo) + campo_file.delete() + + url = ('http://187.6.249.156:8480/sapl/%s' + ) % base_origem.format(item.pk) + + request = http.request('GET', url) + + try: + data = request.data.decode('utf-8') + except: + temp = NamedTemporaryFile(delete=True) + temp.write(request.data) + temp.flush() + + ct = request.getheaders()['Content-Type'] + print (ct, campo, item) + + name_file = '%s%s' % (campo, get_extensao(ct)) + + campo_file.save(name_file, File(temp), save=True) + + +def migrar_documentos(): + for model in [ + Parlamentar, + MateriaLegislativa, + DocumentoAcessorio, + NormaJuridica, + DocumentoAdministrativo, + DocumentoAcessorioAdministrativo, + ]: + migrar_docs_por_ids(model) + + +# %run 'sapl/legacy/migracao_documentos_via_request.py' +if __name__ == '__main__': + migrar_documentos() From 743774fe53d0061f258a3c5c0c41441902cde8b4 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Wed, 28 Feb 2018 13:53:47 -0300 Subject: [PATCH 12/23] Revert "add clear thumbnails cache" This reverts commit 46b9a5adf0cef6299681006720afc45e605c53ae. --- .../legacy/migracao_documentos_via_request.py | 212 ------------------ 1 file changed, 212 deletions(-) delete mode 100644 sapl/legacy/migracao_documentos_via_request.py diff --git a/sapl/legacy/migracao_documentos_via_request.py b/sapl/legacy/migracao_documentos_via_request.py deleted file mode 100644 index c49958b60..000000000 --- a/sapl/legacy/migracao_documentos_via_request.py +++ /dev/null @@ -1,212 +0,0 @@ -import mimetypes -import os -import re - -from django.core.files.base import File -from django.core.files.temp import NamedTemporaryFile -import magic -import urllib3 - -from sapl.base.models import CasaLegislativa -from sapl.legacy.migration import warn -from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa, - Proposicao) -from sapl.norma.models import NormaJuridica -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 ################################################### -EXTENSOES = { - 'application/msword': '.doc', - 'application/pdf': '.pdf', - 'application/vnd.oasis.opendocument.text': '.odt', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx', # noqa - 'application/xml': '.xml', - 'text/xml': '.xml', - 'application/zip': '.zip', - 'image/jpeg': '.jpeg', - 'image/png': '.png', - 'text/html': '.html', - 'image/gif': '.gif', - 'text/rtf': '.rtf', - 'text/x-python': '.py', - 'text/plain': '.ksh', - 'text/plain': '.c', - 'text/plain': '.h', - 'text/plain': '.txt', - 'text/plain': '.bat', - 'text/plain': '.pl', - 'text/plain': '.asc', - 'text/plain': '.text', - 'text/plain': '.pot', - 'text/plain': '.brf', - 'text/plain': '.srt', - 'image/tiff': '.tiff', - - # sem extensao - 'application/octet-stream': '', # binário - 'inode/x-empty': '', # vazio -} - -DOCS = { - CasaLegislativa: [( - 'logotipo', - 'props_sapl/logo_casa.gif', - 'casa/logotipo/logo_casa.gif')], - Parlamentar: [( - 'fotografia', - 'parlamentar/fotos/{}_foto_parlamentar', - 'public/parlamentar/{0}/{0}_foto_parlamentar{1}')], - MateriaLegislativa: [( - 'texto_original', - 'materia/{}_texto_integral', - 'public/materialegislativa/{2}/{0}/{0}_texto_integral{1}')], - DocumentoAcessorio: [( - 'arquivo', - 'materia/{}', - 'public/documentoacessorio/{2}/{0}/{0}{1}')], - NormaJuridica: [( - 'texto_integral', - 'norma_juridica/{}_texto_integral', - 'public/normajuridica/{2}/{0}/{0}_texto_integral{1}')], - SessaoPlenaria: [ - ('upload_ata', - 'ata_sessao/{}_ata_sessao', - 'public/sessaoplenaria/{0}/ata/{0}_ata_sessao{1}'), - ('upload_anexo', - 'anexo_sessao/{}_texto_anexado', - 'public/sessaoplenaria/{0}/anexo/{0}_texto_anexado{1}') - ], - Proposicao: [( - 'texto_original', - 'proposicao/{}', - 'private/proposicao/{0}/{0}{1}')], - DocumentoAdministrativo: [( - 'texto_integral', - 'administrativo/{}_texto_integral', - 'private/documentoadministrativo/{0}/{0}_texto_integral{1}') - ], - DocumentoAcessorioAdministrativo: [( - 'arquivo', - 'administrativo/{}', - 'private/documentoacessorioadministrativo/{0}/' - '{0}_acessorio_administrativo{1}') - ], -} - -DOCS = {model: [(campo, - os.path.join('sapl_documentos', origem), - os.path.join('sapl', destino)) - for campo, origem, destino 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 - for c in (origem, destino)] - os.makedirs(os.path.dirname(destino), exist_ok=True) - os.rename(origem, destino) - - -def get_casa_legislativa(): - casa = CasaLegislativa.objects.first() - if not casa: - casa = CasaLegislativa.objects.create(**{k: 'PREENCHER...' for k in [ - 'codigo', 'nome', 'sigla', 'endereco', 'cep', 'municipio', 'uf', - ]}) - return casa - - -def migrar_docs_logo(): - print('#### Migrando logotipo da casa ####') - [(_, origem, destino)] = DOCS[CasaLegislativa] - props_sapl = os.path.dirname(origem) - - # a pasta props_sapl deve conter apenas o origem e metadatas! - # Edit: Aparentemente há diretório que contém properties ao invés de - # metadata. O assert foi modificado para essa situação. - sobrando = set(os.listdir(em_media(props_sapl))) - { - 'logo_casa.gif', '.metadata', 'logo_casa.gif.metadata', - '.properties', 'logo_casa.gif.properties', '.objects'} - - if sobrando: - warn('Os seguintes arquivos da pasta props_sapl foram ignorados: ' + - ', '.join(sobrando)) - - mover_documento(origem, destino) - casa = get_casa_legislativa() - casa.logotipo = destino - casa.save() - - -def get_extensao(mime): - try: - return EXTENSOES[mime] - except KeyError as e: - raise Exception('\n'.join([ - 'mimetype:', - mime, - ' Algumas possibilidades são:', ] + - [" '{}': '{}',".format(mime, ext) - for ext in mimetypes.guess_all_extensions(mime)] + - ['Atualize o código do dicionário EXTENSOES!'] - )) from e - - -http = urllib3.PoolManager() - - -def migrar_docs_por_ids(model): - for campo, base_origem, base_destino in DOCS[model]: - print('#### Migrando {} de {} ####'.format(campo, model.__name__)) - - registros = model.objects.all() - - for item in registros: - - campo_file = getattr(item, campo) - campo_file.delete() - - url = ('http://187.6.249.156:8480/sapl/%s' - ) % base_origem.format(item.pk) - - request = http.request('GET', url) - - try: - data = request.data.decode('utf-8') - except: - temp = NamedTemporaryFile(delete=True) - temp.write(request.data) - temp.flush() - - ct = request.getheaders()['Content-Type'] - print (ct, campo, item) - - name_file = '%s%s' % (campo, get_extensao(ct)) - - campo_file.save(name_file, File(temp), save=True) - - -def migrar_documentos(): - for model in [ - Parlamentar, - MateriaLegislativa, - DocumentoAcessorio, - NormaJuridica, - DocumentoAdministrativo, - DocumentoAcessorioAdministrativo, - ]: - migrar_docs_por_ids(model) - - -# %run 'sapl/legacy/migracao_documentos_via_request.py' -if __name__ == '__main__': - migrar_documentos() From a568f5d0eee119765126321ffc475f4ea386adde Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 28 Feb 2018 13:00:56 -0300 Subject: [PATCH 13/23] =?UTF-8?q?Adiciona=20antiword=20para=20indexa=C3=A7?= =?UTF-8?q?=C3=A3o=20de=20docs=20do=20Word?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- docs/instalacao31.rst | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index c192ccab4..693230025 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM alpine:3.5 ENV BUILD_PACKAGES postgresql-dev graphviz-dev graphviz build-base git pkgconfig \ python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev nodejs py3-lxml \ -py3-magic postgresql-client poppler-utils vim +py3-magic postgresql-client poppler-utils antiword vim RUN apk --update add fontconfig ttf-dejavu && fc-cache -fv diff --git a/docs/instalacao31.rst b/docs/instalacao31.rst index f12b92d9c..12828b199 100644 --- a/docs/instalacao31.rst +++ b/docs/instalacao31.rst @@ -28,7 +28,7 @@ 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 default-jre + python3-pip curl poppler-utils antiword default-jre sudo -i curl -sL https://deb.nodesource.com/setup_6.x | bash - @@ -187,9 +187,9 @@ Copie a chave que aparecerá, edite o arquivo .env e altere o valor do parâmetr * Subir o servidor do django:: ./manage.py runserver 0.0.0.0:8001 - + * Compilar os arquivos de estilização:: - + ./manage.py compilescss ./manage.py collectstatic @@ -211,7 +211,7 @@ Instruções para criação do super usuário e de usuários de testes * Os perfis fixos não aceitam customização via admin, porém outros grupos podem ser criados. O SAPL não interferirá no conjunto de permissões definidas em grupos customizados e se comportará diante de usuários segundo seus grupos e suas permissões. * Para criar os usuários de teste, deve-se seguir os seguintes passos:: - + ./manage.py shell_plus from sapl.rules.apps import cria_usuarios_padrao cria_usuarios_padrao() From bed5e581e4f40b6ca84c25b410b5f2e2d0d66e4f Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 28 Feb 2018 14:06:23 -0300 Subject: [PATCH 14/23] Release: 3.1.53 --- 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 3afd6dc62..6f8963a04 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.52 + image: interlegis/sapl:3.1.53 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 1feba9cef..1008529f5 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.52', + version='3.1.53', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 94f58e7b09a4a0c846962ba4e42efaa75f6fd15f Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 27 Feb 2018 17:16:48 -0300 Subject: [PATCH 15/23] Adiciona nota ao migrar doc adm sem protocolo --- sapl/legacy/migration.py | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/sapl/legacy/migration.py b/sapl/legacy/migration.py index abd232d47..636bc7e18 100644 --- a/sapl/legacy/migration.py +++ b/sapl/legacy/migration.py @@ -785,26 +785,51 @@ def adjust_acompanhamentomateria(new, old): new.confirmado = True +NOTA_DOCADM = ''' +## NOTA DE MIGRAÇÃO DE DADOS DO SAPL 2.5 ## +O número de protocolo original deste documento era [{num_protocolo}], ano {ano_original}. +'''.strip() # noqa + + def adjust_documentoadministrativo(new, old): if old.num_protocolo: + nota = None + ano_original = new.ano protocolo = Protocolo.objects.filter( numero=old.num_protocolo, ano=new.ano) if not protocolo: # tentamos encontrar o protocolo no ano seguinte - protocolo = Protocolo.objects.filter( - numero=old.num_protocolo, ano=new.ano + 1) + ano_novo = ano_original + 1 + protocolo = Protocolo.objects.filter(numero=old.num_protocolo, + ano=ano_novo) if protocolo: - print('PROTOCOLO ENCONTRADO APENAS PARA O ANO SEGUINTE!!!!! ' - 'DocumentoAdministrativo: {}, numero_protocolo: {}, ' - 'ano doc adm: {}'.format( - old.cod_documento, old.num_protocolo, new.ano)) + nota = NOTA_DOCADM + ''' +O protocolo vinculado é o de mesmo número, porém do ano seguinte ({ano_novo}), +pois não existe protocolo no sistema com este número no ano {ano_original}. +''' + nota = nota.strip().format(num_protocolo=old.num_protocolo, + ano_original=ano_original, + ano_novo=ano_novo) + warn('PROTOCOLO ENCONTRADO APENAS PARA O ANO SEGUINTE!!!!! ' + 'DocumentoAdministrativo: {}, numero_protocolo: {}, ' + 'ano doc adm: {}'.format( + old.cod_documento, old.num_protocolo, ano_original)) else: + nota = NOTA_DOCADM + ''' +Não existe no sistema nenhum protocolo com estes dados +e portanto nenhum protocolo foi vinculado a este documento.''' + nota = nota.format( + num_protocolo=old.num_protocolo, + ano_original=ano_original) warn('Protocolo {} faltando ' - '(referenciado no documento administrativo {}'.format( + '(referenciado no documento administrativo {})'.format( old.num_protocolo, old.cod_documento)) if protocolo: assert len(protocolo) == 1, 'mais de um protocolo encontrado' [new.protocolo] = protocolo + # adiciona nota ao final da observação + if nota: + new.observacao += ('\n\n' if new.observacao else '') + nota def adjust_mandato(new, old): From e9f7884f68a0b1e3e5c06df4a0ffb362b21d74c6 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 27 Feb 2018 17:35:06 -0300 Subject: [PATCH 16/23] =?UTF-8?q?Completa=20migra=C3=A7=C3=A3o=20de=20senh?= =?UTF-8?q?as=20do=20zope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/hashers.py | 2 ++ sapl/legacy/migracao_usuarios.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/sapl/hashers.py b/sapl/hashers.py index a514f8f19..e80642def 100644 --- a/sapl/hashers.py +++ b/sapl/hashers.py @@ -44,6 +44,8 @@ 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): data = encoded[len(ZOPE_SHA1_PREFIX):] salt = get_salt_from_zope_sha1(data) diff --git a/sapl/legacy/migracao_usuarios.py b/sapl/legacy/migracao_usuarios.py index 591f08b20..39d6df4e9 100644 --- a/sapl/legacy/migracao_usuarios.py +++ b/sapl/legacy/migracao_usuarios.py @@ -1,6 +1,7 @@ import yaml from django.contrib.auth.models import Group, User +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) @@ -83,6 +84,7 @@ def migra_usuarios(): for nome, senha, perfis in usuarios: usuario = User.objects.get_or_create(username=nome)[0] + usuario.password = zope_encoded_password_to_django(senha) for perfil in perfis: if perfil in ADMINISTRADORES: # Manager From 5394ac32c1f5d41a6c94fd24cac7d9b676a94646 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 28 Feb 2018 14:29:09 -0300 Subject: [PATCH 17/23] =?UTF-8?q?Renomeia=20m=C3=B3dulo=20e=20fun=C3=A7?= =?UTF-8?q?=C3=A3o=20de=20migra=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/management/commands/migracao_25_31.py | 5 +++-- sapl/legacy/{migration.py => migracao.py} | 6 +++--- sapl/legacy/migracao_documentos.py | 2 +- sapl/legacy/scripts/scrap_original_forms.py | 2 +- sapl/legacy/scripts/study.py | 2 +- sapl/legacy/scripts/utils.py | 2 +- sapl/legacy/test_migration.py | 2 +- sapl/legacy/test_renames.py | 2 +- 8 files changed, 12 insertions(+), 11 deletions(-) rename sapl/legacy/{migration.py => migracao.py} (99%) diff --git a/sapl/legacy/management/commands/migracao_25_31.py b/sapl/legacy/management/commands/migracao_25_31.py index 9e7f0a32a..1298feeb3 100644 --- a/sapl/legacy/management/commands/migracao_25_31.py +++ b/sapl/legacy/management/commands/migracao_25_31.py @@ -1,6 +1,7 @@ from django.core import management from django.core.management.base import BaseCommand -from sapl.legacy import migration + +from sapl.legacy.migracao import migrar class Command(BaseCommand): @@ -18,4 +19,4 @@ class Command(BaseCommand): def handle(self, *args, **options): management.call_command('migrate') - migration.migrate(interativo=not options['force']) + migrar(interativo=not options['force']) diff --git a/sapl/legacy/migration.py b/sapl/legacy/migracao.py similarity index 99% rename from sapl/legacy/migration.py rename to sapl/legacy/migracao.py index 636bc7e18..fb2cbfa8c 100644 --- a/sapl/legacy/migration.py +++ b/sapl/legacy/migracao.py @@ -647,7 +647,7 @@ class DataMigrator: setattr(new, field.name, value) - def migrate(self, obj=appconfs, interativo=True): + def migrar(self, obj=appconfs, interativo=True): # warning: model/app migration order is of utmost importance uniformiza_banco() @@ -774,9 +774,9 @@ class DataMigrator: exec_legado(sql_delete_legado) -def migrate(obj=appconfs, interativo=True): +def migrar(obj=appconfs, interativo=True): dm = DataMigrator() - dm.migrate(obj, interativo) + dm.migrar(obj, interativo) # MIGRATION_ADJUSTMENTS ##################################################### diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index 1f5ca2cd0..9de759348 100644 --- a/sapl/legacy/migracao_documentos.py +++ b/sapl/legacy/migracao_documentos.py @@ -6,7 +6,7 @@ from glob import glob import yaml from sapl.base.models import CasaLegislativa -from sapl.legacy.migration import exec_legado, warn +from sapl.legacy.migracao import exec_legado, warn from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa, Proposicao) from sapl.norma.models import NormaJuridica diff --git a/sapl/legacy/scripts/scrap_original_forms.py b/sapl/legacy/scripts/scrap_original_forms.py index fb6927cdc..a3325b32e 100644 --- a/sapl/legacy/scripts/scrap_original_forms.py +++ b/sapl/legacy/scripts/scrap_original_forms.py @@ -10,7 +10,7 @@ from bs4.element import NavigableString, Tag from django.apps.config import AppConfig from sapl.crispy_layout_mixin import heads_and_tails -from sapl.legacy.migration import appconfs, get_renames +from sapl.legacy.migracao import appconfs, get_renames from sapl.legacy.scripts.utils import getsourcelines from sapl.utils import listify diff --git a/sapl/legacy/scripts/study.py b/sapl/legacy/scripts/study.py index a28428c7d..1078af38e 100644 --- a/sapl/legacy/scripts/study.py +++ b/sapl/legacy/scripts/study.py @@ -1,5 +1,5 @@ from django.apps import apps -from sapl.legacy.migration import legacy_app +from sapl.legacy.migracao import legacy_app for model in apps.get_app_config('legacy').get_models(): if 'ind_excluido' in [f.name for f in model._meta.fields]: diff --git a/sapl/legacy/scripts/utils.py b/sapl/legacy/scripts/utils.py index 21f74ce52..c426f1b3b 100644 --- a/sapl/legacy/scripts/utils.py +++ b/sapl/legacy/scripts/utils.py @@ -1,7 +1,7 @@ import inspect from sapl.base.models import Autor -from sapl.legacy.migration import appconfs +from sapl.legacy.migracao import appconfs def getsourcelines(model): diff --git a/sapl/legacy/test_migration.py b/sapl/legacy/test_migration.py index efaa2e6d6..53034987d 100644 --- a/sapl/legacy/test_migration.py +++ b/sapl/legacy/test_migration.py @@ -1,6 +1,6 @@ from random import shuffle -from .migration import (_formatar_lista_para_sql, get_autorias_sem_repeticoes, +from .migracao import (_formatar_lista_para_sql, get_autorias_sem_repeticoes, get_reapontamento_de_autores_repetidos) diff --git a/sapl/legacy/test_renames.py b/sapl/legacy/test_renames.py index 27987aeeb..f275efa2f 100644 --- a/sapl/legacy/test_renames.py +++ b/sapl/legacy/test_renames.py @@ -3,7 +3,7 @@ import sapl.materia import sapl.norma import sapl.sessao -from .migration import appconfs, get_renames, legacy_app +from .migracao import appconfs, get_renames, legacy_app RENAMING_IGNORED_MODELS = [ sapl.comissoes.models.Composicao, From d4f998411fc0350b7e793f318284a0f0d0d34400 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 28 Feb 2018 15:43:33 -0300 Subject: [PATCH 18/23] =?UTF-8?q?Propaga=20exclus=C3=B5es=20na=20pr=C3=A9-?= =?UTF-8?q?migra=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #1721 --- sapl/legacy/migracao.py | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index fb2cbfa8c..b228acbc1 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -389,10 +389,57 @@ def checa_registros_votacao_ambiguos_e_remove_nao_usados(): where cod_votacao in {}''', nao_usados) +PROPAGACOES_DE_EXCLUSAO = [ + # sessao_legislativa + ('composicao_mesa', 'sessao_legislativa', 'cod_sessao_leg'), + + # parlamentar + ('dependente', 'parlamentar', 'cod_parlamentar'), + ('filiacao', 'parlamentar', 'cod_parlamentar'), + ('mandato', 'parlamentar', 'cod_parlamentar'), + + # comissao + ('composicao_comissao', 'comissao', 'cod_comissao'), + + # sessao + ('ordem_dia', 'sessao_plenaria', 'cod_sessao_plen'), + ('expediente_materia', 'sessao_plenaria', 'cod_sessao_plen'), + ('expediente_sessao_plenaria', 'sessao_plenaria', 'cod_sessao_plen'), + ('registro_votacao_parlamentar', 'registro_votacao', 'cod_votacao'), + # as consultas no código do sapl 2.5 + # votacao_ordem_dia_obter_zsql e votacao_expediente_materia_obter_zsql + # indicam que os registros de votação de matérias excluídas não são + # exibidos... + ('registro_votacao', 'materia_legislativa', 'cod_materia'), + # as exclusões de registro_votacao sem referência + # nem a ordem_dia nem a expediente_materia são feitas num método à parte + + # materia + ('tramitacao', 'materia_legislativa', 'cod_materia'), + ('autoria', 'materia_legislativa', 'cod_materia'), + ('anexada', 'materia_legislativa', 'cod_materia_principal'), + ('anexada', 'materia_legislativa', 'cod_materia_anexada'), + ('documento_acessorio', 'materia_legislativa', 'cod_materia'), + + # documento administrativo + ('tramitacao_administrativo', 'documento_administrativo', 'cod_documento'), +] + + +def propaga_exclusoes(): + for tabela_filha, tabela_pai, fk in PROPAGACOES_DE_EXCLUSAO: + [pk_pai] = get_pk_legado(tabela_pai) + exec_legado(''' + update {} set ind_excluido = 1 where {} not in ( + select {} from {} where ind_excluido != 1) + '''.format(tabela_filha, fk, pk_pai, tabela_pai)) + + def uniformiza_banco(): exec_legado('SET SESSION sql_mode = "";') # desliga checagens do mysql checa_registros_votacao_ambiguos_e_remove_nao_usados() + propaga_exclusoes() garante_coluna_no_legado('proposicao', 'num_proposicao int(11) NULL') From 07096f8668537a4de0b9bd2939e9d320c10c0a98 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 28 Feb 2018 16:53:26 -0300 Subject: [PATCH 19/23] =?UTF-8?q?HOT-FIX:=20conserta=20bug=20em=20cria?= =?UTF-8?q?=C3=A7=C3=A3o=20de=20proposica=C3=A7=C3=A3o=20sem=20texto=5Fori?= =?UTF-8?q?ginal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/materia/forms.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 038a24d82..4b06957db 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1261,11 +1261,10 @@ class ProposicaoForm(forms.ModelForm): numero__max + 1) if numero__max else 1 inst.save() - if cd['receber_recibo'] == 'True': + if cd['receber_recibo'] == 'True' or not inst.texto_original: inst.hash_code = '' else: _hash = gerar_hash_arquivo(inst.texto_original.path, str(inst.pk)) - inst.hash_code = _hash inst.save() From 7a71fb40ea21fc8f1e4a54697a28dd286198bf94 Mon Sep 17 00:00:00 2001 From: "tapumar@gmail.com" Date: Wed, 28 Feb 2018 17:32:22 -0300 Subject: [PATCH 20/23] =?UTF-8?q?HOT-FIX:=20Gerar=20hash=20na=20edi=C3=A7?= =?UTF-8?q?=C3=A3o=20da=20proposi=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/materia/forms.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 4b06957db..011181ec7 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1,6 +1,5 @@ import os - import django_filters import sapl from crispy_forms.bootstrap import Alert, FormActions, InlineRadios @@ -23,7 +22,7 @@ from django.utils.encoding import force_text from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ -from sapl.base.models import Autor, TipoAutor +from sapl.base.models import Autor, TipoAutor, AppConfig from sapl.comissoes.models import Comissao from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC, STATUS_TA_PRIVATE) @@ -1235,6 +1234,7 @@ class ProposicaoForm(forms.ModelForm): def save(self, commit=True): cd = self.cleaned_data inst = self.instance + receber_recibo = AppConfig.objects.last().receber_recibo_proposicao if inst.pk: if 'tipo_texto' in cd: @@ -1249,6 +1249,13 @@ class ProposicaoForm(forms.ModelForm): not cd['texto_original'] and \ inst.texto_original: inst.texto_original.delete() + inst.save() + import ipdb; ipdb.set_trace() + if receber_recibo == True or not inst.texto_original: + inst.hash_code = '' + else: + _hash = gerar_hash_arquivo(inst.texto_original.path, str(inst.pk)) + inst.hash_code = _hash return super().save(commit) @@ -1261,7 +1268,7 @@ class ProposicaoForm(forms.ModelForm): numero__max + 1) if numero__max else 1 inst.save() - if cd['receber_recibo'] == 'True' or not inst.texto_original: + if receber_recibo == True or not inst.texto_original: inst.hash_code = '' else: _hash = gerar_hash_arquivo(inst.texto_original.path, str(inst.pk)) From fd932c406891c176e4dd938d916b7a0e6eaf6f34 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 28 Feb 2018 19:13:30 -0300 Subject: [PATCH 21/23] Release 3.1.54 --- 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 6f8963a04..11e5caedf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.53 + image: interlegis/sapl:3.1.54 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 1008529f5..c98fb482e 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.53', + version='3.1.54', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 25c679cba94e166002e649c17c970571f6f15db8 Mon Sep 17 00:00:00 2001 From: "tapumar@gmail.com" Date: Thu, 1 Mar 2018 10:24:31 -0300 Subject: [PATCH 22/23] HOT-FIX: tirar ipdb do materia/form --- sapl/materia/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 011181ec7..5c4032635 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1250,7 +1250,7 @@ class ProposicaoForm(forms.ModelForm): inst.texto_original: inst.texto_original.delete() inst.save() - import ipdb; ipdb.set_trace() + if receber_recibo == True or not inst.texto_original: inst.hash_code = '' else: From 379baafb9c9d58bb93a80f908203361937ed5b7e Mon Sep 17 00:00:00 2001 From: "tapumar@gmail.com" Date: Thu, 1 Mar 2018 11:22:19 -0300 Subject: [PATCH 23/23] HOT-HOT-FIX: gerar hash_code para texto articulado --- sapl/materia/forms.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 5c4032635..5ee44e1c2 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1208,6 +1208,20 @@ class ProposicaoForm(forms.ModelForm): "Arquivo muito grande. ( > {0}MB )".format(max_size)) return texto_original + def gerar_hash(self, inst, receber_recibo): + + inst.save() + if receber_recibo == True: + inst.hash_code = '' + else: + if inst.texto_original: + inst.hash_code = gerar_hash_arquivo( + inst.texto_original.path, str(inst.pk)) + elif inst.texto_articulado.exists(): + ta = inst.texto_articulado.first() + # FIXME hash para textos articulados + inst.hash_code = 'P' + ta.hash() + '/' + str(inst.pk) + def clean(self): super(ProposicaoForm, self).clean() @@ -1249,13 +1263,8 @@ class ProposicaoForm(forms.ModelForm): not cd['texto_original'] and \ inst.texto_original: inst.texto_original.delete() - inst.save() - if receber_recibo == True or not inst.texto_original: - inst.hash_code = '' - else: - _hash = gerar_hash_arquivo(inst.texto_original.path, str(inst.pk)) - inst.hash_code = _hash + self.gerar_hash(inst, receber_recibo) return super().save(commit) @@ -1267,12 +1276,7 @@ class ProposicaoForm(forms.ModelForm): inst.numero_proposicao = ( numero__max + 1) if numero__max else 1 - inst.save() - if receber_recibo == True or not inst.texto_original: - inst.hash_code = '' - else: - _hash = gerar_hash_arquivo(inst.texto_original.path, str(inst.pk)) - inst.hash_code = _hash + self.gerar_hash(inst, receber_recibo) inst.save()