From 2ad74d7e501ae88d59ebd56a87597028d885a029 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 23 Feb 2018 15:10:21 -0300 Subject: [PATCH 001/121] =?UTF-8?q?Adiciona=20valida=C3=A7=C3=A3o=20de=20R?= =?UTF-8?q?egistroVotacao?= 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 002/121] =?UTF-8?q?Revisa=20migra=C3=A7=C3=A3o=20de=20Regi?= =?UTF-8?q?stroVotacao?= 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 003/121] =?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 004/121] 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 005/121] =?UTF-8?q?Checa=20registros=20de=20vota=C3=A7?= =?UTF-8?q?=C3=A3o=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 c908df84910b19c691e38f9c3219e18d5fdadc03 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Tue, 27 Feb 2018 14:45:56 -0300 Subject: [PATCH 006/121] 1718 remover acesso dos models de tipos (#1719) * Fixes #1718 --- sapl/materia/admin.py | 24 ++++++++++++++++--- sapl/templates/materia/proposicao_detail.html | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/sapl/materia/admin.py b/sapl/materia/admin.py index 8da7408b1..65b754817 100644 --- a/sapl/materia/admin.py +++ b/sapl/materia/admin.py @@ -1,5 +1,11 @@ from django.contrib import admin -from sapl.materia.models import Proposicao +from sapl.materia.models import Proposicao, TipoMateriaLegislativa +from sapl.base.models import TipoAutor +from sapl.comissoes.models import TipoComissao +from sapl.parlamentares.models import TipoAfastamento, SituacaoMilitar, TipoDependente +from sapl.norma.models import TipoNormaJuridica, TipoVinculoNormaJuridica +from sapl.sessao.models import TipoSessaoPlenaria, TipoExpediente, TipoResultadoVotacao +from sapl.protocoloadm.models import TipoDocumentoAdministrativo from sapl.settings import DEBUG from sapl.utils import register_all_models_in_admin @@ -8,8 +14,14 @@ register_all_models_in_admin(__name__) if not DEBUG: admin.site.unregister(Proposicao) + admin.site.unregister(TipoAutor) + admin.site.unregister(TipoComissao) + admin.site.unregister(TipoAfastamento) + admin.site.unregister(SituacaoMilitar) + admin.site.unregister(TipoDependente) - class ProposicaoAdmin(admin.ModelAdmin): + + class RestricaoAdmin(admin.ModelAdmin): def has_add_permission(self, request, obj=None): return False @@ -20,4 +32,10 @@ if not DEBUG: def has_delete_permission(self, request, obj=None): return False - admin.site.register(Proposicao, ProposicaoAdmin) + + admin.site.register(Proposicao, RestricaoAdmin) + admin.site.register(TipoAutor, RestricaoAdmin) + admin.site.register(TipoComissao, RestricaoAdmin) + admin.site.register(TipoAfastamento, RestricaoAdmin) + admin.site.register(SituacaoMilitar, RestricaoAdmin) + admin.site.register(TipoDependente, RestricaoAdmin) diff --git a/sapl/templates/materia/proposicao_detail.html b/sapl/templates/materia/proposicao_detail.html index 23500e739..53d6e8620 100644 --- a/sapl/templates/materia/proposicao_detail.html +++ b/sapl/templates/materia/proposicao_detail.html @@ -136,7 +136,7 @@ {% endif %} - + {% if not AppConfig.receber_recibo_proposicao %} {% if object.hash_code %} From 505af2f13ef012ae28c1aff0610a78071ed08b31 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Tue, 27 Feb 2018 14:59:36 -0300 Subject: [PATCH 007/121] =?UTF-8?q?add=20menu=20de=20config=20de=20TAs=20n?= =?UTF-8?q?as=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 008/121] =?UTF-8?q?refatora=20gera=C3=A7=C3=A3o=20de=20bas?= =?UTF-8?q?e=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 009/121] 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 010/121] 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 011/121] =?UTF-8?q?add=20limp=20de=20varia=C3=A7=C3=B5es?= =?UTF-8?q?=20de=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 012/121] 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 013/121] 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 014/121] =?UTF-8?q?Adiciona=20antiword=20para=20indexa?= =?UTF-8?q?=C3=A7=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 015/121] 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 016/121] 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 017/121] =?UTF-8?q?Completa=20migra=C3=A7=C3=A3o=20de=20se?= =?UTF-8?q?nhas=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 018/121] =?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 019/121] =?UTF-8?q?Propaga=20exclus=C3=B5es=20na=20pr?= =?UTF-8?q?=C3=A9-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 020/121] =?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 021/121] =?UTF-8?q?HOT-FIX:=20Gerar=20hash=20na=20edi?= =?UTF-8?q?=C3=A7=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 022/121] 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 023/121] 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 024/121] 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() From f3d1a9925a16a7e15ef864430d43f28377efde42 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Thu, 1 Mar 2018 11:45:54 -0300 Subject: [PATCH 025/121] 1664 fix numeracao materia legislativa (#1726) * Fix #1714 * Fixes #1718 * Fix #1718 * Progress * Fix #1664 * Fix #1664 * Fix #1664 --- sapl/materia/forms.py | 2 +- sapl/materia/tests/test_materia.py | 75 ++++++++++++++++++++++++++++++ sapl/materia/urls.py | 2 +- sapl/materia/views.py | 6 ++- 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 5ee44e1c2..6ef99995b 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1575,7 +1575,7 @@ class ConfirmarProposicaoForm(ProposicaoForm): except AttributeError: pass - tipo = proposicao.tipo.tipo_conteudo_related + tipo = self.instance.tipo.tipo_conteudo_related if tipo.sequencia_numeracao: numeracao = tipo.sequencia_numeracao diff --git a/sapl/materia/tests/test_materia.py b/sapl/materia/tests/test_materia.py index c0a0358d6..ff8f89ad6 100644 --- a/sapl/materia/tests/test_materia.py +++ b/sapl/materia/tests/test_materia.py @@ -1,10 +1,12 @@ import pytest +from django.db.models import Max from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.core.files.uploadedfile import SimpleUploadedFile from django.core.urlresolvers import reverse from model_mommy import mommy from sapl.base.models import Autor, TipoAutor +from sapl.parlamentares.models import Legislatura from sapl.comissoes.models import Comissao, TipoComissao from sapl.materia.models import (Anexada, Autoria, DespachoInicial, DocumentoAcessorio, MateriaLegislativa, @@ -505,3 +507,76 @@ def test_form_errors_proposicao(admin_client): ['Este campo é obrigatório.']) assert (response.context_data['form'].errors['descricao'] == ['Este campo é obrigatório.']) + + + +@pytest.mark.django_db(transaction=False) +def test_numeracao_materia_legislativa_por_legislatura(admin_client): + + #Criar Legislaturas + legislatura1 = mommy.make(Legislatura, + data_inicio='2014-01-01', + data_fim='2018-12-31', + numero=20, + data_eleicao='2013-10-15' + ) + legislatura2 = mommy.make(Legislatura, + data_inicio='2009-01-01', + data_fim='2013-12-31', + numero=21, + data_eleicao='2018-10-15' + ) + + + # Cria uma materia na legislatura1 + tipo_materia = mommy.make(TipoMateriaLegislativa, id=1,sequencia_numeracao='L') + materia = mommy.make(MateriaLegislativa, + tipo=tipo_materia, + ano=2017, + numero=1 + ) + + url = reverse('sapl.materia:recuperar_materia') + + # Testa numeração do Materia Legislativa na Legislatura1 + query_params = '?tipo={}&ano={}'.format(materia.tipo.id, materia.ano) + response = admin_client.get(url + query_params, follow=True) + response_content = eval(response.content.decode('ascii')) + esperado_legislatura1 = eval('{"numero": 2, "ano": "2017"}') + assert response_content['numero'] == esperado_legislatura1['numero'] + + # Testa numeração do Materia Legislativa na Legislatura2 + query_params = '?tipo={}&ano={}'.format(1, '2010') + response = admin_client.get(url + query_params, follow=True) + response_content = eval(response.content.decode('ascii')) + esperado_legislatura2 = eval('{"ano": "2010", "numero": 1}') + assert response_content['numero'] == esperado_legislatura2['numero'] + + +@pytest.mark.django_db(transaction=False) +def test_numeracao_materia_legislativa_por_ano(admin_client): + + # Cria uma materia + tipo_materia = mommy.make(TipoMateriaLegislativa, id=1,sequencia_numeracao='A') + materia = mommy.make(MateriaLegislativa, + tipo=tipo_materia, + ano=2017, + numero=1 + ) + + + url = reverse('sapl.materia:recuperar_materia') + + # Testa numeração da Materia Legislativa no ano da materia criada + query_params = '?tipo={}&ano={}'.format(materia.tipo.id, materia.ano) + response = admin_client.get(url + query_params, follow=True) + response_content = eval(response.content.decode('ascii')) + esperado_ano = eval('{"numero": 2, "ano": "2017"}') + assert response_content['numero'] == esperado_ano['numero'] + + # Testa numeração da Materia Legislativa de outro ano + query_params = '?tipo={}&ano={}'.format(1, '2010') + response = admin_client.get(url + query_params, follow=True) + response_content = eval(response.content.decode('ascii')) + esperado_outro_ano = eval('{"ano": "2010", "numero": 1}') + assert response_content['numero'] == esperado_outro_ano['numero'] diff --git a/sapl/materia/urls.py b/sapl/materia/urls.py index 67ecf010f..3a30800d2 100644 --- a/sapl/materia/urls.py +++ b/sapl/materia/urls.py @@ -62,7 +62,7 @@ urlpatterns_materia = [ url(r'^materia/(?P[0-9]+)/create_simplificado$', CriarProtocoloMateriaView.as_view(), name='materia_create_simplificado'), - url(r'^materia/recuperar-materia', recuperar_materia), + url(r'^materia/recuperar-materia',recuperar_materia, name='recuperar_materia'), url(r'^materia/(?P[0-9]+)/ta$', MateriaTaView.as_view(), name='materia_ta'), diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 7ca7c0b7a..ffeda503b 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -295,9 +295,11 @@ def recuperar_materia(request): if numeracao == 'A': numero = MateriaLegislativa.objects.filter( - ano=timezone.now().year).aggregate(Max('numero')) + ano=ano).aggregate(Max('numero')) elif numeracao == 'L': - legislatura = Legislatura.objects.first() + legislatura = Legislatura.objects.filter( + data_inicio__year__lte=ano, + data_fim__year__gte=ano).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim numero = MateriaLegislativa.objects.filter( From 08a971856b74132f8b2dc220aa6312680831f1e8 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 1 Mar 2018 12:04:14 -0300 Subject: [PATCH 026/121] Release: 3.1.55 --- 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 11e5caedf..75c7c0615 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.54 + image: interlegis/sapl:3.1.55 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index c98fb482e..279a55a1a 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.54', + version='3.1.55', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 282a1f80cea275f809636044eb8eabd94bb3b40e Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Fri, 2 Mar 2018 11:28:29 -0300 Subject: [PATCH 027/121] Fix #1727 fix #1664 (#1728) --- sapl/materia/views.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index ffeda503b..a5f69a1e0 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -295,7 +295,7 @@ def recuperar_materia(request): if numeracao == 'A': numero = MateriaLegislativa.objects.filter( - ano=ano).aggregate(Max('numero')) + ano=ano, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': legislatura = Legislatura.objects.filter( data_inicio__year__lte=ano, @@ -304,10 +304,11 @@ def recuperar_materia(request): data_fim = legislatura.data_fim numero = MateriaLegislativa.objects.filter( data_apresentacao__gte=data_inicio, - data_apresentacao__lte=data_fim).aggregate( + data_apresentacao__lte=data_fim, + tipo=tipo).aggregate( Max('numero')) elif numeracao == 'U': - numero = MateriaLegislativa.objects.all().aggregate(Max('numero')) + numero = MateriaLegislativa.objects.filter(tipo=tipo).aggregate(Max('numero')) if numeracao is None: numero['numero__max'] = 0 From 32854290d91526b778be6099ec7b5d4f7ff1ae17 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 2 Mar 2018 12:52:56 -0300 Subject: [PATCH 028/121] =?UTF-8?q?HOT-FIX:=20trata=20arquivo=20inexistent?= =?UTF-8?q?e=20e=20atualiza=20doc=20de=20instala=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/instalacao31.rst | 2 +- sapl/utils.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/instalacao31.rst b/docs/instalacao31.rst index 12828b199..e53bd6545 100644 --- a/docs/instalacao31.rst +++ b/docs/instalacao31.rst @@ -202,7 +202,7 @@ Instruções para criação do super usuário e de usuários de testes * Criar super usuário do django-contrib-admin (Será solicitado alguns dados para criação):: - ./manage.py createsuperuser + python3 manage.py createsuperuser * `Os perfis semânticos do SAPL `_ são fixos e atualizados a cada execução do comando:: diff --git a/sapl/utils.py b/sapl/utils.py index 488b2d8d6..80f1d3414 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -47,6 +47,10 @@ def clear_thumbnails_cache(queryset, field): continue path = Path(getattr(r, field).path) + + if not path.exists(): + continue + cache_files = path.parent.walk() for cf in cache_files: From ba4022a28fdb53e76f75361d0566ee1542bfe819 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 2 Mar 2018 12:54:52 -0300 Subject: [PATCH 029/121] Release: 3.1.56 --- 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 75c7c0615..dd6e180e7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.55 + image: interlegis/sapl:3.1.56 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 279a55a1a..a1e78cba8 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.55', + version='3.1.56', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 5efba8a78881b0a8e6a35066abfdacc6d54199ad Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Tue, 6 Mar 2018 09:08:06 -0300 Subject: [PATCH 030/121] Fix #1489 (#1731) --- sapl/protocoloadm/forms.py | 45 ++++++++++++++++++-- sapl/protocoloadm/tests/test_protocoloadm.py | 3 +- sapl/protocoloadm/views.py | 7 +++ sapl/templates/protocoloadm/layouts.yaml | 1 + 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 15f4850b0..7d00d8090 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -15,7 +15,7 @@ from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row from sapl.materia.models import (MateriaLegislativa, TipoMateriaLegislativa, UnidadeTramitacao) from sapl.utils import (RANGE_ANOS, AnoNumeroOrderingFilter, - RangeWidgetOverride, autor_label, autor_modal) + RangeWidgetOverride, autor_label, autor_modal, YES_NO_CHOICES) from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo, Protocolo, TipoDocumentoAdministrativo, @@ -363,6 +363,17 @@ class ProtocoloMateriaForm(ModelForm): empty_label='Selecione', ) + + numero_materia = forms.CharField( + label=_('Número matéria'), required=False) + + ano_materia = forms.CharField( + label=_('Ano matéria'), required=False) + + vincular_materia = forms.ChoiceField(label=_('Vincular a matéria existente?'), + widget=forms.RadioSelect(), + choices= YES_NO_CHOICES) + numero_paginas = forms.CharField(label=_('Núm. Páginas'), required=True) observacao = forms.CharField(required=False, @@ -378,7 +389,11 @@ class ProtocoloMateriaForm(ModelForm): 'autor', 'tipo_autor', 'assunto_ementa', - 'observacao'] + 'observacao', + 'numero_materia', + 'ano_materia', + 'vincular_materia' + ] def clean_autor(self): autor_field = self.cleaned_data['autor'] @@ -390,6 +405,26 @@ class ProtocoloMateriaForm(ModelForm): autor_field = autor return autor_field + def clean(self): + super(ProtocoloMateriaForm, self).clean() + + data = self.cleaned_data + if self.is_valid(): + if data['vincular_materia'] == 'True': + try: + self.materia = MateriaLegislativa.objects.get(ano=data['ano_materia'], + numero=data['numero_materia'], + tipo=data['tipo_materia']) + if self.materia.numero_protocolo: + raise ValidationError(_('Matéria Legislativa informada já possui o protocolo {}/{} vinculado.' + .format(self.materia.numero_protocolo, self.materia.ano))) + except ObjectDoesNotExist: + raise ValidationError(_('Matéria Legislativa informada não existente.')) + + return data + + + def __init__(self, *args, **kwargs): row1 = to_row( @@ -397,6 +432,10 @@ class ProtocoloMateriaForm(ModelForm): ('numero_paginas', 2), ('tipo_autor', 3), ('autor', 3)]) + row2 = to_row( + [('vincular_materia', 4), + ('numero_materia', 4), + ('ano_materia', 4),]) row3 = to_row( [('assunto_ementa', 12)]) row4 = to_row( @@ -405,7 +444,7 @@ class ProtocoloMateriaForm(ModelForm): self.helper = FormHelper() self.helper.layout = Layout( Fieldset(_('Identificação da Matéria'), - row1, row3, + row1, row2, row3, row4, form_actions(label='Protocolar Matéria'))) super(ProtocoloMateriaForm, self).__init__( diff --git a/sapl/protocoloadm/tests/test_protocoloadm.py b/sapl/protocoloadm/tests/test_protocoloadm.py index 31e957513..216a0f24d 100644 --- a/sapl/protocoloadm/tests/test_protocoloadm.py +++ b/sapl/protocoloadm/tests/test_protocoloadm.py @@ -411,5 +411,6 @@ def test_protocolo_materia_invalido(): assert errors['tipo_materia'] == [_('Este campo é obrigatório.')] assert errors['numero_paginas'] == [_('Este campo é obrigatório.')] assert errors['autor'] == [_('Este campo é obrigatório.')] + assert errors['vincular_materia'] == [_('Este campo é obrigatório.')] - assert len(errors) == 5 + assert len(errors) == 6 diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index a10aa30f8..47b875753 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -468,6 +468,13 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): protocolo.assunto_ementa = self.request.POST['assunto_ementa'] protocolo.save() + data = form.cleaned_data + materia = MateriaLegislativa.objects.get(ano=data['ano_materia'], + numero=data['numero_materia'], + tipo=data['tipo_materia']) + materia.numero_protocolo = protocolo.numero + materia.save() + return redirect(self.get_success_url(protocolo)) def get_context_data(self, **kwargs): diff --git a/sapl/templates/protocoloadm/layouts.yaml b/sapl/templates/protocoloadm/layouts.yaml index b46664de6..76b80da18 100644 --- a/sapl/templates/protocoloadm/layouts.yaml +++ b/sapl/templates/protocoloadm/layouts.yaml @@ -43,6 +43,7 @@ Protocolo: Protocolo: {% trans 'Indentificação da Matéria' %}: - tipo_materia numero_paginas + - numero_materia ano_materia vincular_materia - assunto_ementa - autor - observacao From 11d35270261cfcf2483d4260b8c038b00e79da9d Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Tue, 6 Mar 2018 09:12:17 -0300 Subject: [PATCH 031/121] Fix numeracao materia (#1730) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix-numeracao-na-incoporacao-da-proposicao * Fix-numeracao-na-incoporacao-da-proposicao * Endereça comentário de review --- sapl/materia/forms.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 6ef99995b..a8a2baaa1 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1578,20 +1578,23 @@ class ConfirmarProposicaoForm(ProposicaoForm): tipo = self.instance.tipo.tipo_conteudo_related if tipo.sequencia_numeracao: numeracao = tipo.sequencia_numeracao - + ano = timezone.now().year if numeracao == 'A': numero = MateriaLegislativa.objects.filter( - ano=timezone.now().year).aggregate(Max('numero')) + ano=ano, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': - legislatura = Legislatura.objects.first() + legislatura = Legislatura.objects.filter( + data_inicio__year__lte=ano, + data_fim__year__gte=ano).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim numero = MateriaLegislativa.objects.filter( data_apresentacao__gte=data_inicio, - data_apresentacao__lte=data_fim).aggregate( + data_apresentacao__lte=data_fim, + tipo=tipo).aggregate( Max('numero')) elif numeracao == 'U': - numero = MateriaLegislativa.objects.all().aggregate(Max('numero')) + numero = MateriaLegislativa.objects.filter(tipo=tipo).aggregate(Max('numero')) if numeracao is None: numero['numero__max'] = 0 @@ -1603,7 +1606,7 @@ class ConfirmarProposicaoForm(ProposicaoForm): materia.numero = max_numero materia.tipo = tipo materia.ementa = proposicao.descricao - materia.ano = timezone.now().year + materia.ano = ano materia.data_apresentacao = timezone.now() materia.em_tramitacao = True materia.regime_tramitacao = cd['regime_tramitacao'] From bb1101e4a5d2594d76a39f6e5471ed86d7a40299 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 6 Mar 2018 09:14:17 -0300 Subject: [PATCH 032/121] Release: 3.1.57 --- 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 dd6e180e7..5c5341afc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.56 + image: interlegis/sapl:3.1.57 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index a1e78cba8..5bac3e202 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.56', + version='3.1.57', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From c6e61e7029ccb91d51e2efb2786f028eeaca0536 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Tue, 6 Mar 2018 11:09:23 -0300 Subject: [PATCH 033/121] Fix #1669 (#1734) --- sapl/base/forms.py | 41 ++++++++++++++++++- sapl/base/urls.py | 6 ++- sapl/base/views.py | 19 ++++++++- ...elatorioDataFimPrazoTramitacao_filter.html | 34 +++++++++++++++ sapl/templates/base/relatorios_list.html | 4 ++ 5 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 1181650ee..cdc6d25c8 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -466,7 +466,46 @@ class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet): self.form.helper = FormHelper() self.form.helper.form_method = 'GET' self.form.helper.layout = Layout( - Fieldset(_('Histórico de Tramita'), + Fieldset(_('Histórico de Tramitação'), + row1, row2, + form_actions(label='Pesquisar')) + ) + +class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet): + + filter_overrides = {models.DateField: { + 'filter_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), + 'widget': RangeWidgetOverride} + }} + + @property + def qs(self): + parent = super(RelatorioDataFimPrazoTramitacaoFilterSet, self).qs + return parent.distinct().order_by('-ano', 'tipo', 'numero') + + class Meta: + model = MateriaLegislativa + fields = ['tipo', 'tramitacao__unidade_tramitacao_local', + 'tramitacao__status', 'tramitacao__data_fim_prazo'] + + def __init__(self, *args, **kwargs): + super(RelatorioDataFimPrazoTramitacaoFilterSet, self).__init__( + *args, **kwargs) + + self.filters['tipo'].label = 'Tipo de Matéria' + + row1 = to_row([('tramitacao__data_fim_prazo', 12)]) + row2 = to_row( + [('tipo', 4), + ('tramitacao__unidade_tramitacao_local', 4), + ('tramitacao__status', 4)]) + + self.form.helper = FormHelper() + self.form.helper.form_method = 'GET' + self.form.helper.layout = Layout( + Fieldset(_('Tramitações por fim de prazo'), row1, row2, form_actions(label='Pesquisar')) ) diff --git a/sapl/base/urls.py b/sapl/base/urls.py index 143a89ba8..3b7d76e40 100644 --- a/sapl/base/urls.py +++ b/sapl/base/urls.py @@ -16,7 +16,8 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud, RelatorioMateriasPorAnoAutorTipoView, RelatorioMateriasPorAutorView, RelatorioMateriasTramitacaoView, - RelatorioPresencaSessaoView, SaplSearchView) + RelatorioPresencaSessaoView, SaplSearchView, + RelatorioDataFimPrazoTramitacaoView) app_name = AppConfig.name @@ -83,6 +84,9 @@ urlpatterns = [ url(r'^sistema/relatorios/historico-tramitacoes$', RelatorioHistoricoTramitacaoView.as_view(), name='historico_tramitacoes'), + url(r'^sistema/relatorios/data-fim-prazo-tramitacoes$', + RelatorioDataFimPrazoTramitacaoView.as_view(), + name='data_fim_prazo_tramitacoes'), url(r'^sistema/relatorios/presenca$', RelatorioPresencaSessaoView.as_view(), name='presenca_sessao'), diff --git a/sapl/base/views.py b/sapl/base/views.py index f31ed1c58..386364420 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -33,7 +33,8 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm, RelatorioMateriasPorAnoAutorTipoFilterSet, RelatorioMateriasPorAutorFilterSet, RelatorioMateriasTramitacaoilterSet, - RelatorioPresencaSessaoFilterSet) + RelatorioPresencaSessaoFilterSet, + RelatorioDataFimPrazoTramitacaoFilterSet) from .models import AppConfig, CasaLegislativa @@ -357,6 +358,22 @@ class RelatorioHistoricoTramitacaoView(FilterView): return context +class RelatorioDataFimPrazoTramitacaoView(FilterView): + model = MateriaLegislativa + filterset_class = RelatorioDataFimPrazoTramitacaoFilterSet + template_name = 'base/RelatorioDataFimPrazoTramitacao_filter.html' + + def get_context_data(self, **kwargs): + context = super(RelatorioDataFimPrazoTramitacaoView, + self).get_context_data(**kwargs) + context['title'] = _('Fim de Prazo de Tramitações') + qr = self.request.GET.copy() + context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' + + context['show_results'] = show_results_filter_set(qr) + + return context + class RelatorioMateriasTramitacaoView(FilterView): model = MateriaLegislativa diff --git a/sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html b/sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html new file mode 100644 index 000000000..1fccf1268 --- /dev/null +++ b/sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html @@ -0,0 +1,34 @@ +{% extends "crud/list.html" %} +{% load i18n %} +{% load crispy_forms_tags %} + +{% block base_content %} + {% if not show_results %} + {% crispy filter.form %} + {% endif %} + + {% if show_results %} + +



    + + + + + + + + + {% for materia in object_list %} + + + + + {% endfor %} + +
    MatériaEmenta
    + {{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} + {{materia.ementa}}
    + {% endif %} +{% endblock base_content %} \ No newline at end of file diff --git a/sapl/templates/base/relatorios_list.html b/sapl/templates/base/relatorios_list.html index c7e47bd69..1bd0f5eda 100644 --- a/sapl/templates/base/relatorios_list.html +++ b/sapl/templates/base/relatorios_list.html @@ -36,6 +36,10 @@ Histórico de tramitações Histórico de tramitações por período e local informados. + + Tramitações por fim de prazo + Tramitações com fim de prazo no intervalo informado. + Date: Tue, 6 Mar 2018 15:45:28 -0300 Subject: [PATCH 034/121] =?UTF-8?q?Fix=20protocola=C3=A7=C3=A3o=20de=20Mat?= =?UTF-8?q?eria=20Legislativa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/protocoloadm/forms.py | 2 ++ sapl/protocoloadm/views.py | 48 ++++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 7d00d8090..fbac3cf6c 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -412,6 +412,8 @@ class ProtocoloMateriaForm(ModelForm): if self.is_valid(): if data['vincular_materia'] == 'True': try: + if not data['ano_materia'] or not data['numero_materia']: + raise ValidationError('Favor informar o número e ano da matéria a ser vinculada') self.materia = MateriaLegislativa.objects.get(ano=data['ano_materia'], numero=data['numero_materia'], tipo=data['tipo_materia']) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 47b875753..17c1c9ab7 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -289,17 +289,21 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, return self.render_to_response(self.get_context_data()) if numeracao == 'A': - numero = Protocolo.objects.filter( - ano=timezone.now().year).aggregate(Max('numero')) + numero = MateriaLegislativa.objects.filter( + ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': - legislatura = Legislatura.objects.first() + legislatura = Legislatura.objects.filter( + data_inicio__year__lte=timezone.now().year, + data_fim__year__gte=timezone.now().year).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim - numero = Protocolo.objects.filter( - data__gte=data_inicio, data__lte=data_fim).aggregate( - Max('numero')) + numero = MateriaLegislativa.objects.filter( + data_apresentacao__gte=data_inicio, + data_apresentacao__lte=data_fim, + tipo=tipo).aggregate( + Max('numero')) elif numeracao == 'U': - numero = Protocolo.objects.all().aggregate(Max('numero')) + numero = MateriaLegislativa.objects.filter(tipo=tipo).aggregate(Max('numero')) f.tipo_processo = '0' # TODO validar o significado f.anulado = False @@ -414,7 +418,6 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): 'pk': protocolo.pk}) def form_valid(self, form): - try: numeracao = sapl.base.models.AppConfig.objects.last( ).sequencia_numeracao @@ -431,17 +434,21 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): numeracao = tipo.sequencia_numeracao if numeracao == 'A': - numero = Protocolo.objects.filter( - ano=timezone.now().year).aggregate(Max('numero')) + numero = MateriaLegislativa.objects.filter( + ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': - legislatura = Legislatura.objects.first() + legislatura = Legislatura.objects.filter( + data_inicio__year__lte=timezone.now().year, + data_fim__year__gte=timezone.now().year).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim - numero = Protocolo.objects.filter( - data__gte=data_inicio, data__lte=data_fim).aggregate( - Max('numero')) + numero = MateriaLegislativa.objects.filter( + data_apresentacao__gte=data_inicio, + data_apresentacao__lte=data_fim, + tipo=tipo).aggregate( + Max('numero')) elif numeracao == 'U': - numero = Protocolo.objects.all().aggregate(Max('numero')) + numero = MateriaLegislativa.objects.filter(tipo=tipo).aggregate(Max('numero')) if numeracao is None: numero['numero__max'] = 0 @@ -469,11 +476,12 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): protocolo.save() data = form.cleaned_data - materia = MateriaLegislativa.objects.get(ano=data['ano_materia'], - numero=data['numero_materia'], - tipo=data['tipo_materia']) - materia.numero_protocolo = protocolo.numero - materia.save() + if data['vincular_materia'] == 'True': + materia = MateriaLegislativa.objects.get(ano=data['ano_materia'], + numero=data['numero_materia'], + tipo=data['tipo_materia']) + materia.numero_protocolo = protocolo.numero + materia.save() return redirect(self.get_success_url(protocolo)) From bb6c382691979ea9f5c6a08ec62547f5604ed262 Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Tue, 6 Mar 2018 15:46:42 -0300 Subject: [PATCH 035/121] 1566 cadastro de reunioes (#1614) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adiciona a model, forms e views da reunião de comissão * Adiciona a model reunião no map_rules * Adiciona telas de cadastro de reunião * Adiciona layouts e legacy * Adiciona template, modifica o subnav e o ListView * Resolve conflitos * corrige form de reunião * Troca Crud por MasterCrudDetail * Adiciona template de cadastro de reunião * Corrige Createview e Listview * Ajusta comissoes * Corrige a model e o layout da tela de criação * Corrige o deleteview e o detailview * FIX #1566 * Muda o layout do create de reunião * Corrige layout e model de reunião * HOT-FIX: tirar ipdb do materia/form * Muda o layout do create de reunião * ajusta campos timefield em reunião de comissões --- sapl/comissoes/forms.py | 33 ++++- sapl/comissoes/legacy.yaml | 18 +++ sapl/comissoes/migrations/0003_reuniao.py | 44 ++++++ sapl/comissoes/migrations/0005_merge.py | 16 +++ .../migrations/0006_auto_20180227_0842.py | 25 ++++ .../migrations/0007_auto_20180227_1025.py | 25 ++++ .../migrations/0008_auto_20180227_1111.py | 25 ++++ .../migrations/0009_auto_20180301_1011.py | 41 ++++++ .../migrations/0010_auto_20180306_0918.py | 25 ++++ sapl/comissoes/models.py | 133 ++++++++++++++++-- sapl/comissoes/urls.py | 3 +- sapl/comissoes/views.py | 57 +++++++- sapl/crispy_layout_mixin.py | 2 +- sapl/materia/forms.py | 1 - sapl/redireciona_urls/views.py | 49 +++++++ sapl/rules/map_rules.py | 1 + sapl/templates/comissoes/layouts.yaml | 15 +- sapl/templates/comissoes/reunioes.html | 8 -- sapl/templates/comissoes/subnav.yaml | 2 + 19 files changed, 491 insertions(+), 32 deletions(-) create mode 100644 sapl/comissoes/migrations/0003_reuniao.py create mode 100644 sapl/comissoes/migrations/0005_merge.py create mode 100644 sapl/comissoes/migrations/0006_auto_20180227_0842.py create mode 100644 sapl/comissoes/migrations/0007_auto_20180227_1025.py create mode 100644 sapl/comissoes/migrations/0008_auto_20180227_1111.py create mode 100644 sapl/comissoes/migrations/0009_auto_20180301_1011.py create mode 100644 sapl/comissoes/migrations/0010_auto_20180306_0918.py delete mode 100644 sapl/templates/comissoes/reunioes.html diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index 2ce7dcfaa..33be2003d 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -3,9 +3,10 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.db import transaction from django.db.models import Q +from django.forms import ModelForm from django.utils.translation import ugettext_lazy as _ from sapl.base.models import Autor, TipoAutor -from sapl.comissoes.models import Comissao, Composicao, Participacao +from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar @@ -69,7 +70,8 @@ class ParticipacaoCreateForm(forms.ModelForm): composicao = Composicao.objects.get(id=self.initial['parent_pk']) participantes = composicao.participacao_set.all() participantes_id = [p.parlamentar.id for p in participantes] - parlamentares = Parlamentar.objects.all().exclude(id__in=participantes_id).order_by('nome_completo') + parlamentares = Parlamentar.objects.all().exclude( + id__in=participantes_id).order_by('nome_completo') parlamentares = [p for p in parlamentares if p.ativo] lista = [] @@ -142,3 +144,30 @@ class ComissaoForm(forms.ModelForm): nome=nome ) return comissao + + +class ReuniaoForm(ModelForm): + + comissao = forms.ModelChoiceField(queryset=Comissao.objects.all(), + widget=forms.HiddenInput()) + + class Meta: + model = Reuniao + exclude = ['cod_andamento_reuniao'] + widgets = { + 'hora_fim': forms.TimeInput(format='%H:%M'), + 'hora_inicio': forms.TimeInput(format='%H:%M'), + } + + def clean(self): + super(ReuniaoForm, self).clean() + + if self.errors: + return + + if self.cleaned_data['hora_fim'] < self.cleaned_data['hora_inicio']: + msg = _('A hora de término da reunião não pode ' + 'ser menor que a de início') + raise ValidationError(msg) + + return self.cleaned_data diff --git a/sapl/comissoes/legacy.yaml b/sapl/comissoes/legacy.yaml index a1093c4d2..2414df885 100644 --- a/sapl/comissoes/legacy.yaml +++ b/sapl/comissoes/legacy.yaml @@ -43,3 +43,21 @@ Participacao (ComposicaoComissao): observacao: obs_composicao parlamentar: cod_parlamentar titular: ind_titular + +Reuniao: + periodo: periodo_reuniao + comissao: cod_comissao + tipo: tipo_comissao + numero: num_comissao + nome: nom_reuniao + tema: tem_reuniao + data: dat_reuniao + hora_inicio: hora_inicio_reuniao + hora_fim: hora_fim_reuniao + local_reuniao: local + observacao: obs_reuniao + ulr_audio: audio_reuniao + url_video: video_reuniao + upload_pauta: pauta_reuniao + upload_ata: ata_reuniao + upload_anexo: anexo_reuniao diff --git a/sapl/comissoes/migrations/0003_reuniao.py b/sapl/comissoes/migrations/0003_reuniao.py new file mode 100644 index 000000000..acdf8bf76 --- /dev/null +++ b/sapl/comissoes/migrations/0003_reuniao.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2017-11-23 13:07 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import sapl.comissoes.models +import sapl.utils + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0002_auto_20170809_1236'), + ] + + operations = [ + migrations.CreateModel( + name='Reuniao', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('numero', models.PositiveIntegerField(verbose_name='Número')), + ('nome', models.CharField(max_length=100, verbose_name='Nome da Reunião')), + ('tema', models.CharField(max_length=100, verbose_name='Tema da Reunião')), + ('data', models.DateField(verbose_name='Data')), + ('hora_inicio', models.CharField(max_length=5, verbose_name='Horário (hh:mm)')), + ('hora_fim', models.CharField(max_length=5, verbose_name='Horário (hh:mm)')), + ('local_reuniao', models.CharField(blank=True, max_length=100, verbose_name='Local Reunião')), + ('observacao', models.CharField(blank=True, max_length=150, verbose_name='Observação')), + ('url_audio', models.URLField(blank=True, max_length=150, verbose_name='URL Arquivo Áudio (Formatos MP3 / AAC)')), + ('url_video', models.URLField(blank=True, max_length=150, verbose_name='URL Arquivo Vídeo (Formatos MP4 / FLV / WebM)')), + ('upload_pauta', models.FileField(blank=True, null=True, upload_to=sapl.comissoes.models.pauta_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Pauta da Reunião')), + ('upload_ata', models.FileField(blank=True, null=True, upload_to=sapl.comissoes.models.ata_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Ata da Reunião')), + ('upload_anexo', models.FileField(blank=True, null=True, upload_to=sapl.comissoes.models.anexo_upload_path, verbose_name='Anexo da Reunião')), + ('comissao', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='comissoes.Comissao', verbose_name='Comissão')), + ('periodo', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='comissoes.Periodo', verbose_name='Periodo da Composicão da Comissão')), + ('tipo', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='comissoes.TipoComissao', verbose_name='Tipo')), + ], + options={ + 'verbose_name': 'Reunião de Comissão', + 'verbose_name_plural': 'Reuniões de Comissão', + }, + ), + ] diff --git a/sapl/comissoes/migrations/0005_merge.py b/sapl/comissoes/migrations/0005_merge.py new file mode 100644 index 000000000..f171eb151 --- /dev/null +++ b/sapl/comissoes/migrations/0005_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-02-26 10:41 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0004_auto_20180102_1652'), + ('comissoes', '0003_reuniao'), + ] + + operations = [ + ] diff --git a/sapl/comissoes/migrations/0006_auto_20180227_0842.py b/sapl/comissoes/migrations/0006_auto_20180227_0842.py new file mode 100644 index 000000000..ebe3e0029 --- /dev/null +++ b/sapl/comissoes/migrations/0006_auto_20180227_0842.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-02-27 11:42 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0005_merge'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='url_audio', + field=models.URLField(blank=True, max_length=150, null=True, verbose_name='URL Arquivo Áudio (Formatos MP3 / AAC)'), + ), + migrations.AlterField( + model_name='reuniao', + name='url_video', + field=models.URLField(blank=True, max_length=150, null=True, verbose_name='URL Arquivo Vídeo (Formatos MP4 / FLV / WebM)'), + ), + ] diff --git a/sapl/comissoes/migrations/0007_auto_20180227_1025.py b/sapl/comissoes/migrations/0007_auto_20180227_1025.py new file mode 100644 index 000000000..fb13ba123 --- /dev/null +++ b/sapl/comissoes/migrations/0007_auto_20180227_1025.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-02-27 13:25 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0006_auto_20180227_0842'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='hora_fim', + field=models.CharField(max_length=5, verbose_name='Horário de Término (hh:mm)'), + ), + migrations.AlterField( + model_name='reuniao', + name='hora_inicio', + field=models.CharField(max_length=5, verbose_name='Horário de Início (hh:mm)'), + ), + ] diff --git a/sapl/comissoes/migrations/0008_auto_20180227_1111.py b/sapl/comissoes/migrations/0008_auto_20180227_1111.py new file mode 100644 index 000000000..478576a1b --- /dev/null +++ b/sapl/comissoes/migrations/0008_auto_20180227_1111.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-02-27 14:11 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0007_auto_20180227_1025'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='url_audio', + field=models.URLField(blank=True, max_length=150, verbose_name='URL Arquivo Áudio (Formatos MP3 / AAC)'), + ), + migrations.AlterField( + model_name='reuniao', + name='url_video', + field=models.URLField(blank=True, max_length=150, verbose_name='URL Arquivo Vídeo (Formatos MP4 / FLV / WebM)'), + ), + ] diff --git a/sapl/comissoes/migrations/0009_auto_20180301_1011.py b/sapl/comissoes/migrations/0009_auto_20180301_1011.py new file mode 100644 index 000000000..db559de75 --- /dev/null +++ b/sapl/comissoes/migrations/0009_auto_20180301_1011.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-01 13:11 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0008_auto_20180227_1111'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='local_reuniao', + field=models.CharField(blank=True, max_length=100, verbose_name='Local da Reunião'), + ), + migrations.AlterField( + model_name='reuniao', + name='observacao', + field=models.TextField(blank=True, max_length=150, verbose_name='Observação'), + ), + migrations.AlterField( + model_name='reuniao', + name='tipo', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='comissoes.TipoComissao', verbose_name='Tipo de Comissão'), + ), + migrations.AlterField( + model_name='reuniao', + name='url_audio', + field=models.URLField(blank=True, max_length=150, verbose_name='URL do Arquivo de Áudio (Formatos MP3 / AAC)'), + ), + migrations.AlterField( + model_name='reuniao', + name='url_video', + field=models.URLField(blank=True, max_length=150, verbose_name='URL do Arquivo de Vídeo (Formatos MP4 / FLV / WebM)'), + ), + ] diff --git a/sapl/comissoes/migrations/0010_auto_20180306_0918.py b/sapl/comissoes/migrations/0010_auto_20180306_0918.py new file mode 100644 index 000000000..b2dd48f87 --- /dev/null +++ b/sapl/comissoes/migrations/0010_auto_20180306_0918.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-06 12:18 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0009_auto_20180301_1011'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='hora_fim', + field=models.TimeField(verbose_name='Horário de Término (hh:mm)'), + ), + migrations.AlterField( + model_name='reuniao', + name='hora_inicio', + field=models.TimeField(verbose_name='Horário de Início (hh:mm)'), + ), + ] diff --git a/sapl/comissoes/models.py b/sapl/comissoes/models.py index 078097cab..882fe8638 100644 --- a/sapl/comissoes/models.py +++ b/sapl/comissoes/models.py @@ -1,11 +1,12 @@ - -import reversion from django.db import models from django.utils.translation import ugettext_lazy as _ from model_utils import Choices +import reversion + from sapl.base.models import Autor from sapl.parlamentares.models import Parlamentar -from sapl.utils import YES_NO_CHOICES, SaplGenericRelation +from sapl.utils import (YES_NO_CHOICES, SaplGenericRelation, + restringe_tipos_de_arquivo_txt, texto_upload_path) @reversion.register() @@ -52,22 +53,18 @@ class Comissao(models.Model): secretario = models.CharField( max_length=30, blank=True, verbose_name=_('Secretário')) telefone_reuniao = models.CharField( - max_length=15, - blank=True, + max_length=15, blank=True, verbose_name=_('Tel. Sala Reunião')) endereco_secretaria = models.CharField( - max_length=100, - blank=True, + max_length=100, blank=True, verbose_name=_('Endereço Secretaria')) telefone_secretaria = models.CharField( - max_length=15, - blank=True, + max_length=15, blank=True, verbose_name=_('Tel. Secretaria')) fax_secretaria = models.CharField( max_length=15, blank=True, verbose_name=_('Fax Secretaria')) agenda_reuniao = models.CharField( - max_length=100, - blank=True, + max_length=100, blank=True, verbose_name=_('Data/Hora Reunião')) local_reuniao = models.CharField( max_length=100, blank=True, verbose_name=_('Local Reunião')) @@ -83,7 +80,6 @@ class Comissao(models.Model): default=False, choices=YES_NO_CHOICES, verbose_name=_('Comissão Ativa?')) - autor = SaplGenericRelation(Autor, related_query_name='comissao_set', fields_search=( @@ -170,8 +166,7 @@ class Participacao(models.Model): # ComposicaoComissao null=True, verbose_name=_('Data Desligamento')) motivo_desligamento = models.CharField( - max_length=150, - blank=True, + max_length=150, blank=True, verbose_name=_('Motivo Desligamento')) observacao = models.CharField( max_length=150, blank=True, verbose_name=_('Observação')) @@ -182,3 +177,113 @@ class Participacao(models.Model): # ComposicaoComissao def __str__(self): return '%s : %s' % (self.cargo, self.parlamentar) + + +def get_comissao_media_path(instance, subpath, filename): + return './sapl/comissao/%s/%s/%s' % (instance.numero, subpath, filename) + + +def pauta_upload_path(instance, filename): + return texto_upload_path(instance, filename, subpath='pauta', pk_first=True) + + +def ata_upload_path(instance, filename): + return texto_upload_path(instance, filename, subpath='ata', pk_first=True) + + +def anexo_upload_path(instance, filename): + return texto_upload_path(instance, filename, subpath='anexo', pk_first=True) + + +class Reuniao(models.Model): + periodo = models. ForeignKey( + Periodo, + on_delete=models.PROTECT, + verbose_name=_('Periodo da Composicão da Comissão')) + comissao = models.ForeignKey( + Comissao, + on_delete=models.PROTECT, + verbose_name=_('Comissão')) + tipo = models.ForeignKey( + TipoComissao, + on_delete=models.PROTECT, + verbose_name=_('Tipo de Comissão')) + numero = models.PositiveIntegerField(verbose_name=_('Número')) + nome = models.CharField( + max_length=100, verbose_name=_('Nome da Reunião')) + tema = models.CharField( + max_length=100, verbose_name=_('Tema da Reunião')) + data = models.DateField(verbose_name=_('Data')) + hora_inicio = models.TimeField( + verbose_name=_('Horário de Início (hh:mm)')) + hora_fim = models.TimeField( + verbose_name=_('Horário de Término (hh:mm)')) + local_reuniao = models.CharField( + max_length=100, blank=True, verbose_name=_('Local da Reunião')) + observacao = models.TextField( + max_length=150, blank=True, verbose_name=_('Observação')) + url_audio = models.URLField( + max_length=150, blank=True, + verbose_name=_('URL do Arquivo de Áudio (Formatos MP3 / AAC)')) + url_video = models.URLField( + max_length=150, blank=True, + verbose_name=_('URL do Arquivo de Vídeo (Formatos MP4 / FLV / WebM)')) + upload_pauta = models.FileField( + blank=True, null=True, + upload_to=pauta_upload_path, + verbose_name=_('Pauta da Reunião'), + validators=[restringe_tipos_de_arquivo_txt]) + upload_ata = models.FileField( + blank=True, null=True, + upload_to=ata_upload_path, + verbose_name=_('Ata da Reunião'), + validators=[restringe_tipos_de_arquivo_txt]) + upload_anexo = models.FileField( + blank=True, null=True, + upload_to=anexo_upload_path, + verbose_name=_('Anexo da Reunião')) + + class Meta: + verbose_name = _('Reunião de Comissão') + verbose_name_plural = _('Reuniões de Comissão') + + def __str__(self): + return self.nome + + def delete(self, using=None, keep_parents=False): + if self.upload_pauta: + self.upload_pauta.delete() + + if self.upload_ata: + self.upload_ata.delete() + + if self.upload_anexo: + self.upload_anexo.delete() + + return models.Model.delete( + self, using=using, keep_parents=keep_parents) + + def save(self, force_insert=False, force_update=False, using=None, + update_fields=None): + + if not self.pk and (self.upload_pauta or self.upload_ata or + self.upload_anexo): + upload_pauta = self.upload_pauta + upload_ata = self.upload_ata + upload_anexo = self.upload_anexo + self.upload_pauta = None + self.upload_ata = None + self.upload_anexo = None + models.Model.save(self, force_insert=force_insert, + force_update=force_update, + using=using, + update_fields=update_fields) + + self.upload_pauta = upload_pauta + self.upload_ata = upload_ata + self.upload_anexo = upload_anexo + + return models.Model.save(self, force_insert=force_insert, + force_update=force_update, + using=using, + update_fields=update_fields) diff --git a/sapl/comissoes/urls.py b/sapl/comissoes/urls.py index 128cb7647..47fb0b059 100644 --- a/sapl/comissoes/urls.py +++ b/sapl/comissoes/urls.py @@ -1,7 +1,7 @@ from django.conf.urls import include, url from sapl.comissoes.views import (CargoCrud, ComissaoCrud, ComposicaoCrud, MateriasTramitacaoListView, ParticipacaoCrud, - PeriodoComposicaoCrud, TipoComissaoCrud) + PeriodoComposicaoCrud, ReuniaoCrud, TipoComissaoCrud) from .apps import AppConfig @@ -10,6 +10,7 @@ app_name = AppConfig.name urlpatterns = [ url(r'^comissao/', include(ComissaoCrud.get_urls() + ComposicaoCrud.get_urls() + + ReuniaoCrud.get_urls() + ParticipacaoCrud.get_urls())), url(r'^comissao/(?P\d+)/materias-em-tramitacao$', diff --git a/sapl/comissoes/views.py b/sapl/comissoes/views.py index eb32b977a..0fd5a2c13 100644 --- a/sapl/comissoes/views.py +++ b/sapl/comissoes/views.py @@ -3,13 +3,23 @@ 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 django.views.generic.base import RedirectView +from django.views.generic.detail import DetailView +from django.views.generic.edit import FormMixin + + +from sapl.base.models import AppConfig as AppsAppConfig +from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, + CrudAux, MasterDetailCrud, + PermissionRequiredForAppCrudMixin) 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, Tramitacao -from .forms import ComissaoForm +from .forms import ReuniaoForm, ComissaoForm + from .models import (CargoComissao, Comissao, Composicao, Participacao, - Periodo, TipoComissao) + Periodo, TipoComissao, Reuniao) +from sapl.comissoes.apps import AppConfig def pegar_url_composicao(pk): @@ -136,3 +146,44 @@ class MateriasTramitacaoListView(ListView): MateriasTramitacaoListView, self).get_context_data(**kwargs) context['object'] = Comissao.objects.get(id=self.kwargs['pk']) return context + +class ReuniaoCrud(MasterDetailCrud): + model = Reuniao + parent_field = 'comissao' + public = [RP_LIST, RP_DETAIL, ] + + class BaseMixin(MasterDetailCrud.BaseMixin): + list_field_names = ['nome', 'tema', 'comissao'] + + @property + def list_url(self): + return '' + + class ListView(MasterDetailCrud.ListView): + paginate_by = 10 + + class UpdateView(MasterDetailCrud.UpdateView): + form_class = ReuniaoForm + + def get_initial(self): + return {'comissao': self.object.comissao} + + + class CreateView(MasterDetailCrud.CreateView): + form_class = ReuniaoForm + + def get_initial(self): + comissao = Comissao.objects.get(id=self.kwargs['pk']) + + return {'comissao': comissao} + + + class DeleteView(MasterDetailCrud.DeleteView): + pass + + + class DetailView(MasterDetailCrud.DetailView): + + @xframe_options_exempt + def get(self, request, *args, **kwargs): + return super().get(request, *args, **kwargs) diff --git a/sapl/crispy_layout_mixin.py b/sapl/crispy_layout_mixin.py index e582ba6c1..0adc1c679 100644 --- a/sapl/crispy_layout_mixin.py +++ b/sapl/crispy_layout_mixin.py @@ -96,7 +96,7 @@ def get_field_display(obj, fieldname): if value is None: display = '' - elif 'date' in str_type_from_value: + elif '.date' in str_type_from_value: display = formats.date_format(value, "SHORT_DATE_FORMAT") elif 'bool' in str_type_from_value: display = _('Sim') if value else _('Não') diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index a8a2baaa1..1eebd5c7d 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1263,7 +1263,6 @@ class ProposicaoForm(forms.ModelForm): not cd['texto_original'] and \ inst.texto_original: inst.texto_original.delete() - self.gerar_hash(inst, receber_recibo) return super().save(commit) diff --git a/sapl/redireciona_urls/views.py b/sapl/redireciona_urls/views.py index 41d58db33..4f1480a13 100644 --- a/sapl/redireciona_urls/views.py +++ b/sapl/redireciona_urls/views.py @@ -31,6 +31,7 @@ parlamentar_mesa_diretora = (app_parlamentares + ':mesa_diretora') comissao_list = (app_comissoes + ':comissao_list') comissao_detail = (app_comissoes + ':comissao_detail') +reuniao_detail = (app_comissoes + ':reuniao_detail') materialegislativa_detail = (app_materia + ':materialegislativa_detail') materialegislativa_list = (app_materia + ':pesquisar_materia') @@ -633,3 +634,51 @@ class RedirecionaMateriasPorAnoAutorTipo(RedirectView): url = has_iframe(url, self.request) return url + +class RedirecionaReuniao(RedirectView): + permanent = True + + def get_redirect_url(self): + pk_reuniao = self.request.GET.get( + 'cod_comissao', + EMPTY_STRING) + url = EMPTY_STRING + if pk_reuniao: + kwargs = {'pk': pk_reuniao} + try: + url = reverse(reuniao_detail, kwargs=kwargs) + except NoReverseMatch: + raise UnknownUrlNameError(reuniao_detail) + + else: + try: + url = reverse(reuniao_list) + except NoReverseMatch: + raise UnknownUrlNameError(reuniao_list) + + year = self.request.GET.get( + 'ano_reuniao', + EMPTY_STRING) + month = self.request.GET.get( + 'mes_reuniao', + EMPTY_STRING) + day = self.request.GET.get( + 'dia_reuniao', + EMPTY_STRING) + tipo_reuniao = self.request.GET.get( + 'tip_reuniao', + EMPTY_STRING) + + # Remove zeros à esquerda + day = day.lstrip("0") + month = month.lstrip("0") + args = EMPTY_STRING + args += "?data_inicio__year=%s" % (year) + args += "&data_inicio__month=%s" % (month) + args += "&data_inicio__day=%s" % (day) + args += "&tipo=%s&salvar=Pesquisar" % (tipo_reuniao) + url = "%s%s" % (url, args) + + url = has_iframe(url, self.request) + + return url diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index 415c7beca..65d6c0be2 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -89,6 +89,7 @@ rules_group_comissoes = { (comissoes.Composicao, __base__), (comissoes.Participacao, __base__), (materia.Relatoria, __base__), + (comissoes.Reuniao, __base__), ] } diff --git a/sapl/templates/comissoes/layouts.yaml b/sapl/templates/comissoes/layouts.yaml index b5e856b2e..231477a9c 100644 --- a/sapl/templates/comissoes/layouts.yaml +++ b/sapl/templates/comissoes/layouts.yaml @@ -1,4 +1,4 @@ -{% load i18n %} + {% load i18n %} CargoComissao: {% trans 'Período de composição de Comissão' %}: - nome:10 unico @@ -42,4 +42,15 @@ ParticipacaoEdit: - nome_parlamentar cargo titular - data_designacao data_desligamento - motivo_desligamento - - observacao \ No newline at end of file + - observacao + +Reuniao: + {% trans 'Reunião' %}: + - periodo numero tipo + - nome tema local_reuniao + - data hora_inicio hora_fim + - url_video url_audio + - observacao + - upload_pauta upload_ata upload_anexo + - comissao + diff --git a/sapl/templates/comissoes/reunioes.html b/sapl/templates/comissoes/reunioes.html deleted file mode 100644 index 6a78b7881..000000000 --- a/sapl/templates/comissoes/reunioes.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "comissoes/comissao_detail.html" %} -{% load i18n %} - -{% block actions %}{% endblock actions %} - -{% block detail_content %} - TODO ... Reuniões -{% endblock detail_content %} diff --git a/sapl/templates/comissoes/subnav.yaml b/sapl/templates/comissoes/subnav.yaml index 02402bfee..01c10b4f3 100644 --- a/sapl/templates/comissoes/subnav.yaml +++ b/sapl/templates/comissoes/subnav.yaml @@ -6,3 +6,5 @@ urls_extras: participacao_detail participacao_create participacao_edit participacao_delete - title: {% trans 'Matérias em Tramitação' %} url: materias_em_tramitacao +- title: {% trans 'Reunião' %} + url: reuniao_list From e3799867d8fa15368be937e32f7c401c87afa402 Mon Sep 17 00:00:00 2001 From: "tapumar@gmail.com" Date: Tue, 6 Mar 2018 16:08:22 -0300 Subject: [PATCH 036/121] Fix #1735 --- sapl/protocoloadm/views.py | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 17c1c9ab7..331c00ff1 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -277,8 +277,8 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, kwargs={'pk': self.object.id}) def form_valid(self, form): - f = form.save(commit=False) - + protocolo = form.save(commit=False) + import ipdb; ipdb.set_trace() try: numeracao = sapl.base.models.AppConfig.objects.last( ).sequencia_numeracao @@ -288,8 +288,10 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, messages.add_message(self.request, messages.ERROR, msg) return self.render_to_response(self.get_context_data()) + tipo = form.cleaned_data['tipo_documento'] + if numeracao == 'A': - numero = MateriaLegislativa.objects.filter( + numero = DocumentoAdministrativo.objects.filter( ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': legislatura = Legislatura.objects.filter( @@ -297,25 +299,25 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, data_fim__year__gte=timezone.now().year).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim - numero = MateriaLegislativa.objects.filter( - data_apresentacao__gte=data_inicio, - data_apresentacao__lte=data_fim, + numero = DocumentoAdministrativo.objects.filter( + data__gte=data_inicio, + data__lte=data_fim, tipo=tipo).aggregate( Max('numero')) elif numeracao == 'U': - numero = MateriaLegislativa.objects.filter(tipo=tipo).aggregate(Max('numero')) + numero = DocumentoAdministrativo.objects.filter(tipo=tipo).aggregate(Max('numero')) - f.tipo_processo = '0' # TODO validar o significado - f.anulado = False - f.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 - f.ano = timezone.now().year - f.data = timezone.now() - f.hora = timezone.now().time() - f.timestamp = timezone.now() - f.assunto_ementa = self.request.POST['assunto'] - - f.save() - self.object = f + protocolo.tipo_processo = '0' # TODO validar o significado + protocolo.anulado = False + protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 + protocolo.ano = timezone.now().year + protocolo.data = timezone.now() + protocolo.hora = timezone.now().time() + protocolo.timestamp = timezone.now() + protocolo.assunto_ementa = self.request.POST['assunto'] + + protocolo.save() + self.object = protocolo return redirect(self.get_success_url()) From 6d1322081c5aaad435041aa7d22fff1245561228 Mon Sep 17 00:00:00 2001 From: "tapumar@gmail.com" Date: Tue, 6 Mar 2018 16:08:22 -0300 Subject: [PATCH 037/121] Fix #1735 --- sapl/protocoloadm/views.py | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 17c1c9ab7..7c3ea3107 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -277,8 +277,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, kwargs={'pk': self.object.id}) def form_valid(self, form): - f = form.save(commit=False) - + protocolo = form.save(commit=False) try: numeracao = sapl.base.models.AppConfig.objects.last( ).sequencia_numeracao @@ -288,8 +287,10 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, messages.add_message(self.request, messages.ERROR, msg) return self.render_to_response(self.get_context_data()) + tipo = form.cleaned_data['tipo_documento'] + if numeracao == 'A': - numero = MateriaLegislativa.objects.filter( + numero = DocumentoAdministrativo.objects.filter( ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': legislatura = Legislatura.objects.filter( @@ -297,25 +298,25 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, data_fim__year__gte=timezone.now().year).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim - numero = MateriaLegislativa.objects.filter( - data_apresentacao__gte=data_inicio, - data_apresentacao__lte=data_fim, + numero = DocumentoAdministrativo.objects.filter( + data__gte=data_inicio, + data__lte=data_fim, tipo=tipo).aggregate( Max('numero')) elif numeracao == 'U': - numero = MateriaLegislativa.objects.filter(tipo=tipo).aggregate(Max('numero')) + numero = DocumentoAdministrativo.objects.filter(tipo=tipo).aggregate(Max('numero')) - f.tipo_processo = '0' # TODO validar o significado - f.anulado = False - f.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 - f.ano = timezone.now().year - f.data = timezone.now() - f.hora = timezone.now().time() - f.timestamp = timezone.now() - f.assunto_ementa = self.request.POST['assunto'] - - f.save() - self.object = f + protocolo.tipo_processo = '0' # TODO validar o significado + protocolo.anulado = False + protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 + protocolo.ano = timezone.now().year + protocolo.data = timezone.now() + protocolo.hora = timezone.now().time() + protocolo.timestamp = timezone.now() + protocolo.assunto_ementa = self.request.POST['assunto'] + + protocolo.save() + self.object = protocolo return redirect(self.get_success_url()) From cd083f7430e4e88d0d86629aaf3f1948b83373c2 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Tue, 6 Mar 2018 16:23:10 -0300 Subject: [PATCH 038/121] Fix #1735 (#1736) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix protocolação de Materia Legislativa * Fix #1735 * Fix #1735 --- sapl/protocoloadm/forms.py | 2 + sapl/protocoloadm/views.py | 77 +++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 7d00d8090..fbac3cf6c 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -412,6 +412,8 @@ class ProtocoloMateriaForm(ModelForm): if self.is_valid(): if data['vincular_materia'] == 'True': try: + if not data['ano_materia'] or not data['numero_materia']: + raise ValidationError('Favor informar o número e ano da matéria a ser vinculada') self.materia = MateriaLegislativa.objects.get(ano=data['ano_materia'], numero=data['numero_materia'], tipo=data['tipo_materia']) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 47b875753..7c3ea3107 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -277,8 +277,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, kwargs={'pk': self.object.id}) def form_valid(self, form): - f = form.save(commit=False) - + protocolo = form.save(commit=False) try: numeracao = sapl.base.models.AppConfig.objects.last( ).sequencia_numeracao @@ -288,30 +287,36 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, messages.add_message(self.request, messages.ERROR, msg) return self.render_to_response(self.get_context_data()) + tipo = form.cleaned_data['tipo_documento'] + if numeracao == 'A': - numero = Protocolo.objects.filter( - ano=timezone.now().year).aggregate(Max('numero')) + numero = DocumentoAdministrativo.objects.filter( + ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': - legislatura = Legislatura.objects.first() + legislatura = Legislatura.objects.filter( + data_inicio__year__lte=timezone.now().year, + data_fim__year__gte=timezone.now().year).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim - numero = Protocolo.objects.filter( - data__gte=data_inicio, data__lte=data_fim).aggregate( - Max('numero')) + numero = DocumentoAdministrativo.objects.filter( + data__gte=data_inicio, + data__lte=data_fim, + tipo=tipo).aggregate( + Max('numero')) elif numeracao == 'U': - numero = Protocolo.objects.all().aggregate(Max('numero')) - - f.tipo_processo = '0' # TODO validar o significado - f.anulado = False - f.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 - f.ano = timezone.now().year - f.data = timezone.now() - f.hora = timezone.now().time() - f.timestamp = timezone.now() - f.assunto_ementa = self.request.POST['assunto'] - - f.save() - self.object = f + numero = DocumentoAdministrativo.objects.filter(tipo=tipo).aggregate(Max('numero')) + + protocolo.tipo_processo = '0' # TODO validar o significado + protocolo.anulado = False + protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 + protocolo.ano = timezone.now().year + protocolo.data = timezone.now() + protocolo.hora = timezone.now().time() + protocolo.timestamp = timezone.now() + protocolo.assunto_ementa = self.request.POST['assunto'] + + protocolo.save() + self.object = protocolo return redirect(self.get_success_url()) @@ -414,7 +419,6 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): 'pk': protocolo.pk}) def form_valid(self, form): - try: numeracao = sapl.base.models.AppConfig.objects.last( ).sequencia_numeracao @@ -431,17 +435,21 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): numeracao = tipo.sequencia_numeracao if numeracao == 'A': - numero = Protocolo.objects.filter( - ano=timezone.now().year).aggregate(Max('numero')) + numero = MateriaLegislativa.objects.filter( + ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': - legislatura = Legislatura.objects.first() + legislatura = Legislatura.objects.filter( + data_inicio__year__lte=timezone.now().year, + data_fim__year__gte=timezone.now().year).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim - numero = Protocolo.objects.filter( - data__gte=data_inicio, data__lte=data_fim).aggregate( - Max('numero')) + numero = MateriaLegislativa.objects.filter( + data_apresentacao__gte=data_inicio, + data_apresentacao__lte=data_fim, + tipo=tipo).aggregate( + Max('numero')) elif numeracao == 'U': - numero = Protocolo.objects.all().aggregate(Max('numero')) + numero = MateriaLegislativa.objects.filter(tipo=tipo).aggregate(Max('numero')) if numeracao is None: numero['numero__max'] = 0 @@ -469,11 +477,12 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): protocolo.save() data = form.cleaned_data - materia = MateriaLegislativa.objects.get(ano=data['ano_materia'], - numero=data['numero_materia'], - tipo=data['tipo_materia']) - materia.numero_protocolo = protocolo.numero - materia.save() + if data['vincular_materia'] == 'True': + materia = MateriaLegislativa.objects.get(ano=data['ano_materia'], + numero=data['numero_materia'], + tipo=data['tipo_materia']) + materia.numero_protocolo = protocolo.numero + materia.save() return redirect(self.get_success_url(protocolo)) From c6d89324df8873a4c5b55f9f5c9a51af757b583f Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 6 Mar 2018 17:32:00 -0300 Subject: [PATCH 039/121] Release: 3.1.58 --- 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 5c5341afc..2b9a24183 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.57 + image: interlegis/sapl:3.1.58 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 5bac3e202..c3db5a9cd 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.57', + version='3.1.58', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 7effdb1ee26bc848a965fb9aa3f849affffa1796 Mon Sep 17 00:00:00 2001 From: "tapumar@gmail.com" Date: Wed, 7 Mar 2018 10:52:22 -0300 Subject: [PATCH 040/121] Fix protocolo duplicado #1735 --- sapl/protocoloadm/forms.py | 3 ++- sapl/protocoloadm/views.py | 35 +++++++++++++---------------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index fbac3cf6c..4f68478ce 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -372,7 +372,8 @@ class ProtocoloMateriaForm(ModelForm): vincular_materia = forms.ChoiceField(label=_('Vincular a matéria existente?'), widget=forms.RadioSelect(), - choices= YES_NO_CHOICES) + choices= YES_NO_CHOICES, + initial=False) numero_paginas = forms.CharField(label=_('Núm. Páginas'), required=True) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 7c3ea3107..90e4e3726 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -287,24 +287,19 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, messages.add_message(self.request, messages.ERROR, msg) return self.render_to_response(self.get_context_data()) - tipo = form.cleaned_data['tipo_documento'] - if numeracao == 'A': - numero = DocumentoAdministrativo.objects.filter( - ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) + numero = Protocolo.objects.filter( + ano=timezone.now().year).aggregate(Max('numero')) elif numeracao == 'L': - legislatura = Legislatura.objects.filter( - data_inicio__year__lte=timezone.now().year, - data_fim__year__gte=timezone.now().year).first() + legislatura = Legislatura.objects.first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim - numero = DocumentoAdministrativo.objects.filter( + numero = Protocolo.objects.filter( data__gte=data_inicio, - data__lte=data_fim, - tipo=tipo).aggregate( + data__lte=data_fim).aggregate( Max('numero')) elif numeracao == 'U': - numero = DocumentoAdministrativo.objects.filter(tipo=tipo).aggregate(Max('numero')) + numero = Protocolo.objects.filter().aggregate(Max('numero')) protocolo.tipo_processo = '0' # TODO validar o significado protocolo.anulado = False @@ -433,23 +428,19 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): tipo = form.cleaned_data['tipo_materia'] if tipo.sequencia_numeracao: numeracao = tipo.sequencia_numeracao - if numeracao == 'A': - numero = MateriaLegislativa.objects.filter( - ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) + numero = Protocolo.objects.filter( + ano=timezone.now().year).aggregate(Max('numero')) elif numeracao == 'L': - legislatura = Legislatura.objects.filter( - data_inicio__year__lte=timezone.now().year, - data_fim__year__gte=timezone.now().year).first() + legislatura = Legislatura.objects.first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim - numero = MateriaLegislativa.objects.filter( - data_apresentacao__gte=data_inicio, - data_apresentacao__lte=data_fim, - tipo=tipo).aggregate( + numero = Protocolo.objects.filter( + data__gte=data_inicio, + data__lte=data_fim).aggregate( Max('numero')) elif numeracao == 'U': - numero = MateriaLegislativa.objects.filter(tipo=tipo).aggregate(Max('numero')) + numero = Protocolo.objects.filter().aggregate(Max('numero')) if numeracao is None: numero['numero__max'] = 0 From fb37dcff46486c998a67ff98728a6233c8665acb Mon Sep 17 00:00:00 2001 From: "tapumar@gmail.com" Date: Wed, 7 Mar 2018 11:15:45 -0300 Subject: [PATCH 041/121] Fix #1735 --- sapl/protocoloadm/views.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 90e4e3726..19b9dedf3 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -423,11 +423,6 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): messages.add_message(self.request, messages.ERROR, msg) return self.render_to_response(self.get_context_data()) - # Se TipoMateriaLegislativa tem sequencia própria, - # então sobreescreve a sequência global - tipo = form.cleaned_data['tipo_materia'] - if tipo.sequencia_numeracao: - numeracao = tipo.sequencia_numeracao if numeracao == 'A': numero = Protocolo.objects.filter( ano=timezone.now().year).aggregate(Max('numero')) From 1623d50cbc06333467682fd218491ab5a829f6dd Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Wed, 7 Mar 2018 11:21:46 -0300 Subject: [PATCH 042/121] 1735 campo tipo no protocolo materia legislativa (#1737) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix protocolação de Materia Legislativa * Fix #1735 * Fix #1735 * Fix protocolo duplicado #1735 * Fix #1735 --- sapl/protocoloadm/forms.py | 3 ++- sapl/protocoloadm/views.py | 28 +++++++++------------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index fbac3cf6c..4f68478ce 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -372,7 +372,8 @@ class ProtocoloMateriaForm(ModelForm): vincular_materia = forms.ChoiceField(label=_('Vincular a matéria existente?'), widget=forms.RadioSelect(), - choices= YES_NO_CHOICES) + choices= YES_NO_CHOICES, + initial=False) numero_paginas = forms.CharField(label=_('Núm. Páginas'), required=True) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 7c3ea3107..bdc1ef4a3 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -287,10 +287,8 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, messages.add_message(self.request, messages.ERROR, msg) return self.render_to_response(self.get_context_data()) - tipo = form.cleaned_data['tipo_documento'] - if numeracao == 'A': - numero = DocumentoAdministrativo.objects.filter( + numero = Protocolo.objects.filter( ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': legislatura = Legislatura.objects.filter( @@ -298,13 +296,12 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, data_fim__year__gte=timezone.now().year).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim - numero = DocumentoAdministrativo.objects.filter( + numero = Protocolo.objects.filter( data__gte=data_inicio, - data__lte=data_fim, - tipo=tipo).aggregate( + data__lte=data_fim).aggregate( Max('numero')) elif numeracao == 'U': - numero = DocumentoAdministrativo.objects.filter(tipo=tipo).aggregate(Max('numero')) + numero = Protocolo.objects.filter().aggregate(Max('numero')) protocolo.tipo_processo = '0' # TODO validar o significado protocolo.anulado = False @@ -428,14 +425,8 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): messages.add_message(self.request, messages.ERROR, msg) return self.render_to_response(self.get_context_data()) - # Se TipoMateriaLegislativa tem sequencia própria, - # então sobreescreve a sequência global - tipo = form.cleaned_data['tipo_materia'] - if tipo.sequencia_numeracao: - numeracao = tipo.sequencia_numeracao - if numeracao == 'A': - numero = MateriaLegislativa.objects.filter( + numero = Protocolo.objects.filter( ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': legislatura = Legislatura.objects.filter( @@ -443,13 +434,12 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): data_fim__year__gte=timezone.now().year).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim - numero = MateriaLegislativa.objects.filter( - data_apresentacao__gte=data_inicio, - data_apresentacao__lte=data_fim, - tipo=tipo).aggregate( + numero = Protocolo.objects.filter( + data__gte=data_inicio, + data__lte=data_fim).aggregate( Max('numero')) elif numeracao == 'U': - numero = MateriaLegislativa.objects.filter(tipo=tipo).aggregate(Max('numero')) + numero = Protocolo.objects.filter().aggregate(Max('numero')) if numeracao is None: numero['numero__max'] = 0 From b1ad8a107b95a96d7ae2e476341a6f3c9bfe6e5a Mon Sep 17 00:00:00 2001 From: "tapumar@gmail.com" Date: Wed, 7 Mar 2018 12:56:57 -0300 Subject: [PATCH 043/121] Fix --- sapl/protocoloadm/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index bdc1ef4a3..14ba66d0f 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -289,7 +289,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, if numeracao == 'A': numero = Protocolo.objects.filter( - ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) + ano=timezone.now().year).aggregate(Max('numero')) elif numeracao == 'L': legislatura = Legislatura.objects.filter( data_inicio__year__lte=timezone.now().year, @@ -301,7 +301,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, data__lte=data_fim).aggregate( Max('numero')) elif numeracao == 'U': - numero = Protocolo.objects.filter().aggregate(Max('numero')) + numero = Protocolo.objects.all().aggregate(Max('numero')) protocolo.tipo_processo = '0' # TODO validar o significado protocolo.anulado = False @@ -427,7 +427,7 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): if numeracao == 'A': numero = Protocolo.objects.filter( - ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) + ano=timezone.now().year).aggregate(Max('numero')) elif numeracao == 'L': legislatura = Legislatura.objects.filter( data_inicio__year__lte=timezone.now().year, @@ -439,7 +439,7 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): data__lte=data_fim).aggregate( Max('numero')) elif numeracao == 'U': - numero = Protocolo.objects.filter().aggregate(Max('numero')) + numero = Protocolo.objects.all().aggregate(Max('numero')) if numeracao is None: numero['numero__max'] = 0 From ae4dbeec1fc1525bac61961acdefb7bffae1d8bf Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 7 Mar 2018 13:24:41 -0300 Subject: [PATCH 044/121] Release: 3.1.59 --- 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 2b9a24183..7fcc17e1e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.58 + image: interlegis/sapl:3.1.59 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index c3db5a9cd..2361cb90a 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.58', + version='3.1.59', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From b2a96d5132e672a4b65e71efe50d18d4eeb903bb Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Thu, 8 Mar 2018 10:11:24 -0300 Subject: [PATCH 045/121] Mgr TabAux p Yaml e impl sidebar nas CrudAux.ListView --- sapl/base/templatetags/menus.py | 6 +- sapl/compilacao/views.py | 12 +- sapl/crud/base.py | 7 +- sapl/materia/views.py | 31 +-- sapl/sessao/views.py | 6 + sapl/static/styles/app.scss | 74 +++++++ .../compilacao/tipotextoarticulado_list.html | 62 +++--- sapl/templates/crud/detail.html | 4 +- sapl/templates/crud/detail_detail.html | 4 +- sapl/templates/crud/list.html | 15 ++ sapl/templates/crud/list_tabaux.html | 15 ++ sapl/templates/menu_tabelas_auxiliares.yaml | 181 ++++++++++++++++++ sapl/templates/menus/menu.html | 36 ++++ sapl/templates/sistema.html | 160 ++++++++-------- 14 files changed, 487 insertions(+), 126 deletions(-) create mode 100644 sapl/templates/crud/list_tabaux.html create mode 100644 sapl/templates/menu_tabelas_auxiliares.yaml create mode 100644 sapl/templates/menus/menu.html diff --git a/sapl/base/templatetags/menus.py b/sapl/base/templatetags/menus.py index 34294fbd8..92df1e39f 100644 --- a/sapl/base/templatetags/menus.py +++ b/sapl/base/templatetags/menus.py @@ -2,13 +2,17 @@ from django import template from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ import yaml - from sapl.utils import sapl_logger register = template.Library() +@register.inclusion_tag('menus/menu.html', takes_context=True) +def menu(context, path=None): + return nav_run(context, path) + + @register.inclusion_tag('menus/subnav.html', takes_context=True) def subnav(context, path=None): return nav_run(context, path) diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index b24bfd677..250ef70ea 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -48,15 +48,15 @@ from sapl.compilacao.models import (STATUS_TA_EDITION, STATUS_TA_PRIVATE, from sapl.compilacao.utils import (DISPOSITIVO_SELECT_RELATED, DISPOSITIVO_SELECT_RELATED_EDIT, get_integrations_view_names) -from sapl.crud.base import Crud, CrudListView, make_pagination +from sapl.crud.base import Crud, CrudListView, make_pagination, CrudAux from sapl.settings import BASE_DIR -TipoNotaCrud = Crud.build(TipoNota, 'tipo_nota') -TipoVideCrud = Crud.build(TipoVide, 'tipo_vide') -TipoPublicacaoCrud = Crud.build(TipoPublicacao, 'tipo_publicacao') -VeiculoPublicacaoCrud = Crud.build(VeiculoPublicacao, 'veiculo_publicacao') -TipoDispositivoCrud = Crud.build( +TipoNotaCrud = CrudAux.build(TipoNota, 'tipo_nota') +TipoVideCrud = CrudAux.build(TipoVide, 'tipo_vide') +TipoPublicacaoCrud = CrudAux.build(TipoPublicacao, 'tipo_publicacao') +VeiculoPublicacaoCrud = CrudAux.build(VeiculoPublicacao, 'veiculo_publicacao') +TipoDispositivoCrud = CrudAux.build( TipoDispositivo, 'tipo_dispositivo') logger = logging.getLogger(BASE_DIR.name) diff --git a/sapl/crud/base.py b/sapl/crud/base.py index c94820a03..3f20e376b 100644 --- a/sapl/crud/base.py +++ b/sapl/crud/base.py @@ -17,18 +17,20 @@ from django.http.response import Http404 from django.shortcuts import redirect from django.utils.decorators import classonlymethod from django.utils.encoding import force_text -from django.utils.translation import ugettext_lazy as _ from django.utils.translation import string_concat +from django.utils.translation import ugettext_lazy as _ from django.views.generic import (CreateView, DeleteView, DetailView, ListView, UpdateView) from django.views.generic.base import ContextMixin from django.views.generic.list import MultipleObjectMixin + from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL, RP_LIST) from sapl.settings import BASE_DIR from sapl.utils import normalize + logger = logging.getLogger(BASE_DIR.name) ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \ @@ -936,6 +938,9 @@ class CrudAux(Crud): """ permission_required = ('base.view_tabelas_auxiliares',) + class ListView(Crud.ListView): + template_name = "crud/list_tabaux.html" + class BaseMixin(Crud.BaseMixin): subnav_template_name = None diff --git a/sapl/materia/views.py b/sapl/materia/views.py index a5f69a1e0..ebbcca5e5 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -2,8 +2,6 @@ from datetime import datetime from random import choice from string import ascii_letters, digits -import sapl -import weasyprint from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML from django.contrib import messages @@ -24,6 +22,8 @@ from django.views.generic import CreateView, ListView, TemplateView, UpdateView from django.views.generic.base import RedirectView from django.views.generic.edit import FormView from django_filters.views import FilterView +import weasyprint + from sapl.base.models import Autor, CasaLegislativa from sapl.comissoes.models import Comissao, Participacao from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT, @@ -47,6 +47,7 @@ from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label, autor_modal, gerar_hash_arquivo, get_base_url, get_mime_type_from_file_extension, montar_row_autor, show_results_filter_set) +import sapl from .email_utils import do_envia_email_confirmacao from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, @@ -67,9 +68,10 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, TipoProposicao, Tramitacao, UnidadeTramitacao) from .signals import tramitacao_signal -AssuntoMateriaCrud = Crud.build(AssuntoMateria, 'assunto_materia') -OrigemCrud = Crud.build(Origem, '') +AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia') + +OrigemCrud = CrudAux.build(Origem, '') TipoMateriaCrud = CrudAux.build( TipoMateriaLegislativa, 'tipo_materia_legislativa') @@ -308,7 +310,8 @@ def recuperar_materia(request): tipo=tipo).aggregate( Max('numero')) elif numeracao == 'U': - numero = MateriaLegislativa.objects.filter(tipo=tipo).aggregate(Max('numero')) + numero = MateriaLegislativa.objects.filter( + tipo=tipo).aggregate(Max('numero')) if numeracao is None: numero['numero__max'] = 0 @@ -323,10 +326,10 @@ def recuperar_materia(request): StatusTramitacaoCrud = CrudAux.build(StatusTramitacao, 'status_tramitacao') -class OrgaoCrud(Crud): +class OrgaoCrud(CrudAux): model = Orgao - class CreateView(Crud.CreateView): + class CreateView(CrudAux.CreateView): form_class = OrgaoForm @@ -591,11 +594,10 @@ class UnidadeTramitacaoCrud(CrudAux): model = UnidadeTramitacao help_topic = 'unidade_tramitacao' - class BaseMixin(Crud.BaseMixin): + class BaseMixin(CrudAux.BaseMixin): list_field_names = ['comissao', 'orgao', 'parlamentar'] - class ListView(Crud.ListView): - template_name = "crud/list.html" + class ListView(CrudAux.ListView): def get_headers(self): return [_('Unidade de Tramitação')] @@ -841,14 +843,17 @@ class ProposicaoCrud(Crud): obj.data_recebimento = 'Não recebida'\ if obj.data_envio else 'Não enviada' else: - obj.data_recebimento = timezone.localtime(obj.data_recebimento) - obj.data_recebimento = obj.data_recebimento = formats.date_format(obj.data_recebimento, "DATETIME_FORMAT") + obj.data_recebimento = timezone.localtime( + obj.data_recebimento) + obj.data_recebimento = obj.data_recebimento = formats.date_format( + obj.data_recebimento, "DATETIME_FORMAT") if obj.data_envio is None: obj.data_envio = 'Em elaboração...' else: obj.data_envio = timezone.localtime(obj.data_envio) - obj.data_envio = formats.date_format(obj.data_envio, "DATETIME_FORMAT") + obj.data_envio = formats.date_format( + obj.data_envio, "DATETIME_FORMAT") return [self._as_row(obj) for obj in object_list] diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 2b66849a7..ab0f2fec4 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -577,6 +577,9 @@ class OradorCrud(OradorCrud): class BancadaCrud(Crud): model = Bancada + class ListView(Crud.ListView): + template_name = 'crud/list_tabaux.html' + class CreateView(Crud.CreateView): form_class = BancadaForm @@ -587,6 +590,9 @@ class BancadaCrud(Crud): class BlocoCrud(Crud): model = Bloco + class ListView(Crud.ListView): + template_name = 'crud/list_tabaux.html' + class CreateView(Crud.CreateView): form_class = BlocoForm diff --git a/sapl/static/styles/app.scss b/sapl/static/styles/app.scss index 2edac98fc..262b3f45e 100644 --- a/sapl/static/styles/app.scss +++ b/sapl/static/styles/app.scss @@ -481,6 +481,80 @@ p { } /* FIM TEMPLATE AJUDA */ +.container-tabaux { + .sidebar-tabaux { + background: #fafafa; + margin-top: -70px; + padding: 10px; + border: 1px solid #eee; + .navbar-right { + margin: 0; + } + .nav-pills > li + li { + margin-left: 0px; + } + li { + width: 100%; + } + span { + display: none; + } + .dropdown-menu { + padding: 0px; + right: 10px; + margin-top: -5px; + overflow: hidden; + a { + border: 0px; + } + } + } + + ul { + list-style: none; + padding: 0; + } + + .list { + font-family: "SourceSansProSemiBold", Helvetica, Arial, sans-serif; + font-size: 0px; + display: table; + width: 100%; + margin: 0; + + ul { + display: table; + width: 100%; + margin: 0; + } + + li { + width: calc(50%); + display: inline-block; + position: relative; + } + & > li { + width: 100%; + border-bottom: 1px solid #eee; + padding-bottom: 20px; + margin-bottom: 20px; + } + + .head_title { + color: #364347; + font-size: 2.4rem; + text-transform: none; + } + + a { + span { + display: none; + } + } + } +} + + @media (max-width: 1199px) { .masthead { .navbar-brand { diff --git a/sapl/templates/compilacao/tipotextoarticulado_list.html b/sapl/templates/compilacao/tipotextoarticulado_list.html index e89e8afd4..509c9c0d3 100644 --- a/sapl/templates/compilacao/tipotextoarticulado_list.html +++ b/sapl/templates/compilacao/tipotextoarticulado_list.html @@ -1,9 +1,9 @@ {% extends "base.html" %} -{% load i18n %} -{% load compilacao_filters %} -{% load common_tags %} +{% load i18n compilacao_filters common_tags menus%} {% block base_content %} + + {% block actions %} {% if perms.compilacao.add_tipotextoarticulado %}
    @@ -14,27 +14,37 @@ {% endif %} {% endblock actions %} - {% if not object_list %} -

    {{ NO_ENTRIES_MSG }}

    - {% else %} - - - - - - - - - - {% for tipo_ta in object_list %} - - - - - - {% endfor %} - -
    {% fieldclass_verbose_name 'sapl.compilacao.models.TipoTextoArticulado' 'sigla' %}{% fieldclass_verbose_name 'sapl.compilacao.models.TipoTextoArticulado' 'descricao' %}{% fieldclass_verbose_name 'sapl.compilacao.models.TipoTextoArticulado' 'content_type' %}
    {{ tipo_ta.sigla }}{{ tipo_ta.descricao }}{{ tipo_ta.content_type }}
    - {%endif%} - {% include 'paginacao.html'%} +
    +
    + {% if not object_list %} +

    {{ NO_ENTRIES_MSG }}

    + {% else %} + + + + + + + + + + {% for tipo_ta in object_list %} + + + + + + {% endfor %} + +
    {% fieldclass_verbose_name 'sapl.compilacao.models.TipoTextoArticulado' 'sigla' %}{% fieldclass_verbose_name 'sapl.compilacao.models.TipoTextoArticulado' 'descricao' %}{% fieldclass_verbose_name 'sapl.compilacao.models.TipoTextoArticulado' 'content_type' %}
    {{ tipo_ta.sigla }}{{ tipo_ta.descricao }}{{ tipo_ta.content_type }}
    + {%endif%} + {% include 'paginacao.html'%} +
    + {% if perms.base.menu_tabelas_auxiliares %} + + {% endif %} +
    {% endblock %} diff --git a/sapl/templates/crud/detail.html b/sapl/templates/crud/detail.html index 8087b458b..4a1cad276 100644 --- a/sapl/templates/crud/detail.html +++ b/sapl/templates/crud/detail.html @@ -23,8 +23,8 @@
    {% if view.extras_url %}
    - {% for url, css_class, text in view.extras_url %} - + {% for href, css_class, text in view.extras_url %} + {{text}} {% endfor %} diff --git a/sapl/templates/crud/detail_detail.html b/sapl/templates/crud/detail_detail.html index cb0b103ec..b2312ec51 100644 --- a/sapl/templates/crud/detail_detail.html +++ b/sapl/templates/crud/detail_detail.html @@ -20,8 +20,8 @@
    {% if view.extras_url %}
    - {% for url, css_class, text in view.extras_url %} - + {% for href, css_class, text in view.extras_url %} + {{text}} {% endfor %} diff --git a/sapl/templates/crud/list.html b/sapl/templates/crud/list.html index 3789761fc..b1743516d 100644 --- a/sapl/templates/crud/list.html +++ b/sapl/templates/crud/list.html @@ -20,7 +20,22 @@ {% block more_buttons %}{% endblock more_buttons %}
    {% endblock actions %} + + {% block extra_actions %}{% endblock extra_actions %} + + {% comment %} + {% if view.extras_url %} +
    + {% for href, css_class, text in view.extras_url %} + + {{text}} + + {% endfor %} +
    + {% endif %} + {% endcomment %} + {% block extra_content %} {% endblock %} {% block container_table_list %} diff --git a/sapl/templates/crud/list_tabaux.html b/sapl/templates/crud/list_tabaux.html new file mode 100644 index 000000000..77c81f651 --- /dev/null +++ b/sapl/templates/crud/list_tabaux.html @@ -0,0 +1,15 @@ +{% extends "crud/list.html" %} +{% load i18n menus%} +{% block base_content %} +
    +
    + {{block.super}} +
    + {% if perms.base.menu_tabelas_auxiliares %} + + {% endif %} +
    +{% endblock base_content %} diff --git a/sapl/templates/menu_tabelas_auxiliares.yaml b/sapl/templates/menu_tabelas_auxiliares.yaml new file mode 100644 index 000000000..3e99fb877 --- /dev/null +++ b/sapl/templates/menu_tabelas_auxiliares.yaml @@ -0,0 +1,181 @@ +{% load i18n common_tags %} +- title: {% trans 'Configurações Gerais' %} + css_class: head_title + children: + - title: {% trans 'Casa Legislativa' %} + url: sapl.base:casalegislativa_list + css_class: btn btn-link + - title: {% trans 'Configurações da Aplicação' %} + url: sapl.base:appconfig_list + css_class: btn btn-link' + - title: {% trans 'Autor' %} + url: sapl.base:autor_list + css_class: btn btn-link + - title: {% trans 'Tipo de Autor' %} + url: sapl.base:tipoautor_list + css_class: btn btn-link +- title: {% trans 'Módulo Parlamentares' %} + css_class: head_title + children: + - title: {% trans 'Legislatura' %} + url: sapl.parlamentares:legislatura_list + css_class: btn btn-link + - title: {% trans 'Tipo de Afastamento' %} + url: sapl.parlamentares:tipoafastamento_list + css_class: btn btn-link + - title: {% trans 'Tipo de Dependente' %} + url: sapl.parlamentares:tipodependente_list + css_class: btn btn-link + - title: {% trans 'Tipo de Situação Militar' %} + url: sapl.parlamentares:situacaomilitar_list + css_class: btn btn-link + - title: {% trans 'Nível de Instrução' %} + url: sapl.parlamentares:nivelinstrucao_list + css_class: btn btn-link + - title: {% trans 'Partido' %} + url: sapl.parlamentares:partido_list + css_class: btn btn-link + - title: {% trans 'Coligação' %} + url: sapl.parlamentares:coligacao_list + css_class: btn btn-link +- title: {% trans 'Módulo Mesa Diretora' %} + css_class: head_title + children: + - title: {% trans 'Sessão Legislativa' %} + url: sapl.parlamentares:sessaolegislativa_list + css_class: btn btn-link + - title: {% trans 'Cargo da Mesa' %} + url: sapl.parlamentares:cargomesa_list + css_class: btn btn-link +- title: {% trans 'Módulo Comissões' %} + css_class: head_title + children: + - title: {% trans 'Cargo de Comissão' %} + url: sapl.comissoes:cargocomissao_list + css_class: btn btn-link + - title: {% trans 'Período de Composição' %} + url: sapl.comissoes:periodo_list + css_class: btn btn-link + - title: {% trans 'Tipo de Comissão' %} + url: sapl.comissoes:tipocomissao_list + css_class: btn btn-link +- title: {% trans 'Módulo Bancadas Parlamentares' %} + css_class: head_title + children: + - title: {% trans 'Bancadas Parlamentares' %} + url: sapl.sessao:bancada_list + css_class: btn btn-link + - title: {% trans 'Cargo de Bancada Parlamentar' %} + url: sapl.sessao:cargobancada_list + css_class: btn btn-link + - title: {% trans 'Frente Parlamentar' %} + url: sapl.parlamentares:frente_list + css_class: btn btn-link + - title: {% trans 'Bloco Parlamentar' %} + url: sapl.sessao:bloco_list + css_class: btn btn-link +- title: {% trans 'Módulo Proposições' %} + css_class: head_title + children: + - title: {% trans 'Tipo de Proposição' %} + url: sapl.materia:tipoproposicao_list + css_class: btn btn-link +- title: {% trans 'Módulo Matéria Legislativa' %} + css_class: head_title + children: + - title: {% trans 'Tipo de Matéria Legislativa' %} + url: sapl.materia:tipomaterialegislativa_list + css_class: btn btn-link + - title: {% trans 'Regime de Tramitação' %} + url: sapl.materia:regimetramitacao_list + css_class: btn btn-link + - title: {% trans 'Tipo de Documento' %} + url: sapl.materia:tipodocumento_list + css_class: btn btn-link + - title: {% trans 'Tipo de fim de Relatoria' %} + url: sapl.materia:tipofimrelatoria_list + css_class: btn btn-link + - title: {% trans 'Unidade de Tramitação' %} + url: sapl.materia:unidadetramitacao_list + css_class: btn btn-link + - title: {% trans 'Origem' %} + url: sapl.materia:origem_list + css_class: btn btn-link + - title: {% trans 'Status da Tramitação' %} + url: sapl.materia:statustramitacao_list + css_class: btn btn-link + - title: {% trans 'Órgão' %} + url: sapl.materia:orgao_list + css_class: btn btn-link + - title: {% trans 'Assunto Matéria' %} + url: sapl.materia:assuntomateria_list + css_class: btn btn-link +- title: {% trans 'Módulo Normas Jurídicas' %} + css_class: head_title + children: + - title: {% trans 'Tipo de Norma Jurídica' %} + url: sapl.norma:tiponormajuridica_list + css_class: btn btn-link + - title: {% trans 'Assunto de Norma Jurídica' %} + url: sapl.norma:assuntonorma_list + css_class: btn btn-link + - title: {% trans 'Tipo de Vínculo' %} + url: sapl.norma:tipovinculonormajuridica_list + css_class: btn btn-link +- title: {% trans 'Módulo Textos Articulados' %} + css_class: head_title + children: + - title: {% trans 'Tipos de Textos Articulados' %} + url: sapl.compilacao:tipo_ta_list + css_class: btn btn-link + - title: {% trans 'Tipos de Publicação' %} + url: sapl.compilacao:tipopublicacao_list + css_class: btn btn-link + - title: {% trans 'Veículos de Publicação' %} + url: sapl.compilacao:veiculopublicacao_list + css_class: btn btn-link + - title: {% trans 'Tipos de Notas' %} + url: sapl.compilacao:tiponota_list + css_class: btn btn-link + - title: {% trans 'Tipos de Vides' %} + url: sapl.compilacao:tipovide_list + css_class: btn btn-link + - title: {% trans 'Tipos de Dispositivos' %} + url: sapl.compilacao:tipodispositivo_list + css_class: btn btn-link + - title: {% trans 'Relacionamento entre Dispositivos' %} + url: /admin/compilacao/tipodispositivorelationship/ + css_class: btn btn-link +- title: {% trans 'Módulo Sessão Plenária' %} + css_class: head_title + children: + - title: {% trans 'Tipo de Sessão Plenária' %} + url: sapl.sessao:tiposessaoplenaria_list + css_class: btn btn-link + - title: {% trans 'Tipo de Resultado da Votação' %} + url: sapl.sessao:tiporesultadovotacao_list + css_class: btn btn-link + - title: {% trans 'Tipo de Expediente' %} + url: sapl.sessao:tipoexpediente_list + css_class: btn btn-link + - title: {% trans 'Ordenação do Resumo' %} + url: sapl.sessao:resumo_ordenacao + css_class: btn btn-link +- title: {% trans 'Módulo LexML' %} + css_class: head_title + children: + - title: {% trans 'Provedor' %} + url: sapl.lexml:lexmlprovedor_list + css_class: btn btn-link + - title: {% trans 'Publicador' %} + url: sapl.lexml:lexmlpublicador_list + css_class: btn btn-link +- title: {% trans 'Módulo Administrativo' %} + css_class: head_title + children: + - title: {% trans 'Tipo de Documento' %} + url: sapl.protocoloadm:tipodocumentoadministrativo_list + css_class: btn btn-link + - title: {% trans 'Status de Tramitação' %} + url: sapl.protocoloadm:statustramitacaoadministrativo_list + css_class: btn btn-link diff --git a/sapl/templates/menus/menu.html b/sapl/templates/menus/menu.html new file mode 100644 index 000000000..9b0a086f4 --- /dev/null +++ b/sapl/templates/menus/menu.html @@ -0,0 +1,36 @@ +{% load i18n %} +{% if menu %} + {% for item in menu %} + {% if item.children %} +
  • + {% if item.url %} + + {{ item.title|safe }} + + + {% else %} + + {{ item.title|safe }} + + {% endif %} +
      + {% with item.children as menu %} + {% include "menus/menu.html" %} + {% endwith %} +
    +
  • + {% else %} +
  • + {% if item.url %} + + {{ item.title|safe }} + + {% else %} + + {{ item.title|safe }} + + {% endif %} +
  • + {% endif %} + {% endfor %} +{% endif %} diff --git a/sapl/templates/sistema.html b/sapl/templates/sistema.html index 643c38a9b..8e3882369 100644 --- a/sapl/templates/sistema.html +++ b/sapl/templates/sistema.html @@ -1,115 +1,125 @@ {% extends "base.html" %} -{% load i18n crispy_forms_tags %} +{% load i18n crispy_forms_tags menus%} {% block base_content %} -

    Configurações Gerais

    - +
    +
      + {% menu 'menu_tabelas_auxiliares.yaml'%} +
    + +
    + + {% comment %} + +

    Configurações Gerais

    +

    Módulo Parlamentares

    - +

    Módulo Mesa Diretora

    - +

    Módulo Comissões

    - +

    Módulo Bancadas Parlamentares

    - +

    Módulo Proposições

    - +

    Módulo Matéria Legislativa

    - +

    Módulo Normas Jurídicas

    - + -
    +

    Módulo Textos Articulados

    - +

    Módulo Sessão Plenária

    - +

    Módulo LexML

    - +

    Módulo Administrativo

    - + + {% endcomment %} {% endblock base_content %} From e5a95e8de39255128d3e248233eb43bb860860d7 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Thu, 8 Mar 2018 13:56:35 -0300 Subject: [PATCH 046/121] ajusta urls ao exigido em test_urls --- sapl/compilacao/urls.py | 30 +++++++++++++++--------------- sapl/test_urls.py | 7 +++++-- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/sapl/compilacao/urls.py b/sapl/compilacao/urls.py index 69b6fd654..decbd5578 100644 --- a/sapl/compilacao/urls.py +++ b/sapl/compilacao/urls.py @@ -98,31 +98,31 @@ urlpatterns_compilacao = [ views.PublicacaoDeleteView.as_view(), name='ta_pub_delete'), - url(r'^config/tipo-textoarticulado$', - views.TipoTaListView.as_view(), name='tipo_ta_list'), - url(r'^config/tipo-textoarticulado/create$', - views.TipoTaCreateView.as_view(), name='tipo_ta_create'), - url(r'^config/tipo-textoarticulado/(?P[0-9]+)$', - views.TipoTaDetailView.as_view(), name='tipo_ta_detail'), - url(r'^config/tipo-textoarticulado/(?P[0-9]+)/edit$', - views.TipoTaUpdateView.as_view(), name='tipo_ta_edit'), - url(r'^config/tipo-textoarticulado/(?P[0-9]+)/delete$', - views.TipoTaDeleteView.as_view(), name='tipo_ta_delete'), ] urlpatterns = [ url(r'^ta/', include(urlpatterns_compilacao)), - url(r'^ta/config/tipo-nota/', + url(r'^sistema/ta/config/tipo-nota/', include(TipoNotaCrud.get_urls())), - url(r'^ta/config/tipo-vide/', + url(r'^sistema/ta/config/tipo-vide/', include(TipoVideCrud.get_urls())), - url(r'^ta/config/tipo-publicacao/', + url(r'^sistema/ta/config/tipo-publicacao/', include(TipoPublicacaoCrud.get_urls())), - url(r'^ta/config/veiculo-publicacao/', + url(r'^sistema/ta/config/veiculo-publicacao/', include(VeiculoPublicacaoCrud.get_urls())), - url(r'^ta/config/tipo-dispositivo/', + url(r'^sistema/ta/config/tipo-dispositivo/', include(TipoDispositivoCrud.get_urls())), + url(r'^sistema/ta/config/tipo-textoarticulado$', + views.TipoTaListView.as_view(), name='tipo_ta_list'), + url(r'^sistema/ta/config/tipo-textoarticulado/create$', + views.TipoTaCreateView.as_view(), name='tipo_ta_create'), + url(r'^sistema/ta/config/tipo-textoarticulado/(?P[0-9]+)$', + views.TipoTaDetailView.as_view(), name='tipo_ta_detail'), + url(r'^sistema/ta/config/tipo-textoarticulado/(?P[0-9]+)/edit$', + views.TipoTaUpdateView.as_view(), name='tipo_ta_edit'), + url(r'^sistema/ta/config/tipo-textoarticulado/(?P[0-9]+)/delete$', + views.TipoTaDeleteView.as_view(), name='tipo_ta_delete'), ] diff --git a/sapl/test_urls.py b/sapl/test_urls.py index 9df5900ee..9c462fc19 100644 --- a/sapl/test_urls.py +++ b/sapl/test_urls.py @@ -1,18 +1,20 @@ -import pytest from django.apps import apps from django.contrib.auth import get_user_model from django.contrib.auth.management import _get_all_permissions from django.contrib.auth.models import Permission 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 django.utils.translation import ugettext_lazy as _ +import pytest + from sapl.crud.base import PermissionRequiredForAppCrudMixin from sapl.rules.apps import AppConfig, update_groups from scripts.lista_urls import lista_urls from .settings import SAPL_APPS + pytestmark = pytest.mark.django_db sapl_appconfs = [apps.get_app_config(n[5:]) for n in SAPL_APPS] @@ -171,6 +173,7 @@ apps_url_patterns_prefixs_and_users = { 'compilacao': { 'prefixs': [ '/ta', + '/sistema/ta', ]}, 'redireciona_urls': { 'prefixs': [ From b61e65f8121b1fe8110136b72a4c557ac4c638be Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Thu, 8 Mar 2018 15:08:46 -0300 Subject: [PATCH 047/121] =?UTF-8?q?corrige=20importa=C3=A7=C3=A3o=20de=20v?= =?UTF-8?q?ari=C3=A1vel=20de=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/materia/admin.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sapl/materia/admin.py b/sapl/materia/admin.py index 65b754817..6ffebda25 100644 --- a/sapl/materia/admin.py +++ b/sapl/materia/admin.py @@ -1,17 +1,19 @@ +from django.conf import settings from django.contrib import admin -from sapl.materia.models import Proposicao, TipoMateriaLegislativa + from sapl.base.models import TipoAutor from sapl.comissoes.models import TipoComissao -from sapl.parlamentares.models import TipoAfastamento, SituacaoMilitar, TipoDependente +from sapl.materia.models import Proposicao, TipoMateriaLegislativa from sapl.norma.models import TipoNormaJuridica, TipoVinculoNormaJuridica -from sapl.sessao.models import TipoSessaoPlenaria, TipoExpediente, TipoResultadoVotacao +from sapl.parlamentares.models import TipoAfastamento, SituacaoMilitar, TipoDependente from sapl.protocoloadm.models import TipoDocumentoAdministrativo -from sapl.settings import DEBUG +from sapl.sessao.models import TipoSessaoPlenaria, TipoExpediente, TipoResultadoVotacao from sapl.utils import register_all_models_in_admin + register_all_models_in_admin(__name__) -if not DEBUG: +if not settings.DEBUG: admin.site.unregister(Proposicao) admin.site.unregister(TipoAutor) @@ -20,7 +22,6 @@ if not DEBUG: admin.site.unregister(SituacaoMilitar) admin.site.unregister(TipoDependente) - class RestricaoAdmin(admin.ModelAdmin): def has_add_permission(self, request, obj=None): @@ -32,7 +33,6 @@ if not DEBUG: def has_delete_permission(self, request, obj=None): return False - admin.site.register(Proposicao, RestricaoAdmin) admin.site.register(TipoAutor, RestricaoAdmin) admin.site.register(TipoComissao, RestricaoAdmin) From abab47e17cfbce15c82de4596a624b790dec6713 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Thu, 8 Mar 2018 16:50:11 -0300 Subject: [PATCH 048/121] corrige admin p/ sapl func c/ app externa em outros projetos --- sapl/materia/admin.py | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/sapl/materia/admin.py b/sapl/materia/admin.py index 6ffebda25..25c107378 100644 --- a/sapl/materia/admin.py +++ b/sapl/materia/admin.py @@ -3,11 +3,9 @@ from django.contrib import admin from sapl.base.models import TipoAutor from sapl.comissoes.models import TipoComissao -from sapl.materia.models import Proposicao, TipoMateriaLegislativa -from sapl.norma.models import TipoNormaJuridica, TipoVinculoNormaJuridica -from sapl.parlamentares.models import TipoAfastamento, SituacaoMilitar, TipoDependente -from sapl.protocoloadm.models import TipoDocumentoAdministrativo -from sapl.sessao.models import TipoSessaoPlenaria, TipoExpediente, TipoResultadoVotacao +from sapl.materia.models import Proposicao +from sapl.parlamentares.models import TipoAfastamento, SituacaoMilitar, \ + TipoDependente from sapl.utils import register_all_models_in_admin @@ -15,13 +13,6 @@ register_all_models_in_admin(__name__) if not settings.DEBUG: - admin.site.unregister(Proposicao) - admin.site.unregister(TipoAutor) - admin.site.unregister(TipoComissao) - admin.site.unregister(TipoAfastamento) - admin.site.unregister(SituacaoMilitar) - admin.site.unregister(TipoDependente) - class RestricaoAdmin(admin.ModelAdmin): def has_add_permission(self, request, obj=None): @@ -33,9 +24,16 @@ if not settings.DEBUG: def has_delete_permission(self, request, obj=None): return False - admin.site.register(Proposicao, RestricaoAdmin) - admin.site.register(TipoAutor, RestricaoAdmin) - admin.site.register(TipoComissao, RestricaoAdmin) - admin.site.register(TipoAfastamento, RestricaoAdmin) - admin.site.register(SituacaoMilitar, RestricaoAdmin) - admin.site.register(TipoDependente, RestricaoAdmin) + models = ( + Proposicao, + TipoAutor, + TipoComissao, + TipoAfastamento, + SituacaoMilitar, + TipoDependente + ) + + for model in models: + if admin.site.is_registered(model): + admin.site.unregister(model) + admin.site.register(model, RestricaoAdmin) From e7c1aa587929115a96f174d78ae3fe2b7ef99532 Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Fri, 9 Mar 2018 08:47:52 -0300 Subject: [PATCH 049/121] Fix #1566 (#1739) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adiciona a model, forms e views da reunião de comissão * Adiciona telas de cadastro de reunião * Adiciona layouts e legacy * Adiciona template, modifica o subnav e o ListView * Troca Crud por MasterCrudDetail * Adiciona template de cadastro de reunião * Corrige Createview e Listview * Ajusta comissoes * Corrige o deleteview e o detailview * Muda o layout do create de reunião * - Retira o campo tipo de cadastro de reunião - Retira a obrigatoriedade do campo tema * Corrige migração --- sapl/comissoes/forms.py | 18 ++++-------- sapl/comissoes/legacy.yaml | 1 - .../migrations/0010_auto_20180307_1645.py | 29 +++++++++++++++++++ sapl/comissoes/migrations/0011_merge.py | 16 ++++++++++ sapl/comissoes/models.py | 12 ++------ sapl/materia/forms.py | 1 + sapl/templates/comissoes/layouts.yaml | 5 ++-- sapl/templates/comissoes/subnav.yaml | 1 + 8 files changed, 58 insertions(+), 25 deletions(-) create mode 100644 sapl/comissoes/migrations/0010_auto_20180307_1645.py create mode 100644 sapl/comissoes/migrations/0011_merge.py diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index 33be2003d..a3414e755 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -10,6 +10,7 @@ from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar + class ParticipacaoCreateForm(forms.ModelForm): parent_pk = forms.CharField(required=False) # widget=forms.HiddenInput()) @@ -154,20 +155,13 @@ class ReuniaoForm(ModelForm): class Meta: model = Reuniao exclude = ['cod_andamento_reuniao'] - widgets = { - 'hora_fim': forms.TimeInput(format='%H:%M'), - 'hora_inicio': forms.TimeInput(format='%H:%M'), - } def clean(self): super(ReuniaoForm, self).clean() - if self.errors: - return - - if self.cleaned_data['hora_fim'] < self.cleaned_data['hora_inicio']: - msg = _('A hora de término da reunião não pode ' - 'ser menor que a de início') - raise ValidationError(msg) - + if self.cleaned_data['hora_fim']: + if (self.cleaned_data['hora_fim'] < + self.cleaned_data['hora_inicio']): + msg = _('A hora de término da reunião não pode ser menor que a de início') + raise ValidationError(msg) return self.cleaned_data diff --git a/sapl/comissoes/legacy.yaml b/sapl/comissoes/legacy.yaml index 2414df885..59aacf503 100644 --- a/sapl/comissoes/legacy.yaml +++ b/sapl/comissoes/legacy.yaml @@ -47,7 +47,6 @@ Participacao (ComposicaoComissao): Reuniao: periodo: periodo_reuniao comissao: cod_comissao - tipo: tipo_comissao numero: num_comissao nome: nom_reuniao tema: tem_reuniao diff --git a/sapl/comissoes/migrations/0010_auto_20180307_1645.py b/sapl/comissoes/migrations/0010_auto_20180307_1645.py new file mode 100644 index 000000000..45b86bec4 --- /dev/null +++ b/sapl/comissoes/migrations/0010_auto_20180307_1645.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-07 19:45 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0009_auto_20180301_1011'), + ] + + operations = [ + migrations.RemoveField( + model_name='reuniao', + name='tipo', + ), + migrations.AlterField( + model_name='reuniao', + name='nome', + field=models.CharField(max_length=150, verbose_name='Nome da Reunião'), + ), + migrations.AlterField( + model_name='reuniao', + name='tema', + field=models.CharField(blank=True, max_length=150, verbose_name='Tema da Reunião'), + ), + ] diff --git a/sapl/comissoes/migrations/0011_merge.py b/sapl/comissoes/migrations/0011_merge.py new file mode 100644 index 000000000..a5a3c7b7a --- /dev/null +++ b/sapl/comissoes/migrations/0011_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-09 10:27 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0010_auto_20180307_1645'), + ('comissoes', '0010_auto_20180306_0918'), + ] + + operations = [ + ] diff --git a/sapl/comissoes/models.py b/sapl/comissoes/models.py index 882fe8638..ed3cd3e50 100644 --- a/sapl/comissoes/models.py +++ b/sapl/comissoes/models.py @@ -182,15 +182,13 @@ class Participacao(models.Model): # ComposicaoComissao def get_comissao_media_path(instance, subpath, filename): return './sapl/comissao/%s/%s/%s' % (instance.numero, subpath, filename) - def pauta_upload_path(instance, filename): - return texto_upload_path(instance, filename, subpath='pauta', pk_first=True) + return texto_upload_path(instance, filename, subpath='pauta', pk_first=True) def ata_upload_path(instance, filename): return texto_upload_path(instance, filename, subpath='ata', pk_first=True) - def anexo_upload_path(instance, filename): return texto_upload_path(instance, filename, subpath='anexo', pk_first=True) @@ -204,15 +202,11 @@ class Reuniao(models.Model): Comissao, on_delete=models.PROTECT, verbose_name=_('Comissão')) - tipo = models.ForeignKey( - TipoComissao, - on_delete=models.PROTECT, - verbose_name=_('Tipo de Comissão')) numero = models.PositiveIntegerField(verbose_name=_('Número')) nome = models.CharField( - max_length=100, verbose_name=_('Nome da Reunião')) + max_length=150, verbose_name=_('Nome da Reunião')) tema = models.CharField( - max_length=100, verbose_name=_('Tema da Reunião')) + max_length=150, blank=True, verbose_name=_('Tema da Reunião')) data = models.DateField(verbose_name=_('Data')) hora_inicio = models.TimeField( verbose_name=_('Horário de Início (hh:mm)')) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 1eebd5c7d..b6d74e970 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1265,6 +1265,7 @@ class ProposicaoForm(forms.ModelForm): inst.texto_original.delete() self.gerar_hash(inst, receber_recibo) + return super().save(commit) inst.ano = timezone.now().year diff --git a/sapl/templates/comissoes/layouts.yaml b/sapl/templates/comissoes/layouts.yaml index 231477a9c..5d0026ba2 100644 --- a/sapl/templates/comissoes/layouts.yaml +++ b/sapl/templates/comissoes/layouts.yaml @@ -46,11 +46,10 @@ ParticipacaoEdit: Reuniao: {% trans 'Reunião' %}: - - periodo numero tipo + - periodo numero - nome tema local_reuniao - data hora_inicio hora_fim - url_video url_audio - observacao - upload_pauta upload_ata upload_anexo - - comissao - + - comissao \ No newline at end of file diff --git a/sapl/templates/comissoes/subnav.yaml b/sapl/templates/comissoes/subnav.yaml index 01c10b4f3..e7e49837b 100644 --- a/sapl/templates/comissoes/subnav.yaml +++ b/sapl/templates/comissoes/subnav.yaml @@ -8,3 +8,4 @@ url: materias_em_tramitacao - title: {% trans 'Reunião' %} url: reuniao_list + From bcc7344876db7e6e8fdfcec5ced13bf46ca2ecf2 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Fri, 9 Mar 2018 10:31:32 -0300 Subject: [PATCH 050/121] Revert "Fix #1566 (#1739)" This reverts commit e7c1aa587929115a96f174d78ae3fe2b7ef99532. --- sapl/comissoes/forms.py | 18 ++++++++---- sapl/comissoes/legacy.yaml | 1 + .../migrations/0010_auto_20180307_1645.py | 29 ------------------- sapl/comissoes/migrations/0011_merge.py | 16 ---------- sapl/comissoes/models.py | 12 ++++++-- sapl/materia/forms.py | 1 - sapl/templates/comissoes/layouts.yaml | 5 ++-- sapl/templates/comissoes/subnav.yaml | 1 - 8 files changed, 25 insertions(+), 58 deletions(-) delete mode 100644 sapl/comissoes/migrations/0010_auto_20180307_1645.py delete mode 100644 sapl/comissoes/migrations/0011_merge.py diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index a3414e755..33be2003d 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -10,7 +10,6 @@ from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar - class ParticipacaoCreateForm(forms.ModelForm): parent_pk = forms.CharField(required=False) # widget=forms.HiddenInput()) @@ -155,13 +154,20 @@ class ReuniaoForm(ModelForm): class Meta: model = Reuniao exclude = ['cod_andamento_reuniao'] + widgets = { + 'hora_fim': forms.TimeInput(format='%H:%M'), + 'hora_inicio': forms.TimeInput(format='%H:%M'), + } def clean(self): super(ReuniaoForm, self).clean() - if self.cleaned_data['hora_fim']: - if (self.cleaned_data['hora_fim'] < - self.cleaned_data['hora_inicio']): - msg = _('A hora de término da reunião não pode ser menor que a de início') - raise ValidationError(msg) + if self.errors: + return + + if self.cleaned_data['hora_fim'] < self.cleaned_data['hora_inicio']: + msg = _('A hora de término da reunião não pode ' + 'ser menor que a de início') + raise ValidationError(msg) + return self.cleaned_data diff --git a/sapl/comissoes/legacy.yaml b/sapl/comissoes/legacy.yaml index 59aacf503..2414df885 100644 --- a/sapl/comissoes/legacy.yaml +++ b/sapl/comissoes/legacy.yaml @@ -47,6 +47,7 @@ Participacao (ComposicaoComissao): Reuniao: periodo: periodo_reuniao comissao: cod_comissao + tipo: tipo_comissao numero: num_comissao nome: nom_reuniao tema: tem_reuniao diff --git a/sapl/comissoes/migrations/0010_auto_20180307_1645.py b/sapl/comissoes/migrations/0010_auto_20180307_1645.py deleted file mode 100644 index 45b86bec4..000000000 --- a/sapl/comissoes/migrations/0010_auto_20180307_1645.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.13 on 2018-03-07 19:45 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('comissoes', '0009_auto_20180301_1011'), - ] - - operations = [ - migrations.RemoveField( - model_name='reuniao', - name='tipo', - ), - migrations.AlterField( - model_name='reuniao', - name='nome', - field=models.CharField(max_length=150, verbose_name='Nome da Reunião'), - ), - migrations.AlterField( - model_name='reuniao', - name='tema', - field=models.CharField(blank=True, max_length=150, verbose_name='Tema da Reunião'), - ), - ] diff --git a/sapl/comissoes/migrations/0011_merge.py b/sapl/comissoes/migrations/0011_merge.py deleted file mode 100644 index a5a3c7b7a..000000000 --- a/sapl/comissoes/migrations/0011_merge.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.13 on 2018-03-09 10:27 -from __future__ import unicode_literals - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('comissoes', '0010_auto_20180307_1645'), - ('comissoes', '0010_auto_20180306_0918'), - ] - - operations = [ - ] diff --git a/sapl/comissoes/models.py b/sapl/comissoes/models.py index ed3cd3e50..882fe8638 100644 --- a/sapl/comissoes/models.py +++ b/sapl/comissoes/models.py @@ -182,13 +182,15 @@ class Participacao(models.Model): # ComposicaoComissao def get_comissao_media_path(instance, subpath, filename): return './sapl/comissao/%s/%s/%s' % (instance.numero, subpath, filename) -def pauta_upload_path(instance, filename): +def pauta_upload_path(instance, filename): return texto_upload_path(instance, filename, subpath='pauta', pk_first=True) + def ata_upload_path(instance, filename): return texto_upload_path(instance, filename, subpath='ata', pk_first=True) + def anexo_upload_path(instance, filename): return texto_upload_path(instance, filename, subpath='anexo', pk_first=True) @@ -202,11 +204,15 @@ class Reuniao(models.Model): Comissao, on_delete=models.PROTECT, verbose_name=_('Comissão')) + tipo = models.ForeignKey( + TipoComissao, + on_delete=models.PROTECT, + verbose_name=_('Tipo de Comissão')) numero = models.PositiveIntegerField(verbose_name=_('Número')) nome = models.CharField( - max_length=150, verbose_name=_('Nome da Reunião')) + max_length=100, verbose_name=_('Nome da Reunião')) tema = models.CharField( - max_length=150, blank=True, verbose_name=_('Tema da Reunião')) + max_length=100, verbose_name=_('Tema da Reunião')) data = models.DateField(verbose_name=_('Data')) hora_inicio = models.TimeField( verbose_name=_('Horário de Início (hh:mm)')) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index b6d74e970..1eebd5c7d 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1265,7 +1265,6 @@ class ProposicaoForm(forms.ModelForm): inst.texto_original.delete() self.gerar_hash(inst, receber_recibo) - return super().save(commit) inst.ano = timezone.now().year diff --git a/sapl/templates/comissoes/layouts.yaml b/sapl/templates/comissoes/layouts.yaml index 5d0026ba2..231477a9c 100644 --- a/sapl/templates/comissoes/layouts.yaml +++ b/sapl/templates/comissoes/layouts.yaml @@ -46,10 +46,11 @@ ParticipacaoEdit: Reuniao: {% trans 'Reunião' %}: - - periodo numero + - periodo numero tipo - nome tema local_reuniao - data hora_inicio hora_fim - url_video url_audio - observacao - upload_pauta upload_ata upload_anexo - - comissao \ No newline at end of file + - comissao + diff --git a/sapl/templates/comissoes/subnav.yaml b/sapl/templates/comissoes/subnav.yaml index e7e49837b..01c10b4f3 100644 --- a/sapl/templates/comissoes/subnav.yaml +++ b/sapl/templates/comissoes/subnav.yaml @@ -8,4 +8,3 @@ url: materias_em_tramitacao - title: {% trans 'Reunião' %} url: reuniao_list - From f1d63c5b1bdccb5b730890e5e23ae8fbd062b373 Mon Sep 17 00:00:00 2001 From: Edward Date: Fri, 9 Mar 2018 14:34:39 -0300 Subject: [PATCH 051/121] =?UTF-8?q?[N=C3=83O=20FA=C3=87A=20MERGE=20AINDA]?= =?UTF-8?q?=20Fix=20#1725=20(#1740)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #1725 - Adiciona tela de admin ao SAPL --- sapl/base/forms.py | 96 ++++++++++++++++++++++- sapl/base/urls.py | 12 ++- sapl/base/views.py | 119 ++++++++++++++++++++++++++++- sapl/templates/auth/user_form.html | 14 ++++ sapl/templates/auth/user_list.html | 33 ++++++++ sapl/templates/navbar.yaml | 2 +- 6 files changed, 269 insertions(+), 7 deletions(-) create mode 100644 sapl/templates/auth/user_form.html create mode 100644 sapl/templates/auth/user_list.html diff --git a/sapl/base/forms.py b/sapl/base/forms.py index cdc6d25c8..7cdf950c6 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -22,7 +22,7 @@ from sapl.settings import MAX_IMAGE_UPLOAD_SIZE from sapl.utils import (RANGE_ANOS, ChoiceWithoutValidationField, ImageThumbnailFileInput, RangeWidgetOverride, autor_label, autor_modal, models_with_gr_for_model, - qs_override_django_filter) + qs_override_django_filter, YES_NO_CHOICES) from .models import AppConfig, CasaLegislativa @@ -40,6 +40,100 @@ STATUS_USER_CHOICE = [ ('X', _('Excluir Usuário')), ] +class UsuarioCreateForm(ModelForm): + + username = forms.CharField(required=True, label="Nome de usuário") + firstname = forms.CharField(required=True, label="Nome") + lastname = forms.CharField(required=True, label="Sobrenome") + password1 = forms.CharField(required=True, widget=forms.PasswordInput, label='Senha') + password2 = forms.CharField(required=True, widget=forms.PasswordInput, label='Confirmar senha') + user_active = forms.ChoiceField(required=False, choices=YES_NO_CHOICES, label="Usuário ativo?", initial='True') + + ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] + + roles = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple(), choices=ROLES) + + class Meta: + model = get_user_model() + fields = ['username', 'firstname', 'lastname', 'email', 'password1', 'password2', 'user_active', 'roles'] + + def clean(self): + super(UsuarioCreateForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + + data = self.cleaned_data + if data['password1'] != data['password2']: + raise ValidationError('Senhas informadas são diferentes') + + def __init__(self, *args, **kwargs): + + super(UsuarioCreateForm, self).__init__(*args, **kwargs) + + row0 = to_row([('username', 12)]) + + row1 = to_row([('firstname', 6), + ('lastname', 6)]) + + row2 = to_row([('email', 6), + ('user_active', 6)]) + row3 = to_row( + [('password1', 6), + ('password2', 6)]) + + row4 = to_row([(form_actions(label='Confirmar'), 6)]) + + self.helper = FormHelper() + self.helper.layout = Layout( + row0, + row1, + row3, + row2, + 'roles', + row4) + +class UsuarioEditForm(ModelForm): + ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] + + password1 = forms.CharField(required=False, widget=forms.PasswordInput, label='Senha') + password2 = forms.CharField(required=False, widget=forms.PasswordInput, label='Confirmar senha') + user_active = forms.ChoiceField(choices=YES_NO_CHOICES, required=True, label="Usuário ativo?", initial='True') + roles = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple(), choices=ROLES) + + class Meta: + model = get_user_model() + fields = ['email', 'password1', 'password2', 'user_active', 'roles'] + + def __init__(self, *args, **kwargs): + + super(UsuarioEditForm, self).__init__(*args, **kwargs) + + row1 = to_row([('email', 6), + ('user_active', 6)]) + row2 = to_row( + [('password1', 6), + ('password2', 6)]) + + row3 = to_row([(form_actions(label='Salvar Alterações'), 6)]) + + self.helper = FormHelper() + self.helper.layout = Layout( + row1, + row2, + 'roles', + row3) + + def clean(self): + super(UsuarioEditForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + + data = self.cleaned_data + if data['password1'] and data['password1'] != data['password2']: + raise ValidationError('Senhas informadas são diferentes') + class TipoAutorForm(ModelForm): diff --git a/sapl/base/urls.py b/sapl/base/urls.py index 3b7d76e40..e1e2e1c00 100644 --- a/sapl/base/urls.py +++ b/sapl/base/urls.py @@ -17,10 +17,18 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud, RelatorioMateriasPorAutorView, RelatorioMateriasTramitacaoView, RelatorioPresencaSessaoView, SaplSearchView, - RelatorioDataFimPrazoTramitacaoView) + RelatorioDataFimPrazoTramitacaoView, ListarUsuarioView, EditUsuarioView, CreateUsuarioView, + DeleteUsuarioView) app_name = AppConfig.name +admin_user = [ + url(r'^sistema/usuario/$', ListarUsuarioView.as_view(), name='user_list'), + url(r'^sistema/usuario/create$', CreateUsuarioView.as_view(), name='user_create'), + url(r'^sistema/usuario/(?P\d+)/edit$', EditUsuarioView.as_view(), name='user_edit'), + url(r'^sistema/usuario/(?P\d+)/delete$', DeleteUsuarioView.as_view(), name='user_delete') +] + alterar_senha = [ url(r'^sistema/alterar-senha/$', AlterarSenha.as_view(), @@ -111,4 +119,4 @@ urlpatterns = [ url(r'^sistema/search/', SaplSearchView(), name='haystack_search'), -] + recuperar_senha + alterar_senha +] + recuperar_senha + alterar_senha + admin_user diff --git a/sapl/base/views.py b/sapl/base/views.py index 386364420..e2bdcef3f 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 +from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.models import Group from django.contrib.auth.tokens import default_token_generator from django.core.exceptions import ObjectDoesNotExist, PermissionDenied @@ -13,13 +14,13 @@ from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode from django.utils.translation import ugettext_lazy as _ from django.utils.translation import string_concat -from django.views.generic import FormView +from django.views.generic import FormView, ListView, DetailView, UpdateView, CreateView, DeleteView from django.views.generic.base import TemplateView from django_filters.views import FilterView from haystack.views import SearchView from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm from sapl.base.models import Autor, TipoAutor -from sapl.crud.base import CrudAux +from sapl.crud.base import (CrudAux, make_pagination) from sapl.materia.models import (Autoria, MateriaLegislativa, TipoMateriaLegislativa) from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria, @@ -34,7 +35,7 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm, RelatorioMateriasPorAutorFilterSet, RelatorioMateriasTramitacaoilterSet, RelatorioPresencaSessaoFilterSet, - RelatorioDataFimPrazoTramitacaoFilterSet) + RelatorioDataFimPrazoTramitacaoFilterSet, UsuarioEditForm, UsuarioCreateForm) from .models import AppConfig, CasaLegislativa @@ -520,6 +521,118 @@ class RelatorioMateriasPorAutorView(FilterView): return context +class ListarUsuarioView(PermissionRequiredMixin, ListView): + model = get_user_model() + template_name = 'auth/user_list.html' + context_object_name = 'user_list' + permission_required = ('base.list_appconfig',) + paginate_by = 10 + + def get_queryset(self): + qs = super(ListarUsuarioView, self).get_queryset() + return qs.order_by('username') + + def get_context_data(self, **kwargs): + context = super(ListarUsuarioView, self).get_context_data(**kwargs) + paginator = context['paginator'] + page_obj = context['page_obj'] + context['page_range'] = make_pagination( + page_obj.number, paginator.num_pages) + context['NO_ENTRIES_MSG'] = 'Nenhum usuário cadastrado.' + return context + + +class CreateUsuarioView(PermissionRequiredMixin, CreateView): + model = get_user_model() + form_class = UsuarioCreateForm + success_message = 'Usuário criado com sucesso' + permission_required = ('base.add_appconfig',) + + def get_success_url(self): + return reverse('sapl.base:user_list') + + def form_valid(self, form): + + data = form.cleaned_data + + new_user = get_user_model().objects.create(username=data['username'], email=data['email']) + new_user.first_name = data['firstname'] + new_user.last_name = data['lastname'] + new_user.set_password(data['password1']) + new_user.is_superuser = False + new_user.is_staff = False + new_user.save() + + groups = Group.objects.filter(id__in=data['roles']) + for g in groups: + g.user_set.add(new_user) + + return HttpResponseRedirect(self.get_success_url()) + +class DeleteUsuarioView(PermissionRequiredMixin, DeleteView): + + model = get_user_model() + permission_required = ('base.delete_appconfig',) + + def get_success_url(self): + return reverse('sapl.base:user_list') + + def get(self, request, *args, **kwargs): + return self.post(request, *args, **kwargs) + + def get_queryset(self): + qs = super(DeleteUsuarioView, self).get_queryset() + return qs.filter(id=self.kwargs['pk']) + + + +class EditUsuarioView(PermissionRequiredMixin, UpdateView): + model = get_user_model() + form_class = UsuarioEditForm + success_message = 'Usuário editado com sucesso' + permission_required = ('base.change_appconfig',) + + def get_success_url(self): + return reverse('sapl.base:user_list') + + def get_initial(self): + initial = super(EditUsuarioView, self).get_initial() + + user = get_user_model().objects.get(id=self.kwargs['pk']) + roles = [str(g.id) for g in user.groups.all()] + initial['roles'] = roles + initial['user_active'] = user.is_active + + return initial + + def form_valid(self, form): + + user = form.save(commit=False) + data = form.cleaned_data + + # new_user.first_name = data['firstname'] + # new_user.last_name = data['lastname'] + + if data['password1']: + user.set_password(data['password1']) + + if data['user_active'] == 'True' and not user.is_active: + user.is_active = True + elif data['user_active'] == 'False' and user.is_active: + user.is_active = False + + user.save() + + for g in user.groups.all(): + g.user_set.remove(user) + + groups = Group.objects.filter(id__in=data['roles']) + for g in groups: + g.user_set.add(user) + + return super(EditUsuarioView, self).form_valid(form) + + class CasaLegislativaCrud(CrudAux): model = CasaLegislativa diff --git a/sapl/templates/auth/user_form.html b/sapl/templates/auth/user_form.html new file mode 100644 index 000000000..3b19ee162 --- /dev/null +++ b/sapl/templates/auth/user_form.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% load i18n crispy_forms_tags %} + +{% block base_content %} + +
    + {% csrf_token %} + {% crispy form %} + {% if object.pk %} + Remover usuário + {% endif %} +
    + +{% endblock base_content %} \ No newline at end of file diff --git a/sapl/templates/auth/user_list.html b/sapl/templates/auth/user_list.html new file mode 100644 index 000000000..d1f45fca6 --- /dev/null +++ b/sapl/templates/auth/user_list.html @@ -0,0 +1,33 @@ +{% extends "base.html" %} +{% load i18n %} +{% load tz %} +{% load common_tags %} +{% block base_content %} +
    +

    Lista de usuários

    + {% if not user_list %} +

    {{ NO_ENTRIES_MSG }}

    + {% else %} + + + + + + + + + {% for user in user_list %} + + + + + {% endfor %} + +
    Nome de UsuárioE-mail do Usuário
    + {{ user.username }} + {{ user.email }}
    + {% endif %} + Criar Usuário +
    + {% include 'paginacao.html'%} +{% endblock base_content %} \ No newline at end of file diff --git a/sapl/templates/navbar.yaml b/sapl/templates/navbar.yaml index c9411cb5c..934557aea 100644 --- a/sapl/templates/navbar.yaml +++ b/sapl/templates/navbar.yaml @@ -68,7 +68,7 @@ url: '/sistema' check_permission: base.view_tabelas_auxiliares - title: {% trans 'Administração de Usuários' %} - url: '/admin' + url: {% url 'sapl.base:user_list' %} check_permission: user.is_superuser {% comment %} From b9afef98e3a661c1315cd33f10e10ceed41716b6 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 9 Mar 2018 15:02:49 -0300 Subject: [PATCH 052/121] HOT-FIX: conserta migrate quando banco vazio --- sapl/base/forms.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 7cdf950c6..1b86c519c 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -40,6 +40,9 @@ STATUS_USER_CHOICE = [ ('X', _('Excluir Usuário')), ] +def get_roles(): + return [(g.id, g.name) for g in Group.objects.all().order_by('name')] + class UsuarioCreateForm(ModelForm): username = forms.CharField(required=True, label="Nome de usuário") @@ -49,14 +52,15 @@ class UsuarioCreateForm(ModelForm): password2 = forms.CharField(required=True, widget=forms.PasswordInput, label='Confirmar senha') user_active = forms.ChoiceField(required=False, choices=YES_NO_CHOICES, label="Usuário ativo?", initial='True') - ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] + #ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] - roles = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple(), choices=ROLES) + roles = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple(), choices=get_roles) class Meta: model = get_user_model() fields = ['username', 'firstname', 'lastname', 'email', 'password1', 'password2', 'user_active', 'roles'] + def clean(self): super(UsuarioCreateForm, self).clean() @@ -94,12 +98,14 @@ class UsuarioCreateForm(ModelForm): row4) class UsuarioEditForm(ModelForm): - ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] + # ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] + + ROLES = [] password1 = forms.CharField(required=False, widget=forms.PasswordInput, label='Senha') password2 = forms.CharField(required=False, widget=forms.PasswordInput, label='Confirmar senha') user_active = forms.ChoiceField(choices=YES_NO_CHOICES, required=True, label="Usuário ativo?", initial='True') - roles = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple(), choices=ROLES) + roles = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple(), choices=get_roles) class Meta: model = get_user_model() @@ -115,6 +121,7 @@ class UsuarioEditForm(ModelForm): [('password1', 6), ('password2', 6)]) + row3 = to_row([(form_actions(label='Salvar Alterações'), 6)]) self.helper = FormHelper() From 219cb89368f7230a9a3e2393cbfd4a2833f8acda Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Fri, 9 Mar 2018 16:13:43 -0300 Subject: [PATCH 053/121] Edita etiqueta de protocolo (#1744) --- sapl/relatorios/views.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py index 30da38f8d..eace383dd 100644 --- a/sapl/relatorios/views.py +++ b/sapl/relatorios/views.py @@ -944,16 +944,22 @@ def get_etiqueta_protocolos(prots): dic['nom_autor'] = str(p.autor or ' ') + dic['num_materia'] = '' + for materia in MateriaLegislativa.objects.filter( + numero_protocolo=p.numero, ano=p.ano): + dic['num_materia'] = materia.tipo.sigla + ' ' + str(materia.numero) + '/' + str(materia.ano) + + dic['natureza'] = '' if p.tipo_processo == 0: dic['natureza'] = 'Administrativo' if p.tipo_processo == 1: - dic['natureza'] = 'Legislativo' + if dic['num_materia']: + dic['natureza'] = dic['num_materia'] + else: + dic['natureza'] = 'Legislativo' + - dic['num_materia'] = '' - for materia in MateriaLegislativa.objects.filter( - numero_protocolo=p.numero, ano=p.ano): - dic['num_materia'] = str(materia) dic['num_documento'] = '' for documento in DocumentoAdministrativo.objects.filter( From af6c78d48b76b0bddb6029d7b7168df0d859e910 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 12 Mar 2018 08:27:46 -0300 Subject: [PATCH 054/121] Release: 3.1.60 --- 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 7fcc17e1e..b30110edf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.59 + image: interlegis/sapl:3.1.60 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 2361cb90a..bfbde4e22 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.59', + version='3.1.60', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From acddd41eea564f1e3e7562246357c9e976c72e88 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 12 Mar 2018 09:54:59 -0300 Subject: [PATCH 055/121] =?UTF-8?q?HOT-FIX:=20adiciona=20nome=20e=20sobren?= =?UTF-8?q?ome=20de=20usu=C3=A1rios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/templates/auth/user_list.html | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sapl/templates/auth/user_list.html b/sapl/templates/auth/user_list.html index d1f45fca6..b24cb764e 100644 --- a/sapl/templates/auth/user_list.html +++ b/sapl/templates/auth/user_list.html @@ -11,7 +11,8 @@ - + + @@ -21,6 +22,7 @@ + {% endfor %} @@ -29,5 +31,5 @@ {% endif %} Criar Usuário - {% include 'paginacao.html'%} -{% endblock base_content %} \ No newline at end of file + {% include 'paginacao.html'%} +{% endblock base_content %} From 3b7f768c29907a135cae15b766765527621d6d39 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 12 Mar 2018 13:21:19 -0300 Subject: [PATCH 056/121] Conserta PEP 8 --- sapl/api/forms.py | 1 + sapl/api/serializers.py | 1 + sapl/api/urls.py | 1 + sapl/api/views.py | 1 + sapl/base/admin.py | 1 + sapl/base/forms.py | 36 +++++++------ sapl/base/search_indexes.py | 3 +- sapl/base/templatetags/common_tags.py | 3 +- sapl/base/templatetags/menus.py | 4 +- sapl/base/tests/test_form.py | 1 + sapl/base/tests/teststub_urls.py | 1 + sapl/base/urls.py | 9 ++-- sapl/base/views.py | 16 ++++-- sapl/comissoes/forms.py | 1 + sapl/comissoes/models.py | 2 +- sapl/comissoes/tests/test_comissoes.py | 1 + sapl/comissoes/urls.py | 4 +- sapl/comissoes/views.py | 23 ++++----- sapl/compilacao/apps.py | 6 +-- sapl/compilacao/forms.py | 1 + sapl/compilacao/models.py | 2 +- .../templatetags/compilacao_filters.py | 1 + .../tests/test_tipo_texto_articulado_form.py | 2 +- sapl/compilacao/urls.py | 11 ++-- sapl/compilacao/views.py | 9 ++-- sapl/crispy_layout_mixin.py | 2 +- sapl/crud/base.py | 3 +- sapl/crud/tests/test_base.py | 1 + .../commands/migracao_documentos.py | 1 + .../scripts/exporta_zope/exporta_zope.py | 1 + sapl/legacy/scripts/scrap_original_forms.py | 2 +- sapl/legacy/scripts/study.py | 1 + sapl/legacy/test_migration.py | 2 +- sapl/lexml/urls.py | 1 + sapl/materia/admin.py | 5 +- sapl/materia/email_utils.py | 1 + sapl/materia/forms.py | 13 ++--- sapl/materia/models.py | 2 +- sapl/materia/receivers.py | 1 + sapl/materia/tests/test_email_templates.py | 1 + sapl/materia/tests/test_materia.py | 50 +++++++++---------- sapl/materia/tests/test_materia_form.py | 1 + sapl/materia/urls.py | 3 +- sapl/materia/views.py | 5 +- sapl/norma/forms.py | 1 + sapl/norma/tests/test_norma.py | 1 + sapl/norma/urls.py | 1 + sapl/norma/views.py | 1 + sapl/painel/views.py | 1 + sapl/parlamentares/forms.py | 1 + sapl/parlamentares/models.py | 1 + sapl/parlamentares/tests/test_mandato.py | 1 + .../parlamentares/tests/test_parlamentares.py | 1 + sapl/parlamentares/urls.py | 1 + sapl/parlamentares/views.py | 3 +- sapl/protocoloadm/forms.py | 15 +++--- sapl/protocoloadm/models.py | 1 + sapl/protocoloadm/tests/test_protocoloadm.py | 1 + sapl/protocoloadm/urls.py | 1 + sapl/protocoloadm/views.py | 3 +- sapl/redireciona_urls/views.py | 2 + sapl/relatorios/views.py | 7 ++- sapl/rules/apps.py | 1 + sapl/rules/tests/test_rules.py | 1 + sapl/sessao/forms.py | 1 + sapl/sessao/tests/test_sessao_view.py | 1 + sapl/sessao/urls.py | 1 + sapl/sessao/views.py | 3 +- sapl/test_crispy_layout_mixin.py | 1 + sapl/test_urls.py | 5 +- sapl/urls.py | 13 ++--- sapl/utils.py | 13 +++-- scripts/anonimizador/anon.py | 1 + ...onvert_null_to_empty_in_all_char_fields.py | 1 + scripts/fk_protocoloadm_docadm.py | 1 + 75 files changed, 189 insertions(+), 134 deletions(-) diff --git a/sapl/api/forms.py b/sapl/api/forms.py index 2ee441d34..94bc80de4 100644 --- a/sapl/api/forms.py +++ b/sapl/api/forms.py @@ -7,6 +7,7 @@ from django_filters.filters import DateFilter, MethodFilter, ModelChoiceFilter from rest_framework import serializers from rest_framework.compat import django_filters from rest_framework.filters import FilterSet + from sapl.base.models import Autor, TipoAutor from sapl.parlamentares.models import Legislatura from sapl.utils import generic_relations_for_model diff --git a/sapl/api/serializers.py b/sapl/api/serializers.py index 9e08ea991..9219bf0e4 100644 --- a/sapl/api/serializers.py +++ b/sapl/api/serializers.py @@ -1,4 +1,5 @@ from rest_framework import serializers + from sapl.base.models import Autor, CasaLegislativa from sapl.materia.models import MateriaLegislativa from sapl.sessao.models import OrdemDia, SessaoPlenaria diff --git a/sapl/api/urls.py b/sapl/api/urls.py index 005a71f5c..1f19e9d1f 100644 --- a/sapl/api/urls.py +++ b/sapl/api/urls.py @@ -1,6 +1,7 @@ from django.conf import settings from django.conf.urls import include, url from rest_framework.routers import DefaultRouter + from sapl.api.views import (AutoresPossiveisListView, AutoresProvaveisListView, AutorListView, MateriaLegislativaViewSet, ModelChoiceView, SessaoPlenariaViewSet) diff --git a/sapl/api/views.py b/sapl/api/views.py index 2adffa7e5..9853e6af0 100644 --- a/sapl/api/views.py +++ b/sapl/api/views.py @@ -8,6 +8,7 @@ from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.permissions import (AllowAny, IsAuthenticated, IsAuthenticatedOrReadOnly) from rest_framework.viewsets import GenericViewSet + from sapl.api.forms import (AutorChoiceFilterSet, AutoresPossiveisFilterSet, AutorSearchForFieldFilterSet) from sapl.api.serializers import (AutorChoiceSerializer, AutorSerializer, diff --git a/sapl/base/admin.py b/sapl/base/admin.py index 00f9e104b..2f7cd0ed4 100644 --- a/sapl/base/admin.py +++ b/sapl/base/admin.py @@ -3,6 +3,7 @@ from django.core.urlresolvers import reverse from django.shortcuts import redirect from django.utils.translation import ugettext_lazy as _ from reversion.models import Revision + from sapl.base.models import ProblemaMigracao from sapl.utils import register_all_models_in_admin diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 1b86c519c..092d93b59 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -13,16 +13,17 @@ from django.db import models, transaction from django.forms import Form, ModelForm from django.utils.translation import ugettext_lazy as _ from django.utils.translation import string_concat + from sapl.base.models import Autor, TipoAutor from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, to_row) from sapl.materia.models import MateriaLegislativa from sapl.sessao.models import SessaoPlenaria from sapl.settings import MAX_IMAGE_UPLOAD_SIZE -from sapl.utils import (RANGE_ANOS, ChoiceWithoutValidationField, - ImageThumbnailFileInput, RangeWidgetOverride, - autor_label, autor_modal, models_with_gr_for_model, - qs_override_django_filter, YES_NO_CHOICES) +from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, + ChoiceWithoutValidationField, ImageThumbnailFileInput, + RangeWidgetOverride, autor_label, autor_modal, + models_with_gr_for_model, qs_override_django_filter) from .models import AppConfig, CasaLegislativa @@ -40,8 +41,10 @@ STATUS_USER_CHOICE = [ ('X', _('Excluir Usuário')), ] + def get_roles(): - return [(g.id, g.name) for g in Group.objects.all().order_by('name')] + return [(g.id, g.name) for g in Group.objects.all().order_by('name')] + class UsuarioCreateForm(ModelForm): @@ -50,16 +53,18 @@ class UsuarioCreateForm(ModelForm): lastname = forms.CharField(required=True, label="Sobrenome") password1 = forms.CharField(required=True, widget=forms.PasswordInput, label='Senha') password2 = forms.CharField(required=True, widget=forms.PasswordInput, label='Confirmar senha') - user_active = forms.ChoiceField(required=False, choices=YES_NO_CHOICES, label="Usuário ativo?", initial='True') + user_active = forms.ChoiceField(required=False, choices=YES_NO_CHOICES, + label="Usuário ativo?", initial='True') #ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] - roles = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple(), choices=get_roles) + roles = forms.MultipleChoiceField( + required=True, widget=forms.CheckboxSelectMultiple(), choices=get_roles) class Meta: model = get_user_model() - fields = ['username', 'firstname', 'lastname', 'email', 'password1', 'password2', 'user_active', 'roles'] - + fields = ['username', 'firstname', 'lastname', 'email', + 'password1', 'password2', 'user_active', 'roles'] def clean(self): super(UsuarioCreateForm, self).clean() @@ -69,7 +74,7 @@ class UsuarioCreateForm(ModelForm): data = self.cleaned_data if data['password1'] != data['password2']: - raise ValidationError('Senhas informadas são diferentes') + raise ValidationError('Senhas informadas são diferentes') def __init__(self, *args, **kwargs): @@ -97,6 +102,7 @@ class UsuarioCreateForm(ModelForm): 'roles', row4) + class UsuarioEditForm(ModelForm): # ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] @@ -104,8 +110,10 @@ class UsuarioEditForm(ModelForm): password1 = forms.CharField(required=False, widget=forms.PasswordInput, label='Senha') password2 = forms.CharField(required=False, widget=forms.PasswordInput, label='Confirmar senha') - user_active = forms.ChoiceField(choices=YES_NO_CHOICES, required=True, label="Usuário ativo?", initial='True') - roles = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple(), choices=get_roles) + user_active = forms.ChoiceField(choices=YES_NO_CHOICES, required=True, + label="Usuário ativo?", initial='True') + roles = forms.MultipleChoiceField( + required=True, widget=forms.CheckboxSelectMultiple(), choices=get_roles) class Meta: model = get_user_model() @@ -121,7 +129,6 @@ class UsuarioEditForm(ModelForm): [('password1', 6), ('password2', 6)]) - row3 = to_row([(form_actions(label='Salvar Alterações'), 6)]) self.helper = FormHelper() @@ -139,7 +146,7 @@ class UsuarioEditForm(ModelForm): data = self.cleaned_data if data['password1'] and data['password1'] != data['password2']: - raise ValidationError('Senhas informadas são diferentes') + raise ValidationError('Senhas informadas são diferentes') class TipoAutorForm(ModelForm): @@ -572,6 +579,7 @@ class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet): form_actions(label='Pesquisar')) ) + class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet): filter_overrides = {models.DateField: { diff --git a/sapl/base/search_indexes.py b/sapl/base/search_indexes.py index 3deb42eac..f685cb002 100644 --- a/sapl/base/search_indexes.py +++ b/sapl/base/search_indexes.py @@ -13,13 +13,14 @@ from haystack.constants import Indexable from haystack.fields import CharField from haystack.indexes import SearchIndex from haystack.utils import get_model_ct_tuple +from textract.exceptions import ExtensionNotSupported + from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC, STATUS_TA_PUBLIC, Dispositivo, TextoArticulado) from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa from sapl.norma.models import NormaJuridica from sapl.settings import BASE_DIR, SOLR_URL -from textract.exceptions import ExtensionNotSupported logger = logging.getLogger(BASE_DIR.name) diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py index 00ab405cf..9e095f072 100644 --- a/sapl/base/templatetags/common_tags.py +++ b/sapl/base/templatetags/common_tags.py @@ -1,11 +1,12 @@ from compressor.utils import get_class from django import template +from django.template.defaultfilters import stringfilter + from sapl.base.models import AppConfig from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa from sapl.norma.models import NormaJuridica from sapl.parlamentares.models import Filiacao from sapl.utils import filiacao_data -from django.template.defaultfilters import stringfilter register = template.Library() diff --git a/sapl/base/templatetags/menus.py b/sapl/base/templatetags/menus.py index 92df1e39f..f90a6940f 100644 --- a/sapl/base/templatetags/menus.py +++ b/sapl/base/templatetags/menus.py @@ -1,9 +1,9 @@ +import yaml from django import template from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ -import yaml -from sapl.utils import sapl_logger +from sapl.utils import sapl_logger register = template.Library() diff --git a/sapl/base/tests/test_form.py b/sapl/base/tests/test_form.py index fcaecdaaf..35f1c82bf 100644 --- a/sapl/base/tests/test_form.py +++ b/sapl/base/tests/test_form.py @@ -1,5 +1,6 @@ import pytest from django.utils.translation import ugettext_lazy as _ + from sapl.base.forms import CasaLegislativaForm diff --git a/sapl/base/tests/teststub_urls.py b/sapl/base/tests/teststub_urls.py index 3d85e2d9b..9796768f2 100644 --- a/sapl/base/tests/teststub_urls.py +++ b/sapl/base/tests/teststub_urls.py @@ -1,5 +1,6 @@ from django.conf.urls import patterns, url from django.views.generic.base import TemplateView + from sapl.urls import urlpatterns as original_patterns ptrn = patterns('', diff --git a/sapl/base/urls.py b/sapl/base/urls.py index e1e2e1c00..0f720071f 100644 --- a/sapl/base/urls.py +++ b/sapl/base/urls.py @@ -5,20 +5,21 @@ 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 sapl.base.views import AutorCrud, ConfirmarEmailView, TipoAutorCrud from sapl.settings import EMAIL_SEND_USER from .apps import AppConfig from .forms import LoginForm, NovaSenhaForm, RecuperarSenhaForm from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud, - HelpTopicView, RelatorioAtasView, + CreateUsuarioView, DeleteUsuarioView, EditUsuarioView, + HelpTopicView, ListarUsuarioView, RelatorioAtasView, + RelatorioDataFimPrazoTramitacaoView, RelatorioHistoricoTramitacaoView, RelatorioMateriasPorAnoAutorTipoView, RelatorioMateriasPorAutorView, RelatorioMateriasTramitacaoView, - RelatorioPresencaSessaoView, SaplSearchView, - RelatorioDataFimPrazoTramitacaoView, ListarUsuarioView, EditUsuarioView, CreateUsuarioView, - DeleteUsuarioView) + RelatorioPresencaSessaoView, SaplSearchView) app_name = AppConfig.name diff --git a/sapl/base/views.py b/sapl/base/views.py index e2bdcef3f..2240a71ba 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -14,13 +14,15 @@ from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode from django.utils.translation import ugettext_lazy as _ from django.utils.translation import string_concat -from django.views.generic import FormView, ListView, DetailView, UpdateView, CreateView, DeleteView +from django.views.generic import (CreateView, DeleteView, DetailView, FormView, + ListView, UpdateView) from django.views.generic.base import TemplateView from django_filters.views import FilterView from haystack.views import SearchView + from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm from sapl.base.models import Autor, TipoAutor -from sapl.crud.base import (CrudAux, make_pagination) +from sapl.crud.base import CrudAux, make_pagination from sapl.materia.models import (Autoria, MateriaLegislativa, TipoMateriaLegislativa) from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria, @@ -30,12 +32,13 @@ from sapl.utils import (parlamentares_ativos, sapl_logger, from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, RelatorioAtasFilterSet, + RelatorioDataFimPrazoTramitacaoFilterSet, RelatorioHistoricoTramitacaoFilterSet, RelatorioMateriasPorAnoAutorTipoFilterSet, RelatorioMateriasPorAutorFilterSet, RelatorioMateriasTramitacaoilterSet, - RelatorioPresencaSessaoFilterSet, - RelatorioDataFimPrazoTramitacaoFilterSet, UsuarioEditForm, UsuarioCreateForm) + RelatorioPresencaSessaoFilterSet, UsuarioCreateForm, + UsuarioEditForm) from .models import AppConfig, CasaLegislativa @@ -70,6 +73,7 @@ class TipoAutorCrud(CrudAux): return vn class ListView(CrudAux.ListView): + def get_queryset(self): qs = CrudAux.ListView.get_queryset(self) qs = qs.filter(content_type__isnull=True) @@ -84,6 +88,7 @@ class TipoAutorCrud(CrudAux): return context class TipoAutorMixin: + def dispatch(self, request, *args, **kwargs): object = self.get_object() if object.content_type: @@ -359,6 +364,7 @@ class RelatorioHistoricoTramitacaoView(FilterView): return context + class RelatorioDataFimPrazoTramitacaoView(FilterView): model = MateriaLegislativa filterset_class = RelatorioDataFimPrazoTramitacaoFilterSet @@ -569,6 +575,7 @@ class CreateUsuarioView(PermissionRequiredMixin, CreateView): return HttpResponseRedirect(self.get_success_url()) + class DeleteUsuarioView(PermissionRequiredMixin, DeleteView): model = get_user_model() @@ -585,7 +592,6 @@ class DeleteUsuarioView(PermissionRequiredMixin, DeleteView): return qs.filter(id=self.kwargs['pk']) - class EditUsuarioView(PermissionRequiredMixin, UpdateView): model = get_user_model() form_class = UsuarioEditForm diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index 33be2003d..ea27eab0d 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -5,6 +5,7 @@ from django.db import transaction from django.db.models import Q from django.forms import ModelForm from django.utils.translation import ugettext_lazy as _ + from sapl.base.models import Autor, TipoAutor from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar diff --git a/sapl/comissoes/models.py b/sapl/comissoes/models.py index 882fe8638..2a5bd489c 100644 --- a/sapl/comissoes/models.py +++ b/sapl/comissoes/models.py @@ -1,7 +1,7 @@ +import reversion from django.db import models from django.utils.translation import ugettext_lazy as _ from model_utils import Choices -import reversion from sapl.base.models import Autor from sapl.parlamentares.models import Parlamentar diff --git a/sapl/comissoes/tests/test_comissoes.py b/sapl/comissoes/tests/test_comissoes.py index 0b040b914..fee303192 100644 --- a/sapl/comissoes/tests/test_comissoes.py +++ b/sapl/comissoes/tests/test_comissoes.py @@ -1,6 +1,7 @@ import pytest from django.core.urlresolvers import reverse from model_mommy import mommy + from sapl.comissoes.models import Comissao, Composicao, Periodo, TipoComissao from sapl.parlamentares.models import Filiacao, Parlamentar, Partido diff --git a/sapl/comissoes/urls.py b/sapl/comissoes/urls.py index 47fb0b059..4bf1904aa 100644 --- a/sapl/comissoes/urls.py +++ b/sapl/comissoes/urls.py @@ -1,7 +1,9 @@ from django.conf.urls import include, url + from sapl.comissoes.views import (CargoCrud, ComissaoCrud, ComposicaoCrud, MateriasTramitacaoListView, ParticipacaoCrud, - PeriodoComposicaoCrud, ReuniaoCrud, TipoComissaoCrud) + PeriodoComposicaoCrud, ReuniaoCrud, + TipoComissaoCrud) from .apps import AppConfig diff --git a/sapl/comissoes/views.py b/sapl/comissoes/views.py index 0fd5a2c13..8324f4b6a 100644 --- a/sapl/comissoes/views.py +++ b/sapl/comissoes/views.py @@ -7,19 +7,17 @@ from django.views.generic.base import RedirectView from django.views.generic.detail import DetailView from django.views.generic.edit import FormMixin - from sapl.base.models import AppConfig as AppsAppConfig -from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, - CrudAux, MasterDetailCrud, - PermissionRequiredForAppCrudMixin) +from sapl.comissoes.apps import AppConfig from sapl.comissoes.forms import ParticipacaoCreateForm, ParticipacaoEditForm +from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, + MasterDetailCrud, + PermissionRequiredForAppCrudMixin) from sapl.materia.models import MateriaLegislativa, Tramitacao -from .forms import ReuniaoForm, ComissaoForm - +from .forms import ComissaoForm, ReuniaoForm from .models import (CargoComissao, Comissao, Composicao, Participacao, - Periodo, TipoComissao, Reuniao) -from sapl.comissoes.apps import AppConfig + Periodo, Reuniao, TipoComissao) def pegar_url_composicao(pk): @@ -60,6 +58,7 @@ class ParticipacaoCrud(MasterDetailCrud): form_class = ParticipacaoEditForm class DeleteView(MasterDetailCrud.DeleteView): + def get_success_url(self): composicao_comissao_pk = self.object.composicao.comissao.pk composicao_pk = self.object.composicao.pk @@ -147,6 +146,7 @@ class MateriasTramitacaoListView(ListView): context['object'] = Comissao.objects.get(id=self.kwargs['pk']) return context + class ReuniaoCrud(MasterDetailCrud): model = Reuniao parent_field = 'comissao' @@ -168,20 +168,17 @@ class ReuniaoCrud(MasterDetailCrud): def get_initial(self): return {'comissao': self.object.comissao} - class CreateView(MasterDetailCrud.CreateView): form_class = ReuniaoForm def get_initial(self): - comissao = Comissao.objects.get(id=self.kwargs['pk']) - - return {'comissao': comissao} + comissao = Comissao.objects.get(id=self.kwargs['pk']) + return {'comissao': comissao} class DeleteView(MasterDetailCrud.DeleteView): pass - class DetailView(MasterDetailCrud.DetailView): @xframe_options_exempt diff --git a/sapl/compilacao/apps.py b/sapl/compilacao/apps.py index 6b96175b5..96bd10b87 100644 --- a/sapl/compilacao/apps.py +++ b/sapl/compilacao/apps.py @@ -2,10 +2,10 @@ import logging from django import apps from django.conf import settings -from django.db import models, connection +from django.db import connection, models from django.db.utils import DEFAULT_DB_ALIAS, IntegrityError -from django.utils.translation import ugettext_lazy as _, string_concat - +from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import string_concat from sapl.settings import BASE_DIR diff --git a/sapl/compilacao/forms.py b/sapl/compilacao/forms.py index 0748b1423..f51504f2c 100644 --- a/sapl/compilacao/forms.py +++ b/sapl/compilacao/forms.py @@ -14,6 +14,7 @@ from django.forms.forms import Form from django.forms.models import ModelForm from django.template import defaultfilters from django.utils.translation import ugettext_lazy as _ + from sapl import utils from sapl.compilacao.models import (NOTAS_PUBLICIDADE_CHOICES, PARTICIPACAO_SOCIAL_CHOICES, Dispositivo, diff --git a/sapl/compilacao/models.py b/sapl/compilacao/models.py index ec420c135..ad30cc23c 100644 --- a/sapl/compilacao/models.py +++ b/sapl/compilacao/models.py @@ -1,4 +1,5 @@ +import reversion from django.contrib import messages from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType @@ -12,7 +13,6 @@ from django.utils import timezone from django.utils.decorators import classonlymethod from django.utils.encoding import force_text from django.utils.translation import ugettext_lazy as _ -import reversion from sapl.compilacao.utils import (get_integrations_view_names, int_to_letter, int_to_roman) diff --git a/sapl/compilacao/templatetags/compilacao_filters.py b/sapl/compilacao/templatetags/compilacao_filters.py index 58c6dfaec..e56478bae 100644 --- a/sapl/compilacao/templatetags/compilacao_filters.py +++ b/sapl/compilacao/templatetags/compilacao_filters.py @@ -4,6 +4,7 @@ from django.core.signing import Signer from django.db.models import Q from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ + from sapl.compilacao.models import Dispositivo register = template.Library() diff --git a/sapl/compilacao/tests/test_tipo_texto_articulado_form.py b/sapl/compilacao/tests/test_tipo_texto_articulado_form.py index b682307c9..6c64adc78 100644 --- a/sapl/compilacao/tests/test_tipo_texto_articulado_form.py +++ b/sapl/compilacao/tests/test_tipo_texto_articulado_form.py @@ -1,6 +1,6 @@ +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 diff --git a/sapl/compilacao/urls.py b/sapl/compilacao/urls.py index decbd5578..7d4d58f0f 100644 --- a/sapl/compilacao/urls.py +++ b/sapl/compilacao/urls.py @@ -1,4 +1,5 @@ from django.conf.urls import include, url + from sapl.compilacao import views from sapl.compilacao.views import (TipoDispositivoCrud, TipoNotaCrud, TipoPublicacaoCrud, TipoVideCrud, @@ -116,13 +117,13 @@ urlpatterns = [ include(TipoDispositivoCrud.get_urls())), url(r'^sistema/ta/config/tipo-textoarticulado$', - views.TipoTaListView.as_view(), name='tipo_ta_list'), + views.TipoTaListView.as_view(), name='tipo_ta_list'), url(r'^sistema/ta/config/tipo-textoarticulado/create$', - views.TipoTaCreateView.as_view(), name='tipo_ta_create'), + views.TipoTaCreateView.as_view(), name='tipo_ta_create'), url(r'^sistema/ta/config/tipo-textoarticulado/(?P[0-9]+)$', - views.TipoTaDetailView.as_view(), name='tipo_ta_detail'), + views.TipoTaDetailView.as_view(), name='tipo_ta_detail'), url(r'^sistema/ta/config/tipo-textoarticulado/(?P[0-9]+)/edit$', - views.TipoTaUpdateView.as_view(), name='tipo_ta_edit'), + views.TipoTaUpdateView.as_view(), name='tipo_ta_edit'), url(r'^sistema/ta/config/tipo-textoarticulado/(?P[0-9]+)/delete$', - views.TipoTaDeleteView.as_view(), name='tipo_ta_delete'), + views.TipoTaDeleteView.as_view(), name='tipo_ta_delete'), ] diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index 250ef70ea..78d1e221e 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -1,7 +1,7 @@ -from collections import OrderedDict -from datetime import timedelta import logging import sys +from collections import OrderedDict +from datetime import timedelta from braces.views import FormMessagesMixin from django import forms @@ -19,8 +19,8 @@ from django.http.response import (HttpResponse, HttpResponseRedirect, from django.shortcuts import get_object_or_404, redirect from django.utils.dateparse import parse_date from django.utils.encoding import force_text -from django.utils.translation import string_concat from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import string_concat from django.views.generic.base import TemplateView from django.views.generic.detail import DetailView from django.views.generic.edit import (CreateView, DeleteView, FormView, @@ -48,10 +48,9 @@ from sapl.compilacao.models import (STATUS_TA_EDITION, STATUS_TA_PRIVATE, from sapl.compilacao.utils import (DISPOSITIVO_SELECT_RELATED, DISPOSITIVO_SELECT_RELATED_EDIT, get_integrations_view_names) -from sapl.crud.base import Crud, CrudListView, make_pagination, CrudAux +from sapl.crud.base import Crud, CrudAux, CrudListView, make_pagination from sapl.settings import BASE_DIR - TipoNotaCrud = CrudAux.build(TipoNota, 'tipo_nota') TipoVideCrud = CrudAux.build(TipoVide, 'tipo_vide') TipoPublicacaoCrud = CrudAux.build(TipoPublicacao, 'tipo_publicacao') diff --git a/sapl/crispy_layout_mixin.py b/sapl/crispy_layout_mixin.py index 0adc1c679..12a876b12 100644 --- a/sapl/crispy_layout_mixin.py +++ b/sapl/crispy_layout_mixin.py @@ -1,5 +1,6 @@ from math import ceil +import rtyaml from crispy_forms.bootstrap import FormActions from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit @@ -7,7 +8,6 @@ from django import template from django.core.urlresolvers import reverse, reverse_lazy from django.utils import formats from django.utils.translation import ugettext as _ -import rtyaml def heads_and_tails(list_of_lists): diff --git a/sapl/crud/base.py b/sapl/crud/base.py index 3f20e376b..8bb8c3794 100644 --- a/sapl/crud/base.py +++ b/sapl/crud/base.py @@ -17,8 +17,8 @@ from django.http.response import Http404 from django.shortcuts import redirect from django.utils.decorators import classonlymethod from django.utils.encoding import force_text -from django.utils.translation import string_concat from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import string_concat from django.views.generic import (CreateView, DeleteView, DetailView, ListView, UpdateView) from django.views.generic.base import ContextMixin @@ -30,7 +30,6 @@ from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL, from sapl.settings import BASE_DIR from sapl.utils import normalize - logger = logging.getLogger(BASE_DIR.name) ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \ diff --git a/sapl/crud/tests/test_base.py b/sapl/crud/tests/test_base.py index 8a8a26af4..8e1d10965 100644 --- a/sapl/crud/tests/test_base.py +++ b/sapl/crud/tests/test_base.py @@ -1,6 +1,7 @@ import pytest from django.core.urlresolvers import reverse from model_mommy import mommy + from sapl.crud.base import (CrispyLayoutFormMixin, CrudListView, from_to, get_field_display, make_pagination) from sapl.crud.tests.stub_app.models import Continent, Country diff --git a/sapl/legacy/management/commands/migracao_documentos.py b/sapl/legacy/management/commands/migracao_documentos.py index f9e81a29c..7cba09d5a 100644 --- a/sapl/legacy/management/commands/migracao_documentos.py +++ b/sapl/legacy/management/commands/migracao_documentos.py @@ -1,4 +1,5 @@ from django.core.management.base import BaseCommand + from sapl.legacy.migracao_documentos import migrar_documentos diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index c097c1a1a..31c4c3188 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 magic import yaml + import ZODB.DB import ZODB.FileStorage from ZODB.broken import Broken diff --git a/sapl/legacy/scripts/scrap_original_forms.py b/sapl/legacy/scripts/scrap_original_forms.py index a3325b32e..dbe8e4219 100644 --- a/sapl/legacy/scripts/scrap_original_forms.py +++ b/sapl/legacy/scripts/scrap_original_forms.py @@ -7,8 +7,8 @@ import pkg_resources import yaml from bs4 import BeautifulSoup from bs4.element import NavigableString, Tag - from django.apps.config import AppConfig + from sapl.crispy_layout_mixin import heads_and_tails from sapl.legacy.migracao import appconfs, get_renames from sapl.legacy.scripts.utils import getsourcelines diff --git a/sapl/legacy/scripts/study.py b/sapl/legacy/scripts/study.py index 1078af38e..9a4149fe5 100644 --- a/sapl/legacy/scripts/study.py +++ b/sapl/legacy/scripts/study.py @@ -1,4 +1,5 @@ from django.apps import apps + from sapl.legacy.migracao import legacy_app for model in apps.get_app_config('legacy').get_models(): diff --git a/sapl/legacy/test_migration.py b/sapl/legacy/test_migration.py index 53034987d..ad1ad86d3 100644 --- a/sapl/legacy/test_migration.py +++ b/sapl/legacy/test_migration.py @@ -1,7 +1,7 @@ from random import shuffle from .migracao import (_formatar_lista_para_sql, get_autorias_sem_repeticoes, - get_reapontamento_de_autores_repetidos) + get_reapontamento_de_autores_repetidos) def test_unifica_autores_repetidos_no_legado(): diff --git a/sapl/lexml/urls.py b/sapl/lexml/urls.py index a10299ca0..e7d582030 100644 --- a/sapl/lexml/urls.py +++ b/sapl/lexml/urls.py @@ -1,4 +1,5 @@ from django.conf.urls import include, url + from sapl.lexml.views import LexmlProvedorCrud, LexmlPublicadorCrud from .apps import AppConfig diff --git a/sapl/materia/admin.py b/sapl/materia/admin.py index 25c107378..6fb649296 100644 --- a/sapl/materia/admin.py +++ b/sapl/materia/admin.py @@ -4,11 +4,10 @@ from django.contrib import admin from sapl.base.models import TipoAutor from sapl.comissoes.models import TipoComissao from sapl.materia.models import Proposicao -from sapl.parlamentares.models import TipoAfastamento, SituacaoMilitar, \ - TipoDependente +from sapl.parlamentares.models import (SituacaoMilitar, TipoAfastamento, + TipoDependente) from sapl.utils import register_all_models_in_admin - register_all_models_in_admin(__name__) if not settings.DEBUG: diff --git a/sapl/materia/email_utils.py b/sapl/materia/email_utils.py index a28fcbc5f..3dc6b220d 100644 --- a/sapl/materia/email_utils.py +++ b/sapl/materia/email_utils.py @@ -4,6 +4,7 @@ from django.core.mail import EmailMultiAlternatives, get_connection, send_mail from django.core.urlresolvers import reverse from django.template import Context, loader from django.utils import timezone + from sapl.base.models import CasaLegislativa from sapl.settings import EMAIL_SEND_USER diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 1eebd5c7d..a7cac7df5 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1,7 +1,7 @@ import os + import django_filters -import sapl from crispy_forms.bootstrap import Alert, FormActions, InlineRadios from crispy_forms.helper import FormHelper from crispy_forms.layout import (HTML, Button, Column, Div, Field, Fieldset, @@ -22,7 +22,9 @@ 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, AppConfig + +import sapl +from sapl.base.models import AppConfig, Autor, TipoAutor from sapl.comissoes.models import Comissao from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC, STATUS_TA_PRIVATE) @@ -39,8 +41,8 @@ from sapl.settings import MAX_DOC_UPLOAD_SIZE from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, ChoiceWithoutValidationField, MateriaPesquisaOrderingFilter, RangeWidgetOverride, - autor_label, autor_modal, models_with_gr_for_model, - qs_override_django_filter, gerar_hash_arquivo) + autor_label, autor_modal, gerar_hash_arquivo, + models_with_gr_for_model, qs_override_django_filter) from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial, DocumentoAcessorio, Numeracao, Proposicao, Relatoria, @@ -1135,7 +1137,7 @@ class ProposicaoForm(forms.ModelForm): widgets = { 'descricao': widgets.Textarea(attrs={'rows': 4}), 'tipo': TipoProposicaoSelect(), - 'hash_code': forms.HiddenInput(),} + 'hash_code': forms.HiddenInput(), } def __init__(self, *args, **kwargs): self.texto_articulado_proposicao = sapl.base.models.AppConfig.attr( @@ -1222,7 +1224,6 @@ class ProposicaoForm(forms.ModelForm): # FIXME hash para textos articulados inst.hash_code = 'P' + ta.hash() + '/' + str(inst.pk) - def clean(self): super(ProposicaoForm, self).clean() diff --git a/sapl/materia/models.py b/sapl/materia/models.py index 66fd94900..51fbcb855 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -10,7 +10,7 @@ from django.utils import formats, timezone from django.utils.translation import ugettext_lazy as _ from model_utils import Choices -from sapl.base.models import Autor, SEQUENCIA_NUMERACAO +from sapl.base.models import SEQUENCIA_NUMERACAO, Autor from sapl.comissoes.models import Comissao from sapl.compilacao.models import (PerfilEstruturalTextoArticulado, TextoArticulado) diff --git a/sapl/materia/receivers.py b/sapl/materia/receivers.py index 6e4ee737e..945c6636e 100644 --- a/sapl/materia/receivers.py +++ b/sapl/materia/receivers.py @@ -1,5 +1,6 @@ from django.db.models.signals import post_delete, post_save from django.dispatch import receiver + from sapl.materia.models import Tramitacao from sapl.materia.signals import tramitacao_signal from sapl.utils import get_base_url diff --git a/sapl/materia/tests/test_email_templates.py b/sapl/materia/tests/test_email_templates.py index 35b5f4ef2..aac13cbb7 100644 --- a/sapl/materia/tests/test_email_templates.py +++ b/sapl/materia/tests/test_email_templates.py @@ -1,4 +1,5 @@ from django.core import mail + from sapl.materia.email_utils import enviar_emails, load_email_templates diff --git a/sapl/materia/tests/test_materia.py b/sapl/materia/tests/test_materia.py index ff8f89ad6..4af9df7ea 100644 --- a/sapl/materia/tests/test_materia.py +++ b/sapl/materia/tests/test_materia.py @@ -1,12 +1,12 @@ import pytest -from django.db.models import Max from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.core.files.uploadedfile import SimpleUploadedFile from django.core.urlresolvers import reverse +from django.db.models import Max from model_mommy import mommy + from sapl.base.models import Autor, TipoAutor -from sapl.parlamentares.models import Legislatura from sapl.comissoes.models import Comissao, TipoComissao from sapl.materia.models import (Anexada, Autoria, DespachoInicial, DocumentoAcessorio, MateriaLegislativa, @@ -16,6 +16,7 @@ from sapl.materia.models import (Anexada, Autoria, DespachoInicial, Tramitacao, UnidadeTramitacao) from sapl.norma.models import (LegislacaoCitada, NormaJuridica, TipoNormaJuridica) +from sapl.parlamentares.models import Legislatura from sapl.utils import models_with_gr_for_model @@ -509,32 +510,30 @@ def test_form_errors_proposicao(admin_client): ['Este campo é obrigatório.']) - @pytest.mark.django_db(transaction=False) def test_numeracao_materia_legislativa_por_legislatura(admin_client): - #Criar Legislaturas + # Criar Legislaturas legislatura1 = mommy.make(Legislatura, - data_inicio='2014-01-01', - data_fim='2018-12-31', - numero=20, - data_eleicao='2013-10-15' - ) + data_inicio='2014-01-01', + data_fim='2018-12-31', + numero=20, + data_eleicao='2013-10-15' + ) legislatura2 = mommy.make(Legislatura, - data_inicio='2009-01-01', - data_fim='2013-12-31', - numero=21, - data_eleicao='2018-10-15' - ) - + data_inicio='2009-01-01', + data_fim='2013-12-31', + numero=21, + data_eleicao='2018-10-15' + ) # Cria uma materia na legislatura1 - tipo_materia = mommy.make(TipoMateriaLegislativa, id=1,sequencia_numeracao='L') + tipo_materia = mommy.make(TipoMateriaLegislativa, id=1, sequencia_numeracao='L') materia = mommy.make(MateriaLegislativa, - tipo=tipo_materia, - ano=2017, - numero=1 - ) + tipo=tipo_materia, + ano=2017, + numero=1 + ) url = reverse('sapl.materia:recuperar_materia') @@ -557,13 +556,12 @@ def test_numeracao_materia_legislativa_por_legislatura(admin_client): def test_numeracao_materia_legislativa_por_ano(admin_client): # Cria uma materia - tipo_materia = mommy.make(TipoMateriaLegislativa, id=1,sequencia_numeracao='A') + tipo_materia = mommy.make(TipoMateriaLegislativa, id=1, sequencia_numeracao='A') materia = mommy.make(MateriaLegislativa, - tipo=tipo_materia, - ano=2017, - numero=1 - ) - + tipo=tipo_materia, + ano=2017, + numero=1 + ) url = reverse('sapl.materia:recuperar_materia') diff --git a/sapl/materia/tests/test_materia_form.py b/sapl/materia/tests/test_materia_form.py index f94a6cb8d..41ad04837 100644 --- a/sapl/materia/tests/test_materia_form.py +++ b/sapl/materia/tests/test_materia_form.py @@ -1,6 +1,7 @@ import pytest from django.utils.translation import ugettext as _ from model_mommy import mommy + from sapl.materia import forms from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa diff --git a/sapl/materia/urls.py b/sapl/materia/urls.py index 3a30800d2..934c4dbac 100644 --- a/sapl/materia/urls.py +++ b/sapl/materia/urls.py @@ -1,4 +1,5 @@ from django.conf.urls import include, url + from sapl.materia.views import (AcompanhamentoConfirmarView, AcompanhamentoExcluirView, AcompanhamentoMateriaView, AnexadaCrud, @@ -62,7 +63,7 @@ urlpatterns_materia = [ url(r'^materia/(?P[0-9]+)/create_simplificado$', CriarProtocoloMateriaView.as_view(), name='materia_create_simplificado'), - url(r'^materia/recuperar-materia',recuperar_materia, name='recuperar_materia'), + url(r'^materia/recuperar-materia', recuperar_materia, name='recuperar_materia'), url(r'^materia/(?P[0-9]+)/ta$', MateriaTaView.as_view(), name='materia_ta'), diff --git a/sapl/materia/views.py b/sapl/materia/views.py index ebbcca5e5..81a4dfcd1 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -2,6 +2,7 @@ from datetime import datetime from random import choice from string import ascii_letters, digits +import weasyprint from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML from django.contrib import messages @@ -22,8 +23,8 @@ from django.views.generic import CreateView, ListView, TemplateView, UpdateView from django.views.generic.base import RedirectView from django.views.generic.edit import FormView from django_filters.views import FilterView -import weasyprint +import sapl from sapl.base.models import Autor, CasaLegislativa from sapl.comissoes.models import Comissao, Participacao from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT, @@ -47,7 +48,6 @@ from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label, autor_modal, gerar_hash_arquivo, get_base_url, get_mime_type_from_file_extension, montar_row_autor, show_results_filter_set) -import sapl from .email_utils import do_envia_email_confirmacao from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, @@ -68,7 +68,6 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, TipoProposicao, Tramitacao, UnidadeTramitacao) from .signals import tramitacao_signal - AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia') OrigemCrud = CrudAux.build(Origem, '') diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index c9daaec9f..87a44d41f 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -8,6 +8,7 @@ from django.db import models from django.forms import ModelForm, widgets from django.utils import timezone from django.utils.translation import ugettext_lazy as _ + from sapl.crispy_layout_mixin import form_actions, to_row from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.settings import MAX_DOC_UPLOAD_SIZE diff --git a/sapl/norma/tests/test_norma.py b/sapl/norma/tests/test_norma.py index 8d40b7202..6603d7167 100644 --- a/sapl/norma/tests/test_norma.py +++ b/sapl/norma/tests/test_norma.py @@ -2,6 +2,7 @@ import pytest from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ from model_mommy import mommy + from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.norma.forms import (NormaJuridicaForm, NormaPesquisaSimplesForm, NormaRelacionadaForm) diff --git a/sapl/norma/urls.py b/sapl/norma/urls.py index 12ba05cba..93081c4fc 100644 --- a/sapl/norma/urls.py +++ b/sapl/norma/urls.py @@ -1,4 +1,5 @@ from django.conf.urls import include, url + from sapl.norma.views import (AssuntoNormaCrud, NormaCrud, NormaPesquisaView, NormaRelacionadaCrud, NormaTaView, TipoNormaCrud, TipoVinculoNormaJuridicaCrud, recuperar_norma, diff --git a/sapl/norma/views.py b/sapl/norma/views.py index 249d480b0..73e259a33 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -11,6 +11,7 @@ from django.views.generic import CreateView, ListView, TemplateView, UpdateView from django.views.generic.base import RedirectView from django.views.generic.edit import FormView from django_filters.views import FilterView + from sapl.base.models import AppConfig from sapl.compilacao.views import IntegracaoTaView from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, diff --git a/sapl/painel/views.py b/sapl/painel/views.py index 5acb06195..454b61d8e 100644 --- a/sapl/painel/views.py +++ b/sapl/painel/views.py @@ -11,6 +11,7 @@ from django.http.response import Http404, HttpResponseRedirect from django.shortcuts import render from django.utils import timezone from django.utils.translation import ugettext_lazy as _ + from sapl.base.models import AppConfig as ConfiguracoesAplicacao from sapl.base.models import CasaLegislativa from sapl.crud.base import Crud diff --git a/sapl/parlamentares/forms.py b/sapl/parlamentares/forms.py index 80c78cf82..a159ca233 100644 --- a/sapl/parlamentares/forms.py +++ b/sapl/parlamentares/forms.py @@ -14,6 +14,7 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from floppyforms.widgets import ClearableFileInput from image_cropping.widgets import CropWidget, ImageCropWidget + from sapl.base.models import Autor, TipoAutor from sapl.crispy_layout_mixin import form_actions, to_row from sapl.rules import SAPL_GROUP_VOTANTE diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py index 86e174f09..9d43e6d6a 100644 --- a/sapl/parlamentares/models.py +++ b/sapl/parlamentares/models.py @@ -5,6 +5,7 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from image_cropping.fields import ImageCropField, ImageRatioField from model_utils import Choices + from sapl.base.models import Autor from sapl.decorators import vigencia_atual from sapl.utils import (INDICADOR_AFASTAMENTO, LISTA_DE_UFS, YES_NO_CHOICES, diff --git a/sapl/parlamentares/tests/test_mandato.py b/sapl/parlamentares/tests/test_mandato.py index df0aabc7f..cc027da1f 100644 --- a/sapl/parlamentares/tests/test_mandato.py +++ b/sapl/parlamentares/tests/test_mandato.py @@ -2,6 +2,7 @@ from datetime import datetime import pytest from model_mommy import mommy + from sapl.parlamentares.models import Filiacao, Legislatura, Mandato pytestmark = pytest.mark.django_db diff --git a/sapl/parlamentares/tests/test_parlamentares.py b/sapl/parlamentares/tests/test_parlamentares.py index 4605f7af6..3bd7abf47 100644 --- a/sapl/parlamentares/tests/test_parlamentares.py +++ b/sapl/parlamentares/tests/test_parlamentares.py @@ -2,6 +2,7 @@ import pytest from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ from model_mommy import mommy + from sapl.parlamentares.forms import FrenteForm, LegislaturaForm, MandatoForm from sapl.parlamentares.models import (Dependente, Filiacao, Legislatura, Mandato, Parlamentar, Partido, diff --git a/sapl/parlamentares/urls.py b/sapl/parlamentares/urls.py index 4f7cd4c91..e383421c4 100644 --- a/sapl/parlamentares/urls.py +++ b/sapl/parlamentares/urls.py @@ -1,4 +1,5 @@ from django.conf.urls import include, url + from sapl.parlamentares.views import (CargoMesaCrud, ColigacaoCrud, ComposicaoColigacaoCrud, DependenteCrud, FiliacaoCrud, FrenteCrud, FrenteList, diff --git a/sapl/parlamentares/views.py b/sapl/parlamentares/views.py index 7654dde6c..8baaadda2 100644 --- a/sapl/parlamentares/views.py +++ b/sapl/parlamentares/views.py @@ -1,5 +1,5 @@ -from datetime import datetime import json +from datetime import datetime from django.contrib import messages from django.contrib.contenttypes.models import ContentType @@ -33,7 +33,6 @@ from .models import (CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa, NivelInstrucao, Parlamentar, Partido, SessaoLegislativa, SituacaoMilitar, TipoAfastamento, TipoDependente, Votante) - CargoMesaCrud = CrudAux.build(CargoMesa, 'cargo_mesa') PartidoCrud = CrudAux.build(Partido, 'partidos') SessaoLegislativaCrud = CrudAux.build(SessaoLegislativa, 'sessao_legislativa') diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 4f68478ce..de647a243 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -10,12 +10,13 @@ from django.db import models from django.forms import ModelForm from django.utils import timezone from django.utils.translation import ugettext_lazy as _ + from sapl.base.models import Autor, TipoAutor from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row from sapl.materia.models import (MateriaLegislativa, TipoMateriaLegislativa, UnidadeTramitacao) -from sapl.utils import (RANGE_ANOS, AnoNumeroOrderingFilter, - RangeWidgetOverride, autor_label, autor_modal, YES_NO_CHOICES) +from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter, + RangeWidgetOverride, autor_label, autor_modal) from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo, Protocolo, TipoDocumentoAdministrativo, @@ -363,7 +364,6 @@ class ProtocoloMateriaForm(ModelForm): empty_label='Selecione', ) - numero_materia = forms.CharField( label=_('Número matéria'), required=False) @@ -372,7 +372,7 @@ class ProtocoloMateriaForm(ModelForm): vincular_materia = forms.ChoiceField(label=_('Vincular a matéria existente?'), widget=forms.RadioSelect(), - choices= YES_NO_CHOICES, + choices=YES_NO_CHOICES, initial=False) numero_paginas = forms.CharField(label=_('Núm. Páginas'), required=True) @@ -414,7 +414,8 @@ class ProtocoloMateriaForm(ModelForm): if data['vincular_materia'] == 'True': try: if not data['ano_materia'] or not data['numero_materia']: - raise ValidationError('Favor informar o número e ano da matéria a ser vinculada') + raise ValidationError( + 'Favor informar o número e ano da matéria a ser vinculada') self.materia = MateriaLegislativa.objects.get(ano=data['ano_materia'], numero=data['numero_materia'], tipo=data['tipo_materia']) @@ -426,8 +427,6 @@ class ProtocoloMateriaForm(ModelForm): return data - - def __init__(self, *args, **kwargs): row1 = to_row( @@ -438,7 +437,7 @@ class ProtocoloMateriaForm(ModelForm): row2 = to_row( [('vincular_materia', 4), ('numero_materia', 4), - ('ano_materia', 4),]) + ('ano_materia', 4), ]) row3 = to_row( [('assunto_ementa', 12)]) row4 = to_row( diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py index 43e18ffd5..d4d45b3ad 100644 --- a/sapl/protocoloadm/models.py +++ b/sapl/protocoloadm/models.py @@ -2,6 +2,7 @@ import reversion 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 TipoMateriaLegislativa, UnidadeTramitacao from sapl.utils import RANGE_ANOS, YES_NO_CHOICES, texto_upload_path diff --git a/sapl/protocoloadm/tests/test_protocoloadm.py b/sapl/protocoloadm/tests/test_protocoloadm.py index 216a0f24d..f74c4dd7b 100644 --- a/sapl/protocoloadm/tests/test_protocoloadm.py +++ b/sapl/protocoloadm/tests/test_protocoloadm.py @@ -5,6 +5,7 @@ from django.core.urlresolvers import reverse from django.utils.encoding import force_text from django.utils.translation import ugettext_lazy as _ from model_mommy import mommy + from sapl.materia.models import UnidadeTramitacao from sapl.protocoloadm.forms import (AnularProcoloAdmForm, DocumentoAdministrativoForm, diff --git a/sapl/protocoloadm/urls.py b/sapl/protocoloadm/urls.py index 77512ff01..46fec9980 100644 --- a/sapl/protocoloadm/urls.py +++ b/sapl/protocoloadm/urls.py @@ -1,4 +1,5 @@ from django.conf.urls import include, url + from sapl.protocoloadm.views import (AnularProtocoloAdmView, ComprovanteProtocoloView, CriarDocumentoProtocolo, diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 14ba66d0f..b92975744 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -1,5 +1,4 @@ -import sapl from braces.views import FormValidMessageMixin from django.contrib import messages from django.contrib.auth.mixins import PermissionRequiredMixin @@ -15,6 +14,8 @@ 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_filters.views import FilterView + +import sapl from sapl.base.models import Autor from sapl.comissoes.models import Comissao from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination diff --git a/sapl/redireciona_urls/views.py b/sapl/redireciona_urls/views.py index 4f1480a13..64e03e36c 100644 --- a/sapl/redireciona_urls/views.py +++ b/sapl/redireciona_urls/views.py @@ -1,5 +1,6 @@ from django.core.urlresolvers import NoReverseMatch, reverse from django.views.generic import RedirectView + from sapl.base.apps import AppConfig as atasConfig from sapl.comissoes.apps import AppConfig as comissoesConfig from sapl.materia.apps import AppConfig as materiaConfig @@ -635,6 +636,7 @@ class RedirecionaMateriasPorAnoAutorTipo(RedirectView): return url + class RedirecionaReuniao(RedirectView): permanent = True diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py index eace383dd..00f33e44e 100644 --- a/sapl/relatorios/views.py +++ b/sapl/relatorios/views.py @@ -6,6 +6,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.http import Http404, HttpResponse from django.utils import timezone from django.utils.translation import ugettext_lazy as _ + from sapl.base.models import Autor, CasaLegislativa from sapl.comissoes.models import Comissao from sapl.materia.models import (Autoria, MateriaLegislativa, Numeracao, @@ -947,8 +948,8 @@ def get_etiqueta_protocolos(prots): dic['num_materia'] = '' for materia in MateriaLegislativa.objects.filter( numero_protocolo=p.numero, ano=p.ano): - dic['num_materia'] = materia.tipo.sigla + ' ' + str(materia.numero) + '/' + str(materia.ano) - + dic['num_materia'] = materia.tipo.sigla + ' ' + \ + str(materia.numero) + '/' + str(materia.ano) dic['natureza'] = '' if p.tipo_processo == 0: @@ -959,8 +960,6 @@ def get_etiqueta_protocolos(prots): else: dic['natureza'] = 'Legislativo' - - dic['num_documento'] = '' for documento in DocumentoAdministrativo.objects.filter( protocolo=p): diff --git a/sapl/rules/apps.py b/sapl/rules/apps.py index 2b03bf239..606190110 100644 --- a/sapl/rules/apps.py +++ b/sapl/rules/apps.py @@ -10,6 +10,7 @@ from django.db import models, router from django.db.utils import DEFAULT_DB_ALIAS from django.utils.translation import ugettext_lazy as _ from django.utils.translation import string_concat + from sapl.rules import (SAPL_GROUP_ADMINISTRATIVO, SAPL_GROUP_COMISSOES, SAPL_GROUP_GERAL, SAPL_GROUP_MATERIA, SAPL_GROUP_NORMA, SAPL_GROUP_PAINEL, SAPL_GROUP_PROTOCOLO, diff --git a/sapl/rules/tests/test_rules.py b/sapl/rules/tests/test_rules.py index 8657290b8..aa97cb5e5 100644 --- a/sapl/rules/tests/test_rules.py +++ b/sapl/rules/tests/test_rules.py @@ -5,6 +5,7 @@ from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from django.utils import six from django.utils.translation import ugettext_lazy as _ + from sapl.base.models import (Argumento, CasaLegislativa, Constraint, ProblemaMigracao) from sapl.compilacao.models import (PerfilEstruturalTextoArticulado, diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index 59fd3391c..40b09c762 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -9,6 +9,7 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db import transaction from django.forms import ModelForm from django.utils.translation import ugettext_lazy as _ + from sapl.base.models import Autor, TipoAutor from sapl.crispy_layout_mixin import form_actions, to_row from sapl.materia.forms import MateriaLegislativaFilterSet diff --git a/sapl/sessao/tests/test_sessao_view.py b/sapl/sessao/tests/test_sessao_view.py index 29e27c169..082652c19 100644 --- a/sapl/sessao/tests/test_sessao_view.py +++ b/sapl/sessao/tests/test_sessao_view.py @@ -2,6 +2,7 @@ import pytest from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ from model_mommy import mommy + from sapl.parlamentares.models import Legislatura, SessaoLegislativa from sapl.sessao.models import SessaoPlenaria, TipoSessaoPlenaria diff --git a/sapl/sessao/urls.py b/sapl/sessao/urls.py index 729c43d58..18b1608df 100644 --- a/sapl/sessao/urls.py +++ b/sapl/sessao/urls.py @@ -1,4 +1,5 @@ from django.conf.urls import include, url + from sapl.sessao.views import (AdicionarVariasMateriasExpediente, AdicionarVariasMateriasOrdemDia, BancadaCrud, BlocoCrud, CargoBancadaCrud, diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index ab0f2fec4..57fa69c09 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -20,6 +20,7 @@ from django.views.generic.base import RedirectView from django.views.generic.detail import DetailView from django.views.generic.edit import FormMixin from django_filters.views import FilterView + from sapl.base.models import AppConfig as AppsAppConfig from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, MasterDetailCrud, @@ -592,7 +593,7 @@ class BlocoCrud(Crud): class ListView(Crud.ListView): template_name = 'crud/list_tabaux.html' - + class CreateView(Crud.CreateView): form_class = BlocoForm diff --git a/sapl/test_crispy_layout_mixin.py b/sapl/test_crispy_layout_mixin.py index bb063a445..2c72a1b44 100644 --- a/sapl/test_crispy_layout_mixin.py +++ b/sapl/test_crispy_layout_mixin.py @@ -1,6 +1,7 @@ from unittest import mock import rtyaml + from sapl.crispy_layout_mixin import read_layout_from_yaml diff --git a/sapl/test_urls.py b/sapl/test_urls.py index 9c462fc19..ebc88da2b 100644 --- a/sapl/test_urls.py +++ b/sapl/test_urls.py @@ -1,12 +1,12 @@ +import pytest from django.apps import apps from django.contrib.auth import get_user_model from django.contrib.auth.management import _get_all_permissions from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from django.db import transaction -from django.utils.translation import string_concat from django.utils.translation import ugettext_lazy as _ -import pytest +from django.utils.translation import string_concat from sapl.crud.base import PermissionRequiredForAppCrudMixin from sapl.rules.apps import AppConfig, update_groups @@ -14,7 +14,6 @@ from scripts.lista_urls import lista_urls from .settings import SAPL_APPS - pytestmark = pytest.mark.django_db sapl_appconfs = [apps.get_app_config(n[5:]) for n in SAPL_APPS] diff --git a/sapl/urls.py b/sapl/urls.py index d5d6cc652..38667b4e7 100644 --- a/sapl/urls.py +++ b/sapl/urls.py @@ -13,6 +13,13 @@ Including another URLconf 1. Add an import: from blog import urls as blog_urls 2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) """ +from django.conf import settings +from django.conf.urls import include, url +from django.conf.urls.static import static +from django.contrib import admin +from django.views.generic.base import RedirectView, TemplateView +from django.views.static import serve as view_static_server + import sapl.api.urls import sapl.base.urls import sapl.comissoes.urls @@ -26,12 +33,6 @@ import sapl.protocoloadm.urls import sapl.redireciona_urls.urls import sapl.relatorios.urls import sapl.sessao.urls -from django.conf import settings -from django.conf.urls import include, url -from django.conf.urls.static import static -from django.contrib import admin -from django.views.generic.base import RedirectView, TemplateView -from django.views.static import serve as view_static_server urlpatterns = [ url(r'^$', TemplateView.as_view(template_name='index.html'), diff --git a/sapl/utils.py b/sapl/utils.py index 80f1d3414..1e92bf7cd 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -1,11 +1,13 @@ -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 @@ -23,13 +25,10 @@ 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 from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row from sapl.settings import BASE_DIR - sapl_logger = logging.getLogger(BASE_DIR.name) @@ -49,7 +48,7 @@ def clear_thumbnails_cache(queryset, field): path = Path(getattr(r, field).path) if not path.exists(): - continue + continue cache_files = path.parent.walk() diff --git a/scripts/anonimizador/anon.py b/scripts/anonimizador/anon.py index 13aef6ad7..98618cee7 100644 --- a/scripts/anonimizador/anon.py +++ b/scripts/anonimizador/anon.py @@ -5,6 +5,7 @@ from string import digits from django.apps import apps from django.db.models.fields import CharField, TextField + from sapl.materia.models import Orgao, Origem from sapl.norma.models import AssuntoNorma from sapl.parlamentares.models import Municipio, NivelInstrucao, Partido diff --git a/scripts/convert_null_to_empty_in_all_char_fields.py b/scripts/convert_null_to_empty_in_all_char_fields.py index 2a8699217..8ad5243a7 100644 --- a/scripts/convert_null_to_empty_in_all_char_fields.py +++ b/scripts/convert_null_to_empty_in_all_char_fields.py @@ -1,5 +1,6 @@ from django.apps import apps from django.db import models + from sapl.settings import SAPL_APPS diff --git a/scripts/fk_protocoloadm_docadm.py b/scripts/fk_protocoloadm_docadm.py index cb66a74bd..a4294206c 100644 --- a/scripts/fk_protocoloadm_docadm.py +++ b/scripts/fk_protocoloadm_docadm.py @@ -3,6 +3,7 @@ from django.core.exceptions import ObjectDoesNotExist + from sapl.protocoloadm.models import DocumentoAdministrativo, Protocolo From 3b6134a4c9865a42c6feb4450b0a8a0b1d372fce Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 12 Mar 2018 13:52:20 -0300 Subject: [PATCH 057/121] Simplifica propriedades constantes --- sapl/base/views.py | 9 ++------- sapl/materia/views.py | 16 ++++------------ sapl/norma/views.py | 16 ++++------------ sapl/parlamentares/views.py | 8 ++------ sapl/protocoloadm/views.py | 4 +--- sapl/sessao/views.py | 12 +++--------- scripts/redbaron.py | 21 +++++++++++++++++++++ 7 files changed, 37 insertions(+), 49 deletions(-) diff --git a/sapl/base/views.py b/sapl/base/views.py index 2240a71ba..bcfc94635 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -683,13 +683,8 @@ class AppConfigCrud(CrudAux): class BaseMixin(CrudAux.BaseMixin): form_class = ConfiguracoesAppForm - @property - def list_url(self): - return '' - - @property - def create_url(self): - return '' + list_url = '' + create_url = '' class CreateView(CrudAux.CreateView): diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 81a4dfcd1..31ce86c43 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -1055,9 +1055,7 @@ class TramitacaoCrud(MasterDetailCrud): class UpdateView(MasterDetailCrud.UpdateView): form_class = TramitacaoUpdateForm - @property - def layout_key(self): - return 'TramitacaoUpdate' + layout_key = 'TramitacaoUpdate' def form_valid(self, form): self.object = form.save() @@ -1281,9 +1279,7 @@ class LegislacaoCitadaCrud(MasterDetailCrud): class DetailView(MasterDetailCrud.DetailView): - @property - def layout_key(self): - return 'LegislacaoCitadaDetail' + layout_key = 'LegislacaoCitadaDetail' class DeleteView(MasterDetailCrud.DeleteView): pass @@ -1357,9 +1353,7 @@ class MateriaLegislativaCrud(Crud): class BaseMixin(Crud.BaseMixin): list_field_names = ['tipo', 'numero', 'ano', 'data_apresentacao'] - @property - def list_url(self): - return '' + list_url = '' @property def search_url(self): @@ -1389,9 +1383,7 @@ class MateriaLegislativaCrud(Crud): class DetailView(Crud.DetailView): - @property - def layout_key(self): - return 'MateriaLegislativaDetail' + layout_key = 'MateriaLegislativaDetail' class ListView(Crud.ListView, RedirectView): diff --git a/sapl/norma/views.py b/sapl/norma/views.py index 73e259a33..d74bc8857 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -60,9 +60,7 @@ class NormaRelacionadaCrud(MasterDetailCrud): class DetailView(MasterDetailCrud.DetailView): - @property - def layout_key(self): - return 'NormaRelacionadaDetail' + layout_key = 'NormaRelacionadaDetail' class NormaPesquisaView(FilterView): @@ -135,9 +133,7 @@ class NormaCrud(Crud): class BaseMixin(Crud.BaseMixin): list_field_names = ['tipo', 'numero', 'ano', 'ementa'] - @property - def list_url(self): - return '' + list_url = '' @property def search_url(self): @@ -159,9 +155,7 @@ class NormaCrud(Crud): def cancel_url(self): return self.search_url - @property - def layout_key(self): - return 'NormaJuridicaCreate' + layout_key = 'NormaJuridicaCreate' class ListView(Crud.ListView, RedirectView): @@ -175,9 +169,7 @@ class NormaCrud(Crud): class UpdateView(Crud.UpdateView): form_class = NormaJuridicaForm - @property - def layout_key(self): - return 'NormaJuridicaCreate' + layout_key = 'NormaJuridicaCreate' def get_initial(self): norma = NormaJuridica.objects.get(id=self.kwargs['pk']) diff --git a/sapl/parlamentares/views.py b/sapl/parlamentares/views.py index 8baaadda2..078483f35 100644 --- a/sapl/parlamentares/views.py +++ b/sapl/parlamentares/views.py @@ -420,16 +420,12 @@ class ParlamentarCrud(Crud): class UpdateView(Crud.UpdateView): form_class = ParlamentarForm - @property - def layout_key(self): - return 'ParlamentarUpdate' + layout_key = 'ParlamentarUpdate' class CreateView(Crud.CreateView): form_class = ParlamentarCreateForm - @property - def layout_key(self): - return 'ParlamentarCreate' + layout_key = 'ParlamentarCreate' def form_valid(self, form): """ diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index b92975744..ee03daaff 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -93,9 +93,7 @@ class DocumentoAdministrativoCrud(Crud): namespace = self.model._meta.app_config.name return reverse('%s:%s' % (namespace, 'pesq_doc_adm')) - @property - def list_url(self): - return '' + list_url = '' class ListView(RedirectView, DocumentoAdministrativoMixin, Crud.ListView): diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 57fa69c09..0e715e514 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -256,9 +256,7 @@ class MateriaOrdemDiaCrud(MasterDetailCrud): class DetailView(MasterDetailCrud.DetailView): - @property - def layout_key(self): - return 'OrdemDiaDetail' + layout_key = 'OrdemDiaDetail' class ListView(MasterDetailCrud.ListView): paginate_by = None @@ -530,9 +528,7 @@ class ExpedienteMateriaCrud(MasterDetailCrud): class DetailView(MasterDetailCrud.DetailView): - @property - def layout_key(self): - return 'ExpedienteMateriaDetail' + layout_key = 'ExpedienteMateriaDetail' class OradorCrud(MasterDetailCrud): @@ -638,9 +634,7 @@ class SessaoCrud(Crud): list_field_names = ['data_inicio', 'legislatura', 'sessao_legislativa', 'tipo'] - @property - def list_url(self): - return '' + list_url = '' @property def search_url(self): diff --git a/scripts/redbaron.py b/scripts/redbaron.py index c3d0894df..3229872bc 100644 --- a/scripts/redbaron.py +++ b/scripts/redbaron.py @@ -2,6 +2,7 @@ import os import re from redbaron import RedBaron +from redbaron.nodes import EndlNode, ReturnNode, StringNode root = '/home/mazza/work/sapl' @@ -85,3 +86,23 @@ def local(node): node.absolute_bounding_box.top_left.line) os.system("echo '%s' | xclip -selection c" % res) return res + + +def acha_props_constantes(red): + "Enumera nós property que apenas retornam uma constante" + for fun in red('def'): + if fun.decorators.dumps().strip() == '@property': + nos = [n for n in fun.value if not isinstance(n, EndlNode)] + if len(nos) == 1: + [ret] = nos + if (isinstance(ret, ReturnNode) + and isinstance(ret.value, StringNode)): + yield fun + + +def corrige_props_constantes(reds): + "Troca nós property que apenas retornam uma constante por um assign" + pp = [p for red in reds for p in acha_props_constantes(red)] + for p in pp: + p.parent.value[p.index_on_parent] = '{} = {}'.format(p.name, p('return')('string').dumps()) + write(p) From 29e94455e3a1f3d0b066090fdd60864834d9d208 Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Tue, 13 Mar 2018 08:13:02 -0300 Subject: [PATCH 058/121] Fix #1566 (#1750) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adiciona a model, forms e views da reunião de comissão * Adiciona a model, forms e views da reunião de comissão * Adiciona a model, forms e views da reunião de comissão * Adiciona telas de cadastro de reunião * Adiciona telas de cadastro de reunião * Adiciona layouts e legacy * Adiciona template, modifica o subnav e o ListView * Troca Crud por MasterCrudDetail * Troca Crud por MasterCrudDetail * Troca Crud por MasterCrudDetail * Adiciona template de cadastro de reunião * Corrige Createview e Listview * Ajusta comissoes * Corrige o deleteview e o detailview * Muda o layout do create de reunião * - Retira o campo tipo de cadastro de reunião - Retira a obrigatoriedade do campo tema * Corrige migração * Adiciona Documento Acessorio em cadastro de reunião * Adiciona migração * Adiciona Documento Acessorio no Map Rules * Corrige alguns erros e adiciona mais detalhes no template * Pequena correção * Fix #1566 * Adiciona migração e corrige list view * Ajusta titulo de exibição do documento acessorio --- sapl/comissoes/forms.py | 56 ++++++++--- sapl/comissoes/legacy.yaml | 1 - .../migrations/0010_auto_20180307_1645.py | 29 ++++++ sapl/comissoes/migrations/0011_merge.py | 16 +++ .../migrations/0012_documentoacessorio.py | 36 +++++++ .../migrations/0013_auto_20180312_1533.py | 20 ++++ sapl/comissoes/models.py | 70 +++++++++++-- sapl/comissoes/urls.py | 9 +- sapl/comissoes/views.py | 98 ++++++++++++++----- sapl/materia/forms.py | 1 + sapl/rules/map_rules.py | 1 + .../templates/comissoes/cadastro_reuniao.html | 7 ++ .../comissoes/cadastro_reuniao_edit.html | 7 ++ sapl/templates/comissoes/layouts.yaml | 17 +++- sapl/templates/comissoes/subnav.yaml | 1 + 15 files changed, 319 insertions(+), 50 deletions(-) create mode 100644 sapl/comissoes/migrations/0010_auto_20180307_1645.py create mode 100644 sapl/comissoes/migrations/0011_merge.py create mode 100644 sapl/comissoes/migrations/0012_documentoacessorio.py create mode 100644 sapl/comissoes/migrations/0013_auto_20180312_1533.py create mode 100644 sapl/templates/comissoes/cadastro_reuniao.html create mode 100644 sapl/templates/comissoes/cadastro_reuniao_edit.html diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index ea27eab0d..e3d9845c3 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -7,7 +7,8 @@ from django.forms import ModelForm from django.utils.translation import ugettext_lazy as _ from sapl.base.models import Autor, TipoAutor -from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao +from sapl.comissoes.models import (Comissao, Composicao, DocumentoAcessorio, + Participacao, Reuniao) from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar @@ -155,20 +156,53 @@ class ReuniaoForm(ModelForm): class Meta: model = Reuniao exclude = ['cod_andamento_reuniao'] - widgets = { - 'hora_fim': forms.TimeInput(format='%H:%M'), - 'hora_inicio': forms.TimeInput(format='%H:%M'), - } def clean(self): super(ReuniaoForm, self).clean() - if self.errors: - return + if self.cleaned_data['hora_fim']: + if (self.cleaned_data['hora_fim'] < + self.cleaned_data['hora_inicio']): + msg = _('A hora de término da reunião não pode ser menor que a de início') + raise ValidationError(msg) + return self.cleaned_data + +class DocumentoAcessorioCreateForm(forms.ModelForm): + + parent_pk = forms.CharField(required=False) # widget=forms.HiddenInput()) + + class Meta: + model = DocumentoAcessorio + exclude = ['reuniao'] + + def __init__(self, user=None, **kwargs): + super(DocumentoAcessorioCreateForm, self).__init__(**kwargs) + + if self.instance: + reuniao = Reuniao.objects.get(id=self.initial['parent_pk']) + comissao = reuniao.comissao + comissao_pk = comissao.id + documentos = reuniao.documentoacessorio_set.all() + return self.create_documentoacessorio() + - if self.cleaned_data['hora_fim'] < self.cleaned_data['hora_inicio']: - msg = _('A hora de término da reunião não pode ' - 'ser menor que a de início') - raise ValidationError(msg) + def create_documentoacessorio(self): + reuniao = Reuniao.objects.get(id=self.initial['parent_pk']) + def clean(self): + super(DocumentoAcessorioCreateForm, self).clean() return self.cleaned_data + + +class DocumentoAcessorioEditForm(forms.ModelForm): + + parent_pk = forms.CharField(required=False) # widget=forms.HiddenInput()) + + class Meta: + model = DocumentoAcessorio + fields = ['nome', 'data', 'autor', 'ementa', + 'indexacao', 'arquivo'] + + def __init__(self, user=None, **kwargs): + super(DocumentoAcessorioEditForm, self).__init__(**kwargs) + diff --git a/sapl/comissoes/legacy.yaml b/sapl/comissoes/legacy.yaml index 2414df885..59aacf503 100644 --- a/sapl/comissoes/legacy.yaml +++ b/sapl/comissoes/legacy.yaml @@ -47,7 +47,6 @@ Participacao (ComposicaoComissao): Reuniao: periodo: periodo_reuniao comissao: cod_comissao - tipo: tipo_comissao numero: num_comissao nome: nom_reuniao tema: tem_reuniao diff --git a/sapl/comissoes/migrations/0010_auto_20180307_1645.py b/sapl/comissoes/migrations/0010_auto_20180307_1645.py new file mode 100644 index 000000000..45b86bec4 --- /dev/null +++ b/sapl/comissoes/migrations/0010_auto_20180307_1645.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-07 19:45 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0009_auto_20180301_1011'), + ] + + operations = [ + migrations.RemoveField( + model_name='reuniao', + name='tipo', + ), + migrations.AlterField( + model_name='reuniao', + name='nome', + field=models.CharField(max_length=150, verbose_name='Nome da Reunião'), + ), + migrations.AlterField( + model_name='reuniao', + name='tema', + field=models.CharField(blank=True, max_length=150, verbose_name='Tema da Reunião'), + ), + ] diff --git a/sapl/comissoes/migrations/0011_merge.py b/sapl/comissoes/migrations/0011_merge.py new file mode 100644 index 000000000..a5a3c7b7a --- /dev/null +++ b/sapl/comissoes/migrations/0011_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-09 10:27 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0010_auto_20180307_1645'), + ('comissoes', '0010_auto_20180306_0918'), + ] + + operations = [ + ] diff --git a/sapl/comissoes/migrations/0012_documentoacessorio.py b/sapl/comissoes/migrations/0012_documentoacessorio.py new file mode 100644 index 000000000..ed296ac21 --- /dev/null +++ b/sapl/comissoes/migrations/0012_documentoacessorio.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-09 12:38 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import sapl.comissoes.models +import sapl.utils + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0011_merge'), + ] + + operations = [ + migrations.CreateModel( + name='DocumentoAcessorio', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nome', models.CharField(max_length=50, verbose_name='Nome')), + ('data', models.DateField(blank=True, default=None, null=True, verbose_name='Data')), + ('autor', models.CharField(blank=True, max_length=50, verbose_name='Autor')), + ('ementa', models.TextField(blank=True, verbose_name='Ementa')), + ('indexacao', models.TextField(blank=True)), + ('arquivo', models.FileField(blank=True, null=True, upload_to=sapl.comissoes.models.anexo_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Texto Integral')), + ('data_ultima_atualizacao', models.DateTimeField(auto_now=True, null=True, verbose_name='Data')), + ('reuniao', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='documentoacessorio_set', to='comissoes.Reuniao')), + ], + options={ + 'verbose_name': 'Documento Acessório', + 'verbose_name_plural': 'Documentos Acessórios', + }, + ), + ] diff --git a/sapl/comissoes/migrations/0013_auto_20180312_1533.py b/sapl/comissoes/migrations/0013_auto_20180312_1533.py new file mode 100644 index 000000000..2210053ff --- /dev/null +++ b/sapl/comissoes/migrations/0013_auto_20180312_1533.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-12 18:33 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0012_documentoacessorio'), + ] + + operations = [ + migrations.AlterField( + model_name='documentoacessorio', + name='autor', + field=models.CharField(max_length=100, verbose_name='Autor'), + ), + ] diff --git a/sapl/comissoes/models.py b/sapl/comissoes/models.py index 2a5bd489c..f0b1b8d8b 100644 --- a/sapl/comissoes/models.py +++ b/sapl/comissoes/models.py @@ -182,15 +182,13 @@ class Participacao(models.Model): # ComposicaoComissao def get_comissao_media_path(instance, subpath, filename): return './sapl/comissao/%s/%s/%s' % (instance.numero, subpath, filename) - def pauta_upload_path(instance, filename): - return texto_upload_path(instance, filename, subpath='pauta', pk_first=True) + return texto_upload_path(instance, filename, subpath='pauta', pk_first=True) def ata_upload_path(instance, filename): return texto_upload_path(instance, filename, subpath='ata', pk_first=True) - def anexo_upload_path(instance, filename): return texto_upload_path(instance, filename, subpath='anexo', pk_first=True) @@ -204,15 +202,11 @@ class Reuniao(models.Model): Comissao, on_delete=models.PROTECT, verbose_name=_('Comissão')) - tipo = models.ForeignKey( - TipoComissao, - on_delete=models.PROTECT, - verbose_name=_('Tipo de Comissão')) numero = models.PositiveIntegerField(verbose_name=_('Número')) nome = models.CharField( - max_length=100, verbose_name=_('Nome da Reunião')) + max_length=150, verbose_name=_('Nome da Reunião')) tema = models.CharField( - max_length=100, verbose_name=_('Tema da Reunião')) + max_length=150, blank=True, verbose_name=_('Tema da Reunião')) data = models.DateField(verbose_name=_('Data')) hora_inicio = models.TimeField( verbose_name=_('Horário de Início (hh:mm)')) @@ -287,3 +281,61 @@ class Reuniao(models.Model): force_update=force_update, using=using, update_fields=update_fields) + + +@reversion.register() +class DocumentoAcessorio(models.Model): + reuniao = models.ForeignKey(Reuniao, + related_name='documentoacessorio_set', + on_delete=models.PROTECT) + nome = models.CharField(max_length=50, verbose_name=_('Nome')) + + data = models.DateField(blank=True, null=True, default=None, verbose_name=_('Data')) + autor = models.CharField( + max_length=100, verbose_name=_('Autor')) + ementa = models.TextField(blank=True, verbose_name=_('Ementa')) + indexacao = models.TextField(blank=True) + arquivo = models.FileField( + blank=True, + null=True, + upload_to=anexo_upload_path, + verbose_name=_('Texto Integral'), + validators=[restringe_tipos_de_arquivo_txt]) + + data_ultima_atualizacao = models.DateTimeField( + blank=True, null=True, + auto_now=True, + verbose_name=_('Data')) + + class Meta: + verbose_name = _('Documento Acessório') + verbose_name_plural = _('Documentos Acessórios') + + def __str__(self): + return _('%(nome)s por %(autor)s') % { + 'nome': self.nome, + 'autor': self.autor} + + def delete(self, using=None, keep_parents=False): + if self.arquivo: + self.arquivo.delete() + + return models.Model.delete( + self, using=using, keep_parents=keep_parents) + + def save(self, force_insert=False, force_update=False, using=None, + update_fields=None): + + if not self.pk and self.arquivo: + arquivo = self.arquivo + self.arquivo = None + models.Model.save(self, force_insert=force_insert, + force_update=force_update, + using=using, + update_fields=update_fields) + self.arquivo = arquivo + + return models.Model.save(self, force_insert=force_insert, + force_update=force_update, + using=using, + update_fields=update_fields) diff --git a/sapl/comissoes/urls.py b/sapl/comissoes/urls.py index 4bf1904aa..72886f1f1 100644 --- a/sapl/comissoes/urls.py +++ b/sapl/comissoes/urls.py @@ -1,9 +1,7 @@ from django.conf.urls import include, url - from sapl.comissoes.views import (CargoCrud, ComissaoCrud, ComposicaoCrud, - MateriasTramitacaoListView, ParticipacaoCrud, - PeriodoComposicaoCrud, ReuniaoCrud, - TipoComissaoCrud) + DocumentoAcessorioCrud, MateriasTramitacaoListView, ParticipacaoCrud, + PeriodoComposicaoCrud, ReuniaoCrud, TipoComissaoCrud) from .apps import AppConfig @@ -13,7 +11,8 @@ urlpatterns = [ url(r'^comissao/', include(ComissaoCrud.get_urls() + ComposicaoCrud.get_urls() + ReuniaoCrud.get_urls() + - ParticipacaoCrud.get_urls())), + ParticipacaoCrud.get_urls() + + DocumentoAcessorioCrud.get_urls())), url(r'^comissao/(?P\d+)/materias-em-tramitacao$', MateriasTramitacaoListView.as_view(), name='materias_em_tramitacao'), diff --git a/sapl/comissoes/views.py b/sapl/comissoes/views.py index 8324f4b6a..428f2bdab 100644 --- a/sapl/comissoes/views.py +++ b/sapl/comissoes/views.py @@ -1,23 +1,27 @@ from django.core.urlresolvers import reverse from django.db.models import F +from django.http.response import HttpResponseRedirect from django.views.decorators.clickjacking import xframe_options_exempt from django.views.generic import ListView from django.views.generic.base import RedirectView from django.views.generic.detail import DetailView from django.views.generic.edit import FormMixin + from sapl.base.models import AppConfig as AppsAppConfig -from sapl.comissoes.apps import AppConfig -from sapl.comissoes.forms import ParticipacaoCreateForm, ParticipacaoEditForm -from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, - MasterDetailCrud, - PermissionRequiredForAppCrudMixin) +from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, + CrudAux, MasterDetailCrud, + PermissionRequiredForAppCrudMixin) +from sapl.comissoes.forms import (ComissaoForm, DocumentoAcessorioCreateForm, + DocumentoAcessorioEditForm, ParticipacaoCreateForm, + ParticipacaoEditForm, ReuniaoForm) from sapl.materia.models import MateriaLegislativa, Tramitacao -from .forms import ComissaoForm, ReuniaoForm -from .models import (CargoComissao, Comissao, Composicao, Participacao, - Periodo, Reuniao, TipoComissao) + +from .models import (CargoComissao, Comissao, Composicao, DocumentoAcessorio, + Participacao, Periodo, TipoComissao, Reuniao) +from sapl.comissoes.apps import AppConfig def pegar_url_composicao(pk): @@ -26,6 +30,11 @@ def pegar_url_composicao(pk): url = reverse('sapl.comissoes:composicao_detail', kwargs={'pk': comp_pk}) return url +def pegar_url_reuniao(pk): + documentoacessorio = DocumentoAcessorio.objects.get(id=pk) + r_pk = documentoacessorio.reuniao.pk + url = reverse('sapl.comissoes:reuniao_detail', kwargs={'pk': r_pk}) + return url CargoCrud = CrudAux.build(CargoComissao, 'cargo_comissao') PeriodoComposicaoCrud = CrudAux.build(Periodo, 'periodo_composicao_comissao') @@ -58,7 +67,6 @@ class ParticipacaoCrud(MasterDetailCrud): form_class = ParticipacaoEditForm class DeleteView(MasterDetailCrud.DeleteView): - def get_success_url(self): composicao_comissao_pk = self.object.composicao.comissao.pk composicao_pk = self.object.composicao.pk @@ -146,22 +154,44 @@ class MateriasTramitacaoListView(ListView): context['object'] = Comissao.objects.get(id=self.kwargs['pk']) return context - class ReuniaoCrud(MasterDetailCrud): model = Reuniao parent_field = 'comissao' + model_set = 'documentoacessorio_set' public = [RP_LIST, RP_DETAIL, ] class BaseMixin(MasterDetailCrud.BaseMixin): - list_field_names = ['nome', 'tema', 'comissao'] - - @property - def list_url(self): - return '' + list_field_names = [ 'nome', 'tema', 'data'] class ListView(MasterDetailCrud.ListView): paginate_by = 10 + def take_reuniao_pk(self): + try: + return int(self.request.GET['pk']) + except: + return 0 + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + reuniao_pk = self.take_reuniao_pk() + + if reuniao_pk == 0: + ultima_reuniao = list(context['reuniao_list']) + if len(ultima_reuniao) > 0: + ultimo = ultima_reuniao[-1] + context['reuniao_pk'] = ultimo.pk + else: + context['reuniao_pk'] = 0 + else: + context['reuniao_pk'] = reuniao_pk + + context['documentoacessorio_set'] = DocumentoAcessorio.objects.filter( + reuniao__pk=context['reuniao_pk'] + ).order_by('id') + return context + class UpdateView(MasterDetailCrud.UpdateView): form_class = ReuniaoForm @@ -172,15 +202,37 @@ class ReuniaoCrud(MasterDetailCrud): form_class = ReuniaoForm def get_initial(self): - comissao = Comissao.objects.get(id=self.kwargs['pk']) + comissao = Comissao.objects.get(id=self.kwargs['pk']) - return {'comissao': comissao} + return {'comissao': comissao} - class DeleteView(MasterDetailCrud.DeleteView): - pass - class DetailView(MasterDetailCrud.DetailView): +class DocumentoAcessorioCrud(MasterDetailCrud): + model = DocumentoAcessorio + parent_field = 'reuniao__comissao' + public = [RP_DETAIL, ] + ListView = None + link_return_to_parent_field = True + + class BaseMixin(MasterDetailCrud.BaseMixin): + list_field_names = ['nome', 'tipo', 'data', 'autor', 'arquivo'] - @xframe_options_exempt - def get(self, request, *args, **kwargs): - return super().get(request, *args, **kwargs) + class CreateView(MasterDetailCrud.CreateView): + form_class = DocumentoAcessorioCreateForm + + def get_initial(self): + initial = super().get_initial() + initial['parent_pk'] = self.kwargs['pk'] + return initial + + class UpdateView(MasterDetailCrud.UpdateView): + layout_key = 'DocumentoAcessorioEdit' + form_class = DocumentoAcessorioEditForm + + class DeleteView(MasterDetailCrud.DeleteView): + def delete(self, *args, **kwargs): + obj = self.get_object() + obj.delete() + return HttpResponseRedirect( + reverse('sapl.comissoes:reuniao_detail', + kwargs={'pk': obj.reuniao.pk})) \ No newline at end of file diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index a7cac7df5..d89f30578 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1266,6 +1266,7 @@ class ProposicaoForm(forms.ModelForm): inst.texto_original.delete() self.gerar_hash(inst, receber_recibo) + return super().save(commit) inst.ano = timezone.now().year diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index 65d6c0be2..d9d199276 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -90,6 +90,7 @@ rules_group_comissoes = { (comissoes.Participacao, __base__), (materia.Relatoria, __base__), (comissoes.Reuniao, __base__), + (comissoes.DocumentoAcessorio, __base__), ] } diff --git a/sapl/templates/comissoes/cadastro_reuniao.html b/sapl/templates/comissoes/cadastro_reuniao.html new file mode 100644 index 000000000..9682c56d5 --- /dev/null +++ b/sapl/templates/comissoes/cadastro_reuniao.html @@ -0,0 +1,7 @@ +{% extends "crud/detail.html" %} +{% load i18n %} +{% load crispy_forms_tags %} +{% block actions %}{% endblock %} +{% block detail_content %} + {% crispy form %} +{% endblock detail_content %} diff --git a/sapl/templates/comissoes/cadastro_reuniao_edit.html b/sapl/templates/comissoes/cadastro_reuniao_edit.html new file mode 100644 index 000000000..9682c56d5 --- /dev/null +++ b/sapl/templates/comissoes/cadastro_reuniao_edit.html @@ -0,0 +1,7 @@ +{% extends "crud/detail.html" %} +{% load i18n %} +{% load crispy_forms_tags %} +{% block actions %}{% endblock %} +{% block detail_content %} + {% crispy form %} +{% endblock detail_content %} diff --git a/sapl/templates/comissoes/layouts.yaml b/sapl/templates/comissoes/layouts.yaml index 231477a9c..f0a21799c 100644 --- a/sapl/templates/comissoes/layouts.yaml +++ b/sapl/templates/comissoes/layouts.yaml @@ -46,7 +46,7 @@ ParticipacaoEdit: Reuniao: {% trans 'Reunião' %}: - - periodo numero tipo + - periodo numero - nome tema local_reuniao - data hora_inicio hora_fim - url_video url_audio @@ -54,3 +54,18 @@ Reuniao: - upload_pauta upload_ata upload_anexo - comissao +DocumentoAcessorio: + {% trans 'Documento Acessório' %}: + - nome data + - autor arquivo + - indexacao + - ementa + +DocumentoAcessorioEdit: + {% trans 'Documento Acessório' %}: + - nome data + - autor arquivo + - indexacao + - ementa + + diff --git a/sapl/templates/comissoes/subnav.yaml b/sapl/templates/comissoes/subnav.yaml index 01c10b4f3..e7e49837b 100644 --- a/sapl/templates/comissoes/subnav.yaml +++ b/sapl/templates/comissoes/subnav.yaml @@ -8,3 +8,4 @@ url: materias_em_tramitacao - title: {% trans 'Reunião' %} url: reuniao_list + From 74f91f0f77e12107f939d35f53ea6d923d113f19 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Tue, 13 Mar 2018 08:13:27 -0300 Subject: [PATCH 059/121] =?UTF-8?q?Formata=20mudan=C3=A7a=20de=20linha=20n?= =?UTF-8?q?a=20exibi=C3=A7=C3=A3o=20de=20TextField=20(#1749)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/crispy_layout_mixin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/crispy_layout_mixin.py b/sapl/crispy_layout_mixin.py index 12a876b12..9b2f0867b 100644 --- a/sapl/crispy_layout_mixin.py +++ b/sapl/crispy_layout_mixin.py @@ -132,6 +132,8 @@ def get_field_display(obj, fieldname): value._meta.app_config.name, obj.content_type.model), args=(value.id,)), value) + elif 'TextField' in str_type_from_field: + display = value.replace('\n', '
    ') else: display = str(value) return verbose_name, display From 27f6365f5b9551544776eb1f1e3801bf88827954 Mon Sep 17 00:00:00 2001 From: Leandro Roberto da Silva Date: Tue, 13 Mar 2018 11:10:58 -0300 Subject: [PATCH 060/121] =?UTF-8?q?HOT-FIX:=20corrige=20chamada=20de=20m?= =?UTF-8?q?=C3=A9todo=20de=20superclasse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/base/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/base/views.py b/sapl/base/views.py index bcfc94635..b2966bdda 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -93,7 +93,7 @@ class TipoAutorCrud(CrudAux): object = self.get_object() if object.content_type: raise PermissionDenied() - return super().get(request, *args, **kwargs) + return super().dispatch(request, *args, **kwargs) class UpdateView(TipoAutorMixin, CrudAux.UpdateView): pass From a7faf06d9f2d2ab7f2b11cef3e1f051716832d6c Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 13 Mar 2018 11:15:55 -0300 Subject: [PATCH 061/121] Release: 3.1.61 --- 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 b30110edf..fa2a99809 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.60 + image: interlegis/sapl:3.1.61 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index bfbde4e22..acec9e0bd 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.60', + version='3.1.61', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 7e5eed7bbe97242e4a0caa68c3808f27269b815f Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Tue, 13 Mar 2018 07:59:31 -0300 Subject: [PATCH 062/121] =?UTF-8?q?corrige=20inser=C3=A7=C3=A3o=20autom?= =?UTF-8?q?=C3=A1tica=20na=20app=20compilacao?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/compilacao/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index 78d1e221e..f4b2b3e7a 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -2235,7 +2235,7 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin): if count_auto_insert: ordem = dp.criar_espaco( - espaco_a_criar=count_auto_insert, local=local_add) + espaco_a_criar=count_auto_insert, local='json_add_in') dp_pk = dp.pk dp.ordem = ordem From fd431d0bf911b631e17f28d5bead98ad1627395b Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Tue, 13 Mar 2018 13:25:00 -0300 Subject: [PATCH 063/121] modifica layout de cadastro de tipoautor --- sapl/base/views.py | 2 +- sapl/templates/base/tipoautor_list.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/base/views.py b/sapl/base/views.py index b2966bdda..70725432d 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -12,7 +12,6 @@ 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 ugettext_lazy as _ from django.utils.translation import string_concat from django.views.generic import (CreateView, DeleteView, DetailView, FormView, ListView, UpdateView) @@ -73,6 +72,7 @@ class TipoAutorCrud(CrudAux): return vn class ListView(CrudAux.ListView): + template_name = "base/tipoautor_list.html" def get_queryset(self): qs = CrudAux.ListView.get_queryset(self) diff --git a/sapl/templates/base/tipoautor_list.html b/sapl/templates/base/tipoautor_list.html index e7aaf98db..e6996dc7f 100644 --- a/sapl/templates/base/tipoautor_list.html +++ b/sapl/templates/base/tipoautor_list.html @@ -1,4 +1,4 @@ -{% extends "crud/list.html" %} +{% extends "crud/list_tabaux.html" %} {% load i18n base_tags %} From 6e9f6c9f68605bff845679c740be7b07be47da39 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Tue, 13 Mar 2018 13:51:04 -0300 Subject: [PATCH 064/121] recoloca import retirado em merge --- sapl/base/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sapl/base/views.py b/sapl/base/views.py index 70725432d..4dbf50ae2 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -13,6 +13,7 @@ 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 @@ -561,7 +562,8 @@ class CreateUsuarioView(PermissionRequiredMixin, CreateView): data = form.cleaned_data - new_user = get_user_model().objects.create(username=data['username'], email=data['email']) + new_user = get_user_model().objects.create( + username=data['username'], email=data['email']) new_user.first_name = data['firstname'] new_user.last_name = data['lastname'] new_user.set_password(data['password1']) From e1a12bbb0d2840d22bb501d4d2890deb4a0d200a Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 13 Mar 2018 15:42:19 -0300 Subject: [PATCH 065/121] Fix #1753 --- sapl/materia/views.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 31ce86c43..5be89a672 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -59,7 +59,7 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, ReceberProposicaoForm, RelatoriaForm, TramitacaoEmLoteFilterSet, filtra_tramitacao_destino, filtra_tramitacao_destino_and_status, - filtra_tramitacao_status) + filtra_tramitacao_status, UnidadeTramitacaoForm) from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, DespachoInicial, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao, @@ -613,6 +613,12 @@ class UnidadeTramitacaoCrud(CrudAux): row[1], row[2] = ('', ''), ('', '') return context + class UpdateView(Crud.UpdateView): + form_class = UnidadeTramitacaoForm + + class CreateView(Crud.CreateView): + form_class = UnidadeTramitacaoForm + class ProposicaoCrud(Crud): model = Proposicao From 724d9da732e0762a0e458e552b5acd7ed09043c8 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 14 Mar 2018 11:00:40 -0300 Subject: [PATCH 066/121] =?UTF-8?q?Revert=20"Formata=20mudan=C3=A7a=20de?= =?UTF-8?q?=20linha=20na=20exibi=C3=A7=C3=A3o=20de=20TextField=20(#1749)"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 74f91f0f77e12107f939d35f53ea6d923d113f19. --- sapl/crispy_layout_mixin.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sapl/crispy_layout_mixin.py b/sapl/crispy_layout_mixin.py index 9b2f0867b..12a876b12 100644 --- a/sapl/crispy_layout_mixin.py +++ b/sapl/crispy_layout_mixin.py @@ -132,8 +132,6 @@ def get_field_display(obj, fieldname): value._meta.app_config.name, obj.content_type.model), args=(value.id,)), value) - elif 'TextField' in str_type_from_field: - display = value.replace('\n', '
    ') else: display = str(value) return verbose_name, display From a5059cc1a06ace8451c7b4bf575210039e5bac70 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Wed, 14 Mar 2018 12:49:59 -0300 Subject: [PATCH 067/121] Fix #1756 (#1759) --- sapl/utils.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sapl/utils.py b/sapl/utils.py index 1e92bf7cd..38b05c9c3 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -401,10 +401,12 @@ def fabrica_validador_de_tipos_de_arquivo(lista, nome): if not os.path.splitext(value.path)[1][:1]: raise ValidationError(_( 'Não é possível fazer upload de arquivos sem extensão.')) - - mime = magic.from_buffer(value.read(), mime=True) - if mime not in lista: - raise ValidationError(_('Tipo de arquivo não suportado')) + try: + mime = magic.from_buffer(value.read(), mime=True) + if mime not in lista: + raise ValidationError(_('Tipo de arquivo não suportado')) + except FileNotFoundError: + raise ValidationError(_('Arquivo não encontrado')) # o nome é importante para as migrations restringe_tipos_de_arquivo.__name__ = nome return restringe_tipos_de_arquivo From 9230f2f1ce553a35e3b8a10f6ab2e85dd0c34ae5 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 14 Mar 2018 15:00:44 -0300 Subject: [PATCH 068/121] Release: 3.1.62 --- 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 fa2a99809..6b91b8a52 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.61 + image: interlegis/sapl:3.1.62 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index acec9e0bd..44cf36134 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.61', + version='3.1.62', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 4ef092b19fbb504fad389681f3b3f04ca89f6886 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 28 Feb 2018 17:33:41 -0300 Subject: [PATCH 069/121] =?UTF-8?q?Reorganiza=20c=C3=B3digo=20de=20migra?= =?UTF-8?q?=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao.py | 1160 +---------------- sapl/legacy/migracao_dados.py | 1155 ++++++++++++++++ sapl/legacy/migracao_documentos.py | 2 +- sapl/legacy/migracao_usuarios.py | 2 +- sapl/legacy/scripts/migra_um_db.sh | 6 +- sapl/legacy/scripts/scrap_original_forms.py | 2 +- sapl/legacy/scripts/study.py | 2 +- sapl/legacy/scripts/utils.py | 2 +- ...st_migration.py => test_migracao_dados.py} | 5 +- sapl/legacy/test_renames.py | 2 +- 10 files changed, 1174 insertions(+), 1164 deletions(-) create mode 100644 sapl/legacy/migracao_dados.py rename sapl/legacy/{test_migration.py => test_migracao_dados.py} (91%) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index b228acbc1..a8fed932f 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -1,1155 +1,9 @@ -import os -import re -from datetime import date -from functools import lru_cache, partial -from itertools import groupby -from subprocess import PIPE, call +from sapl.legacy.migracao_dados import migrar_dados +from sapl.legacy.migracao_documentos import migrar_documentos +from sapl.legacy.migracao_usuarios import migrar_usuarios -import pkg_resources -import reversion -import yaml -from django.apps import apps -from django.apps.config import AppConfig -from django.contrib.auth import get_user_model -from django.contrib.auth.models import Group -from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ObjectDoesNotExist -from django.db import connections, transaction -from django.db.models import Count, Max -from django.db.models.base import ModelBase -from pytz import timezone -from sapl.base.models import AppConfig as AppConf -from sapl.base.models import (Autor, ProblemaMigracao, TipoAutor, - cria_models_tipo_autor) -from sapl.comissoes.models import Comissao, Composicao, Participacao -from sapl.legacy.models import TipoNumeracaoProtocolo -from sapl.materia.models import (AcompanhamentoMateria, Proposicao, - StatusTramitacao, TipoDocumento, - TipoMateriaLegislativa, TipoProposicao, - Tramitacao) -from sapl.norma.models import (AssuntoNorma, NormaJuridica, NormaRelacionada, - TipoVinculoNormaJuridica) -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 -from sapl.settings import DATABASES, PROJECT_DIR -from sapl.utils import normalize - -from .timezonesbrasil import get_timezone - -# BASE ###################################################################### -# apps to be migrated, in app dependency order (very important) -appconfs = [apps.get_app_config(n) for n in [ - 'parlamentares', - 'comissoes', - 'base', - 'materia', - 'norma', - 'sessao', - 'lexml', - 'protocoloadm', ]] - -unique_constraints = [] -one_to_one_constraints = [] -primeira_vez = [] - -name_sets = [set(m.__name__ for m in ac.get_models()) for ac in appconfs] - -# apps do not overlap -for s1 in name_sets: - for s2 in name_sets: - if s1 is not s2: - assert not s1.intersection(s2) - -# apps include all legacy models -legacy_app = apps.get_app_config('legacy') -legacy_model_names = set(m.__name__ for m in legacy_app.get_models()) - -model_dict = {m.__name__: m for ac in appconfs for m in ac.get_models()} - - -# RENAMES ################################################################### - -MODEL_RENAME_PATTERN = re.compile('(.+) \((.+)\)') - - -def get_renames(): - field_renames = {} - model_renames = {} - for app in appconfs: - app_rename_data = yaml.load( - pkg_resources.resource_string(app.module.__name__, 'legacy.yaml')) - for model_name, renames in app_rename_data.items(): - match = MODEL_RENAME_PATTERN.match(model_name) - if match: - model_name, old_name = match.groups() - else: - old_name = None - model = getattr(app.models_module, model_name) - if old_name: - model_renames[model] = old_name - field_renames[model] = renames - - # collect renames from parent classes - for model, renames in field_renames.items(): - if any(parent in field_renames for parent in model.__mro__[1:]): - renames = {} - for parent in reversed(model.__mro__): - if parent in field_renames: - renames.update(field_renames[parent]) - field_renames[model] = renames - - # remove abstract classes - field_renames = {m: r for m, r in field_renames.items() - if not m._meta.abstract} - - return field_renames, model_renames - -# MIGRATION ################################################################# - - -def info(msg): - print('INFO: ' + msg) - - -def warn(msg): - print('CUIDADO! ' + msg) - - -class ForeignKeyFaltando(ObjectDoesNotExist): - 'Uma FK aponta para um registro inexistente' - - def __init__(self, msg=''): - self.msg = msg - - -@lru_cache() -def _get_all_ids_from_model(model): - # esta função para uso apenas em get_fk_related - return set(model.objects.values_list('id', flat=True)) - - -def get_fk_related(field, value, label=None): - if value is None and field.null: - return None - - # if field.related_model.objects.filter(id=value).exists(): - if value in _get_all_ids_from_model(field.related_model): - return value - elif value == 0 and field.null: - # consideramos zeros como nulos, se não está entre os ids anteriores - return None - else: - msg = 'FK [%s] não encontrada para o valor %s (em %s %s)' % ( - field.name, value, field.model.__name__, label or '---') - warn(msg) - raise ForeignKeyFaltando(msg) - - -def exec_sql(sql, db='default'): - cursor = connections[db].cursor() - cursor.execute(sql) - return cursor - - -exec_legado = partial(exec_sql, db='legacy') - - -def _formatar_lista_para_sql(iteravel): - lista = list(iteravel) - if lista: - return '({})'.format(str(lista)[1:-1]) # transforma "[...]" em "(...)" - else: - return None - - -def exec_legado_em_subconjunto(sql, ids): - """Executa uma query sql no legado no formato '.... in {}' - interpolando `ids`, se houver ids""" - - lista_sql = _formatar_lista_para_sql(ids) - if lista_sql: - return exec_legado(sql.format(lista_sql)) - else: - return [] - - -def primeira_coluna(cursor): - return (r[0] for r in cursor) - - -# UNIFORMIZAÇÃO DO BANCO ANTES DA MIGRAÇÃO ############################### - -SQL_NAO_TEM_TABELA = ''' - SELECT count(*) - FROM information_schema.columns - WHERE table_schema=database() - AND TABLE_NAME="{}" -''' - - -def existe_tabela_no_legado(tabela): - sql = SQL_NAO_TEM_TABELA.format(tabela) - return list(primeira_coluna(exec_legado(sql)))[0] - - -def existe_coluna_no_legado(tabela, coluna): - sql_nao_tem_coluna = SQL_NAO_TEM_TABELA + ' AND COLUMN_NAME="{}"' - sql = sql_nao_tem_coluna.format(tabela, coluna) - return list(primeira_coluna(exec_legado(sql)))[0] > 0 - - -def garante_coluna_no_legado(tabela, spec_coluna): - coluna = spec_coluna.split()[0] - if not existe_coluna_no_legado(tabela, coluna): - exec_legado('ALTER TABLE {} ADD COLUMN {}'.format(tabela, spec_coluna)) - assert existe_coluna_no_legado(tabela, coluna) - - -def garante_tabela_no_legado(create_table): - tabela = create_table.strip().splitlines()[0].split()[2] - if not existe_tabela_no_legado(tabela): - exec_legado(create_table) - assert existe_tabela_no_legado(tabela) - - -TABELAS_REFERENCIANDO_AUTOR = [ - # , - ('autoria', True), - ('documento_administrativo', True), - ('proposicao', True), - ('protocolo', False)] - - -def reverte_exclusao_de_autores_referenciados_no_legado(): - """Reverte a exclusão de autores que sejam referenciados de alguma forma - na base legada""" - - def get_autores_referenciados(tabela, tem_ind_excluido): - sql = '''select distinct cod_autor from {} - where cod_autor is not null - '''.format(tabela) - if tem_ind_excluido: - sql += ' and ind_excluido != 1' - return primeira_coluna(exec_legado(sql)) - - # reverte exclusões de autores referenciados por outras tabelas - autores_referenciados = { - cod - for tabela, tem_ind_excluido in TABELAS_REFERENCIANDO_AUTOR - for cod in get_autores_referenciados(tabela, tem_ind_excluido)} - exec_legado_em_subconjunto( - 'update autor set ind_excluido = 0 where cod_autor in {}', - autores_referenciados) - - -def get_reapontamento_de_autores_repetidos(autores): - """ Dada uma lista ordenada de pares (cod_zzz, cod_autor) retorna: - - * a lista de grupos de cod_autor'es repetidos - (quando há mais de um cod_autor para um mesmo cod_zzz) - - * a lista de cod_autor'es a serem apagados (todos além do 1o de cada grupo) - """ - grupos_de_repetidos = [ - [cod_autor for _, cod_autor in grupo] - for cod_zzz, grupo in groupby(autores, lambda r: r[0])] - # mantém apenas os grupos com mais de um autor por cod_zzz - grupos_de_repetidos = [g for g in grupos_de_repetidos if len(g) > 1] - # aponta cada autor de cada grupo de repetidos para o 1o do seu grupo - reapontamento = {autor: grupo[0] - for grupo in grupos_de_repetidos - for autor in grupo} - # apagaremos todos menos o primeiro - apagar = [k for k, v in reapontamento.items() if k != v] - return reapontamento, apagar - - -def get_autorias_sem_repeticoes(autoria, reapontamento): - "Autorias sem repetições de autores e com ind_primeiro_autor ajustado" - - # substitui cada autor repetido pelo 1o de seu grupo - autoria = sorted((reapontamento[a], m, i) for a, m, i in autoria) - # agrupa por [autor (1o do grupo de repetidos), materia], com - # ind_primeiro_autor == 1 se isso acontece em qualquer autor do grupo - autoria = [(a, m, max(i for a, m, i in grupo)) - for (a, m), grupo in groupby(autoria, lambda x: x[:2])] - return autoria - - -def unifica_autores_repetidos_no_legado(campo_agregador): - "Reúne autores repetidos em um único, antes da migracão" - - # enumeramos a repeticoes segundo o campo relevante - # (p. ex. cod_parlamentar ou cod_comissao) - # a ordenação prioriza, as entradas: - # - não excluidas, - # - em seguida as que têm col_username, - # - em seguida as que têm des_cargo - autores = exec_legado(''' - select {cod_parlamentar}, cod_autor from autor - where {cod_parlamentar} is not null - order by {cod_parlamentar}, - ind_excluido, col_username desc, des_cargo desc'''.format( - cod_parlamentar=campo_agregador)) - - reapontamento, apagar = get_reapontamento_de_autores_repetidos(autores) - - # se não houver autores repetidos encerramos por aqui - if not reapontamento: - return - - # Reaponta AUTORIA (many-to-many) - - # simplificamos retirando inicialmente as autorias excluidas - exec_legado('delete from autoria where ind_excluido = 1') - - # selecionamos as autorias envolvidas em repetições de autores - from_autoria = ' from autoria where cod_autor in {}' - autoria = exec_legado_em_subconjunto( - 'select cod_autor, cod_materia, ind_primeiro_autor' + from_autoria, - reapontamento) - - # apagamos todas as autorias envolvidas - exec_legado_em_subconjunto('delete ' + from_autoria, reapontamento) - # e depois inserimos apenas as sem repetições c ind_primeiro_autor ajustado - nova_autoria = get_autorias_sem_repeticoes(autoria, reapontamento) - exec_legado(''' - insert into autoria - (cod_autor, cod_materia, ind_primeiro_autor, ind_excluido) - values {}'''.format(', '.join([str((a, m, i, 0)) - for a, m, i in nova_autoria]))) - - # Reaponta outras tabelas que referenciam autor - for tabela, _ in TABELAS_REFERENCIANDO_AUTOR: - for antigo, novo in reapontamento.items(): - if antigo != novo: - exec_legado(''' - update {} set cod_autor = {} where cod_autor = {} - '''.format(tabela, novo, antigo)) - - # Finalmente excluimos os autores redundantes, - # cujas referências foram todas substituídas a essa altura - exec_legado_em_subconjunto('delete from autor where cod_autor in {}', - apagar) - - -def anula_tipos_origem_externa_invalidos(): - """Anula tipos de origem externa inválidos - para que não impeçam a migração da matéria""" - - tipos_validos = primeira_coluna(exec_legado(''' - select tip_materia - from tipo_materia_legislativa - where ind_excluido <> 1;''')) - - exec_legado_em_subconjunto(''' - update materia_legislativa - set tip_origem_externa = NULL - 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) - - -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') - - garante_coluna_no_legado('tipo_materia_legislativa', - 'ind_num_automatica BOOLEAN NULL DEFAULT FALSE') - - garante_coluna_no_legado('tipo_materia_legislativa', - 'quorum_minimo_votacao int(11) 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', - 'cod_presenca_sessao'): - exec_legado(''' - ALTER TABLE sessao_plenaria_presenca - DROP PRIMARY KEY, - ADD cod_presenca_sessao INT auto_increment PRIMARY KEY FIRST; - ''') - assert existe_coluna_no_legado('sessao_plenaria_presenca', - 'cod_presenca_sessao') - - garante_coluna_no_legado('sessao_plenaria_presenca', - 'dat_sessao DATE NULL') - - garante_tabela_no_legado(''' - CREATE TABLE lexml_registro_publicador ( - cod_publicador INT auto_increment NOT NULL, - id_publicador INT, nom_publicador varchar(255), - adm_email varchar(50), - sigla varchar(255), - nom_responsavel varchar(255), - tipo varchar(50), - id_responsavel INT, PRIMARY KEY (cod_publicador)); - ''') - - garante_tabela_no_legado(''' - CREATE TABLE lexml_registro_provedor ( - cod_provedor INT auto_increment NOT NULL, - id_provedor INT, nom_provedor varchar(255), - sgl_provedor varchar(15), - adm_email varchar(50), - nom_responsavel varchar(255), - tipo varchar(50), - id_responsavel INT, xml_provedor longtext, - PRIMARY KEY (cod_provedor)); - ''') - - garante_tabela_no_legado(''' - CREATE TABLE tipo_situacao_militar ( - tip_situacao_militar INT auto_increment NOT NULL, - des_tipo_situacao varchar(50), - ind_excluido INT, PRIMARY KEY (tip_situacao_militar)); - ''') - - update_specs = ''' -vinculo_norma_juridica| ind_excluido = '' | trim(ind_excluido) = '0' -unidade_tramitacao | cod_parlamentar = NULL | cod_parlamentar = 0 -parlamentar | cod_nivel_instrucao = NULL | cod_nivel_instrucao = 0 -parlamentar | tip_situacao_militar = NULL | tip_situacao_militar = 0 -mandato | tip_afastamento = NULL | tip_afastamento = 0 -relatoria | tip_fim_relatoria = NULL | tip_fim_relatoria = 0 - '''.strip().splitlines() - - for spec in update_specs: - spec = spec.split('|') - exec_legado('UPDATE {} SET {} WHERE {}'.format(*spec)) - - # retira apontamentos de materia para assunto inexistente - exec_legado('delete from materia_assunto where cod_assunto = 0') - - # corrige string "None" em autor - exec_legado('update autor set des_cargo = NULL where des_cargo = "None"') - - unifica_autores_repetidos_no_legado('cod_parlamentar') - unifica_autores_repetidos_no_legado('cod_comissao') - - # é importante reverter a exclusão de autores somente depois, para que a - # unificação possa dar prioridade às informações dos autores não excluídos - reverte_exclusao_de_autores_referenciados_no_legado() - - anula_tipos_origem_externa_invalidos() - - -def iter_sql_records(sql): - class Record: - pass - cursor = exec_legado(sql) - fieldnames = [name[0] for name in cursor.description] - for row in cursor.fetchall(): - record = Record() - record.__dict__.update(zip(fieldnames, row)) - yield record - - -def save_relation(obj, nome_campo='', problema='', descricao='', - eh_stub=False, critico=False): - link = ProblemaMigracao( - content_object=obj, nome_campo=nome_campo, problema=problema, - descricao=descricao, eh_stub=eh_stub, critico=critico) - link.save() - - -def fill_vinculo_norma_juridica(): - lista = [('A', 'Altera o(a)', - 'Alterado(a) pelo(a)'), - ('R', 'Revoga integralmente o(a)', - 'Revogado(a) integralmente pelo(a)'), - ('P', 'Revoga parcialmente o(a)', - 'Revogado(a) parcialmente pelo(a)'), - ('T', 'Revoga integralmente por consolidação', - 'Revogado(a) integralmente por consolidação'), - ('C', 'Norma correlata', - 'Norma correlata'), - ('S', 'Ressalva o(a)', - 'Ressalvada pelo(a)'), - ('E', 'Reedita o(a)', - 'Reeditada pelo(a)'), - ('I', 'Reedita com alteração o(a)', - 'Reeditada com alteração pelo(a)'), - ('G', 'Regulamenta o(a)', - 'Regulamentada pelo(a)'), - ('K', 'Suspende parcialmente o(a)', - 'Suspenso(a) parcialmente pelo(a)'), - ('L', 'Suspende integralmente o(a)', - 'Suspenso(a) integralmente pelo(a)'), - ('N', 'Julga integralmente inconstitucional', - 'Julgada integralmente inconstitucional'), - ('O', 'Julga parcialmente inconstitucional', - 'Julgada parcialmente inconstitucional')] - lista_objs = [TipoVinculoNormaJuridica( - sigla=item[0], descricao_ativa=item[1], descricao_passiva=item[2]) - for item in lista] - TipoVinculoNormaJuridica.objects.bulk_create(lista_objs) - - -def fill_dados_basicos(): - # Ajusta sequencia numérica e cria base.AppConfig - letra = 'A' - try: - tipo = TipoNumeracaoProtocolo.objects.latest('dat_inicial_protocolo') - if 'POR ANO' in tipo.des_numeracao_protocolo: - letra = 'A' - elif 'POR LEGISLATURA' in tipo.des_numeracao_protocolo: - letra = 'L' - elif 'CONSECUTIVO' in tipo.des_numeracao_protocolo: - letra = 'U' - except Exception as e: - pass - appconf = AppConf(sequencia_numeracao=letra) - appconf.save() - - -# Uma anomalia no sapl 2.5 causa a duplicação de registros de votação. -# Essa duplicação deve ser eliminada para que não haja erro no sapl 3.1 -def excluir_registrovotacao_duplicados(): - duplicatas_ids = RegistroVotacao.objects.values( - 'materia', 'ordem', 'expediente').annotate( - Count('id')).order_by().filter(id__count__gt=1) - duplicatas_queryset = RegistroVotacao.objects.filter( - materia__in=[item['materia'] for item in duplicatas_ids]) - - for dup in duplicatas_queryset: - lista_dups = duplicatas_queryset.filter( - materia=dup.materia, expediente=dup.expediente, ordem=dup.ordem) - primeiro_registro = lista_dups[0] - lista_dups = lista_dups.exclude(pk=primeiro_registro.pk) - for objeto in lista_dups: - if (objeto.pk > primeiro_registro.pk): - try: - objeto.delete() - except: - assert 0 - else: - try: - primeiro_registro.delete() - primeiro_registro = objeto - except: - assert 0 - - -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;' % ( - 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): - self.field_renames, self.model_renames = get_renames() - self.choice_valida = {} - - # configura timezone de migração - nome_legado = DATABASES['legacy']['NAME'] - match = re.match('sapl_cm_(.*)', nome_legado) - sigla_casa = match.group(1) - with open(os.path.expanduser('~/sapl_dumps/tabela_timezones.yaml'), 'r') as arq: - tabela_timezones = yaml.load(arq) - municipio, uf, nome_timezone = tabela_timezones[sigla_casa] - if nome_timezone: - self.timezone = timezone(nome_timezone) - else: - self.timezone = get_timezone(municipio, uf) - - def populate_renamed_fields(self, new, old): - renames = self.field_renames[type(new)] - - for field in new._meta.fields: - old_field_name = renames.get(field.name) - field_type = field.get_internal_type() - if old_field_name: - old_value = getattr(old, old_field_name) - - if field_type == 'ForeignKey': - # not necessarily a model - if hasattr(old, '_meta') and old._meta.pk.name != 'id': - label = old.pk - else: - label = '-- SEM PK --' - fk_field_name = '{}_id'.format(field.name) - value = get_fk_related(field, old_value, label) - setattr(new, fk_field_name, value) - else: - value = getattr(old, old_field_name) - - if (field_type in ['CharField', 'TextField'] - and value in [None, 'None']): - value = '' - - # adiciona timezone faltante aos campos com tempo - # os campos TIMESTAMP do mysql são gravados em UTC - # os DATETIME e TIME não têm timezone - def campo_tempo_sem_timezone(tipo): - return (field_type == tipo - and value and not value.tzinfo) - if campo_tempo_sem_timezone('DateTimeField'): - value = self.timezone.localize(value) - if campo_tempo_sem_timezone('TimeField'): - value = value.replace(tzinfo=self.timezone) - - setattr(new, field.name, value) - - def migrar(self, obj=appconfs, interativo=True): - # warning: model/app migration order is of utmost importance - - uniformiza_banco() - - # excluindo database antigo. - if interativo: - info('Todos os dados do banco serão excluidos. ' - 'Recomendamos que faça backup do banco sapl ' - 'antes de continuar.') - info('Deseja continuar? [s/n]') - resposta = input() - if resposta.lower() in ['s', 'sim', 'y', 'yes']: - pass - else: - info('Migração cancelada.') - return 0 - info('Excluindo entradas antigas do banco.') - call([PROJECT_DIR.child('manage.py'), 'flush', - '--database=default', '--no-input'], stdout=PIPE) - - # apaga tipos de autor padrão (criados no flush acima) - TipoAutor.objects.all().delete() - - fill_vinculo_norma_juridica() - fill_dados_basicos() - info('Começando migração: %s...' % obj) - self._do_migrate(obj) - - # 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() - - def _do_migrate(self, obj): - if isinstance(obj, AppConfig): - models_to_migrate = (model for model in obj.models.values() - if model in self.field_renames) - self._do_migrate(models_to_migrate) - elif isinstance(obj, ModelBase): - # A migração vai pular TipoProposicao e só vai migrar essa model - # antes de migrar Proposicao. Isso deve acontecer por causa da - # GenericRelation existente em TipoProposicao. - if not obj.__name__ == 'TipoProposicao': - if obj.__name__ == 'Proposicao': - self.migrate_model(TipoProposicao) - self.migrate_model(obj) - elif hasattr(obj, '__iter__'): - for item in obj: - self._do_migrate(item) - else: - raise TypeError( - 'Parameter must be a Model, AppConfig or a sequence of them') - - def migrate_model(self, model): - print('Migrando %s...' % model.__name__) - - 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) - - 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) - - def get_id_do_legado(old): - return getattr(old, nome_pk) - else: - # 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 - continue - new = model() - try: - self.populate_renamed_fields(new, old) - if ajuste_antes_salvar: - ajuste_antes_salvar(new, old) - 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: - 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) - - # 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 migrar(obj=appconfs, interativo=True): - dm = DataMigrator() - dm.migrar(obj, interativo) - - -# MIGRATION_ADJUSTMENTS ##################################################### - -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 - ano_novo = ano_original + 1 - protocolo = Protocolo.objects.filter(numero=old.num_protocolo, - ano=ano_novo) - if protocolo: - 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( - 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): - if old.dat_fim_mandato: - new.data_fim_mandato = old.dat_fim_mandato - if not new.data_fim_mandato: - legislatura = Legislatura.objects.latest('data_fim') - new.data_fim_mandato = legislatura.data_fim - new.data_expedicao_diploma = legislatura.data_inicio - if not new.data_inicio_mandato: - new.data_inicio_mandato = new.legislatura.data_inicio - new.data_fim_mandato = new.legislatura.data_fim - - -def adjust_ordemdia_antes_salvar(new, old): - new.votacao_aberta = False - - if not old.tip_votacao: - new.tipo_votacao = 1 - - if old.num_ordem is None: - new.numero_ordem = 999999999 - - -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' \ - ' nulo.' % old.pk - descricao = 'O valor %s foi colocado no lugar.' % new.numero_ordem - warn(problema + ' => ' + descricao) - save_relation(obj=new, problema=problema, - descricao=descricao, eh_stub=False) - reversion.set_comment('OrdemDia sem número da ordem.') - - -def adjust_parlamentar(new, old): - if old.ind_unid_deliberativa: - value = new.unidade_deliberativa - # Field is defined as not null in legacy db, - # but data includes null values - # => transform None to False - if value is None: - warn('nulo convertido para falso') - new.unidade_deliberativa = False - # migra município de residência - if old.cod_localidade_resid: - municipio_uf = list(exec_legado(''' - select nom_localidade, sgl_uf from localidade - where cod_localidade = {}'''.format(old.cod_localidade_resid))) - if municipio_uf: - new.municipio_residencia, new.uf_residencia = municipio_uf[0] - - -def adjust_participacao(new, old): - composicao = Composicao() - composicao.comissao_id, composicao.periodo_id = [ - get_fk_related(Composicao._meta.get_field(name), value) - for name, value in (('comissao', old.cod_comissao), - ('periodo', old.cod_periodo_comp))] - # check if there is already an "equal" one in the db - already_created = Composicao.objects.filter( - comissao=composicao.comissao, periodo=composicao.periodo) - if already_created: - assert len(already_created) == 1 # we must never have made 2 copies - [composicao] = already_created - else: - with reversion.create_revision(): - composicao.save() - reversion.set_comment('Objeto criado pela migração') - new.composicao = composicao - - -def adjust_proposicao_antes_salvar(new, old): - if new.data_envio: - new.ano = new.data_envio.year - - -def adjust_normarelacionada(new, old): - tipo = TipoVinculoNormaJuridica.objects.filter(sigla=old.tip_vinculo) - assert len(tipo) == 1 - new.tipo_vinculo = tipo[0] - - -def adjust_protocolo_antes_salvar(new, old): - if old.num_protocolo is None: - new.numero = old.cod_protocolo - - -def adjust_protocolo_depois_salvar(new, old): - if old.num_protocolo is None: - with reversion.create_revision(): - problema = 'Número do protocolo de PK %s é nulo' % new.pk - descricao = 'Número do protocolo alterado para %s!' % new.numero - warn(problema + ' => ' + descricao) - save_relation(obj=new, problema=problema, - descricao=descricao, eh_stub=False) - reversion.set_comment('Número de protocolo teve que ser alterado') - - -def adjust_registrovotacao_antes_salvar(new, old): - ordem_dia = OrdemDia.objects.filter( - pk=old.cod_ordem, materia=old.cod_materia) - expediente_materia = ExpedienteMateria.objects.filter( - pk=old.cod_ordem, materia=old.cod_materia) - - if ordem_dia and not expediente_materia: - new.ordem = ordem_dia[0] - if not ordem_dia and expediente_materia: - new.expediente = expediente_materia[0] - - -def adjust_tipoafastamento(new, old): - if old.ind_afastamento == 1: - new.indicador = 'A' - - -def adjust_tipoproposicao(new, old): - if old.ind_mat_ou_doc == 'M': - tipo_materia = TipoMateriaLegislativa.objects.filter( - pk=old.tip_mat_ou_doc) - if tipo_materia: - new.tipo_conteudo_related = tipo_materia[0] - else: - raise ForeignKeyFaltando - elif old.ind_mat_ou_doc == 'D': - tipo_documento = TipoDocumento.objects.filter(pk=old.tip_mat_ou_doc) - if tipo_documento: - new.tipo_conteudo_related = tipo_documento[0] - else: - raise ForeignKeyFaltando - - -def adjust_statustramitacao(new, old): - if old.ind_fim_tramitacao: - new.indicador = 'F' - elif old.ind_retorno_tramitacao: - new.indicador = 'R' - else: - new.indicador = '' - - -def adjust_statustramitacaoadm(new, old): - adjust_statustramitacao(new, old) - - -def adjust_tramitacao(new, old): - if old.sgl_turno == 'Ú': - new.turno = 'U' - - -def adjust_tipo_autor(new, old): - model_apontado = normalize(new.descricao.lower()).replace(' ', '') - content_types = ContentType.objects.filter( - model=model_apontado).exclude(app_label='legacy') - assert len(content_types) <= 1 - new.content_type = content_types[0] if content_types else None - - -def adjust_normajuridica_antes_salvar(new, old): - # Ajusta choice de esfera_federacao - # O 'S' vem de 'Selecionar'. Na versão antiga do SAPL, quando uma opção do - # combobox era selecionada, o sistema pegava a primeira letra da seleção, - # sendo F para Federal, E para Estadual, M para Municipal e o S para - # Selecionar, que era a primeira opção quando nada era selecionado. - if old.tip_esfera_federacao == 'S': - new.esfera_federacao = '' - - -def adjust_normajuridica_depois_salvar(new, old): - # Ajusta relação M2M - - if not old.cod_assunto: # it can be null or empty - return - - # lista de pks separadas por vírgulas (ignorando strings vazias) - lista_pks_assunto = [int(pk) for pk in old.cod_assunto.split(',') if pk] - - for pk_assunto in lista_pks_assunto: - try: - new.assuntos.add(AssuntoNorma.objects.get(pk=pk_assunto)) - except ObjectDoesNotExist: - pass # ignora assuntos inexistentes - - -def vincula_autor(new, old, model_relacionado, campo_relacionado, campo_nome): - pk_rel = getattr(old, campo_relacionado) - if pk_rel: - try: - new.autor_related = model_relacionado.objects.get(pk=pk_rel) - except ObjectDoesNotExist: - # ignoramos o autor órfão - 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 - - -def adjust_autor(new, old): - for args in [ - # essa ordem é importante - (Parlamentar, 'cod_parlamentar', 'nome_parlamentar'), - (Comissao, 'cod_comissao', 'nome'), - (Partido, 'cod_partido', 'nome')]: - if vincula_autor(new, old, *args): - 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) - # gera uma senha inutilizável, que precisará ser trocada - user.set_password(None) - with reversion.create_revision(): - user.save() - 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) - - -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): - new.ativa = True - else: - new.ativa = False - - -AJUSTE_ANTES_SALVAR = { - Autor: adjust_autor, - TipoAutor: adjust_tipo_autor, - AcompanhamentoMateria: adjust_acompanhamentomateria, - Comissao: adjust_comissao, - DocumentoAdministrativo: adjust_documentoadministrativo, - Mandato: adjust_mandato, - NormaJuridica: adjust_normajuridica_antes_salvar, - NormaRelacionada: adjust_normarelacionada, - OrdemDia: adjust_ordemdia_antes_salvar, - Parlamentar: adjust_parlamentar, - Participacao: adjust_participacao, - Proposicao: adjust_proposicao_antes_salvar, - Protocolo: adjust_protocolo_antes_salvar, - RegistroVotacao: adjust_registrovotacao_antes_salvar, - TipoAfastamento: adjust_tipoafastamento, - TipoProposicao: adjust_tipoproposicao, - StatusTramitacao: adjust_statustramitacao, - StatusTramitacaoAdministrativo: adjust_statustramitacaoadm, - Tramitacao: adjust_tramitacao, -} - -AJUSTE_DEPOIS_SALVAR = { - NormaJuridica: adjust_normajuridica_depois_salvar, - OrdemDia: adjust_ordemdia_depois_salvar, - Protocolo: adjust_protocolo_depois_salvar, -} - -# CHECKS #################################################################### - - -def get_ind_excluido(new): - 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) - - -def check_app_no_ind_excluido(app): - for model in app.models.values(): - assert not any(get_ind_excluido(new) for new in model.objects.all()) - print('OK!') +def migrar(interativo=False): + migrar_dados(interativo) + migrar_usuarios() + migrar_documentos() diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py new file mode 100644 index 000000000..374ac9f2c --- /dev/null +++ b/sapl/legacy/migracao_dados.py @@ -0,0 +1,1155 @@ +import os +import re +from datetime import date +from functools import lru_cache, partial +from itertools import groupby +from subprocess import PIPE, call + +import pkg_resources +import reversion +import yaml +from django.apps import apps +from django.apps.config import AppConfig +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group +from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import ObjectDoesNotExist +from django.db import connections, transaction +from django.db.models import Count, Max +from django.db.models.base import ModelBase +from pytz import timezone + +from sapl.base.models import AppConfig as AppConf +from sapl.base.models import (Autor, ProblemaMigracao, TipoAutor, + cria_models_tipo_autor) +from sapl.comissoes.models import Comissao, Composicao, Participacao +from sapl.legacy.models import TipoNumeracaoProtocolo +from sapl.materia.models import (AcompanhamentoMateria, Proposicao, + StatusTramitacao, TipoDocumento, + TipoMateriaLegislativa, TipoProposicao, + Tramitacao) +from sapl.norma.models import (AssuntoNorma, NormaJuridica, NormaRelacionada, + TipoVinculoNormaJuridica) +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 +from sapl.settings import DATABASES, PROJECT_DIR +from sapl.utils import normalize + +from .timezonesbrasil import get_timezone + +# BASE ###################################################################### +# apps to be migrated, in app dependency order (very important) +appconfs = [apps.get_app_config(n) for n in [ + 'parlamentares', + 'comissoes', + 'base', + 'materia', + 'norma', + 'sessao', + 'lexml', + 'protocoloadm', ]] + +unique_constraints = [] +one_to_one_constraints = [] +primeira_vez = [] + +name_sets = [set(m.__name__ for m in ac.get_models()) for ac in appconfs] + +# apps do not overlap +for s1 in name_sets: + for s2 in name_sets: + if s1 is not s2: + assert not s1.intersection(s2) + +# apps include all legacy models +legacy_app = apps.get_app_config('legacy') +legacy_model_names = set(m.__name__ for m in legacy_app.get_models()) + +model_dict = {m.__name__: m for ac in appconfs for m in ac.get_models()} + + +# RENAMES ################################################################### + +MODEL_RENAME_PATTERN = re.compile('(.+) \((.+)\)') + + +def get_renames(): + field_renames = {} + model_renames = {} + for app in appconfs: + app_rename_data = yaml.load( + pkg_resources.resource_string(app.module.__name__, 'legacy.yaml')) + for model_name, renames in app_rename_data.items(): + match = MODEL_RENAME_PATTERN.match(model_name) + if match: + model_name, old_name = match.groups() + else: + old_name = None + model = getattr(app.models_module, model_name) + if old_name: + model_renames[model] = old_name + field_renames[model] = renames + + # collect renames from parent classes + for model, renames in field_renames.items(): + if any(parent in field_renames for parent in model.__mro__[1:]): + renames = {} + for parent in reversed(model.__mro__): + if parent in field_renames: + renames.update(field_renames[parent]) + field_renames[model] = renames + + # remove abstract classes + field_renames = {m: r for m, r in field_renames.items() + if not m._meta.abstract} + + return field_renames, model_renames + +# MIGRATION ################################################################# + + +def info(msg): + print('INFO: ' + msg) + + +def warn(msg): + print('CUIDADO! ' + msg) + + +class ForeignKeyFaltando(ObjectDoesNotExist): + 'Uma FK aponta para um registro inexistente' + + def __init__(self, msg=''): + self.msg = msg + + +@lru_cache() +def _get_all_ids_from_model(model): + # esta função para uso apenas em get_fk_related + return set(model.objects.values_list('id', flat=True)) + + +def get_fk_related(field, value, label=None): + if value is None and field.null: + return None + + # if field.related_model.objects.filter(id=value).exists(): + if value in _get_all_ids_from_model(field.related_model): + return value + elif value == 0 and field.null: + # consideramos zeros como nulos, se não está entre os ids anteriores + return None + else: + msg = 'FK [%s] não encontrada para o valor %s (em %s %s)' % ( + field.name, value, field.model.__name__, label or '---') + warn(msg) + raise ForeignKeyFaltando(msg) + + +def exec_sql(sql, db='default'): + cursor = connections[db].cursor() + cursor.execute(sql) + return cursor + + +exec_legado = partial(exec_sql, db='legacy') + + +def _formatar_lista_para_sql(iteravel): + lista = list(iteravel) + if lista: + return '({})'.format(str(lista)[1:-1]) # transforma "[...]" em "(...)" + else: + return None + + +def exec_legado_em_subconjunto(sql, ids): + """Executa uma query sql no legado no formato '.... in {}' + interpolando `ids`, se houver ids""" + + lista_sql = _formatar_lista_para_sql(ids) + if lista_sql: + return exec_legado(sql.format(lista_sql)) + else: + return [] + + +def primeira_coluna(cursor): + return (r[0] for r in cursor) + + +# UNIFORMIZAÇÃO DO BANCO ANTES DA MIGRAÇÃO ############################### + +SQL_NAO_TEM_TABELA = ''' + SELECT count(*) + FROM information_schema.columns + WHERE table_schema=database() + AND TABLE_NAME="{}" +''' + + +def existe_tabela_no_legado(tabela): + sql = SQL_NAO_TEM_TABELA.format(tabela) + return list(primeira_coluna(exec_legado(sql)))[0] + + +def existe_coluna_no_legado(tabela, coluna): + sql_nao_tem_coluna = SQL_NAO_TEM_TABELA + ' AND COLUMN_NAME="{}"' + sql = sql_nao_tem_coluna.format(tabela, coluna) + return list(primeira_coluna(exec_legado(sql)))[0] > 0 + + +def garante_coluna_no_legado(tabela, spec_coluna): + coluna = spec_coluna.split()[0] + if not existe_coluna_no_legado(tabela, coluna): + exec_legado('ALTER TABLE {} ADD COLUMN {}'.format(tabela, spec_coluna)) + assert existe_coluna_no_legado(tabela, coluna) + + +def garante_tabela_no_legado(create_table): + tabela = create_table.strip().splitlines()[0].split()[2] + if not existe_tabela_no_legado(tabela): + exec_legado(create_table) + assert existe_tabela_no_legado(tabela) + + +TABELAS_REFERENCIANDO_AUTOR = [ + # , + ('autoria', True), + ('documento_administrativo', True), + ('proposicao', True), + ('protocolo', False)] + + +def reverte_exclusao_de_autores_referenciados_no_legado(): + """Reverte a exclusão de autores que sejam referenciados de alguma forma + na base legada""" + + def get_autores_referenciados(tabela, tem_ind_excluido): + sql = '''select distinct cod_autor from {} + where cod_autor is not null + '''.format(tabela) + if tem_ind_excluido: + sql += ' and ind_excluido != 1' + return primeira_coluna(exec_legado(sql)) + + # reverte exclusões de autores referenciados por outras tabelas + autores_referenciados = { + cod + for tabela, tem_ind_excluido in TABELAS_REFERENCIANDO_AUTOR + for cod in get_autores_referenciados(tabela, tem_ind_excluido)} + exec_legado_em_subconjunto( + 'update autor set ind_excluido = 0 where cod_autor in {}', + autores_referenciados) + + +def get_reapontamento_de_autores_repetidos(autores): + """ Dada uma lista ordenada de pares (cod_zzz, cod_autor) retorna: + + * a lista de grupos de cod_autor'es repetidos + (quando há mais de um cod_autor para um mesmo cod_zzz) + + * a lista de cod_autor'es a serem apagados (todos além do 1o de cada grupo) + """ + grupos_de_repetidos = [ + [cod_autor for _, cod_autor in grupo] + for cod_zzz, grupo in groupby(autores, lambda r: r[0])] + # mantém apenas os grupos com mais de um autor por cod_zzz + grupos_de_repetidos = [g for g in grupos_de_repetidos if len(g) > 1] + # aponta cada autor de cada grupo de repetidos para o 1o do seu grupo + reapontamento = {autor: grupo[0] + for grupo in grupos_de_repetidos + for autor in grupo} + # apagaremos todos menos o primeiro + apagar = [k for k, v in reapontamento.items() if k != v] + return reapontamento, apagar + + +def get_autorias_sem_repeticoes(autoria, reapontamento): + "Autorias sem repetições de autores e com ind_primeiro_autor ajustado" + + # substitui cada autor repetido pelo 1o de seu grupo + autoria = sorted((reapontamento[a], m, i) for a, m, i in autoria) + # agrupa por [autor (1o do grupo de repetidos), materia], com + # ind_primeiro_autor == 1 se isso acontece em qualquer autor do grupo + autoria = [(a, m, max(i for a, m, i in grupo)) + for (a, m), grupo in groupby(autoria, lambda x: x[:2])] + return autoria + + +def unifica_autores_repetidos_no_legado(campo_agregador): + "Reúne autores repetidos em um único, antes da migracão" + + # enumeramos a repeticoes segundo o campo relevante + # (p. ex. cod_parlamentar ou cod_comissao) + # a ordenação prioriza, as entradas: + # - não excluidas, + # - em seguida as que têm col_username, + # - em seguida as que têm des_cargo + autores = exec_legado(''' + select {cod_parlamentar}, cod_autor from autor + where {cod_parlamentar} is not null + order by {cod_parlamentar}, + ind_excluido, col_username desc, des_cargo desc'''.format( + cod_parlamentar=campo_agregador)) + + reapontamento, apagar = get_reapontamento_de_autores_repetidos(autores) + + # se não houver autores repetidos encerramos por aqui + if not reapontamento: + return + + # Reaponta AUTORIA (many-to-many) + + # simplificamos retirando inicialmente as autorias excluidas + exec_legado('delete from autoria where ind_excluido = 1') + + # selecionamos as autorias envolvidas em repetições de autores + from_autoria = ' from autoria where cod_autor in {}' + autoria = exec_legado_em_subconjunto( + 'select cod_autor, cod_materia, ind_primeiro_autor' + from_autoria, + reapontamento) + + # apagamos todas as autorias envolvidas + exec_legado_em_subconjunto('delete ' + from_autoria, reapontamento) + # e depois inserimos apenas as sem repetições c ind_primeiro_autor ajustado + nova_autoria = get_autorias_sem_repeticoes(autoria, reapontamento) + exec_legado(''' + insert into autoria + (cod_autor, cod_materia, ind_primeiro_autor, ind_excluido) + values {}'''.format(', '.join([str((a, m, i, 0)) + for a, m, i in nova_autoria]))) + + # Reaponta outras tabelas que referenciam autor + for tabela, _ in TABELAS_REFERENCIANDO_AUTOR: + for antigo, novo in reapontamento.items(): + if antigo != novo: + exec_legado(''' + update {} set cod_autor = {} where cod_autor = {} + '''.format(tabela, novo, antigo)) + + # Finalmente excluimos os autores redundantes, + # cujas referências foram todas substituídas a essa altura + exec_legado_em_subconjunto('delete from autor where cod_autor in {}', + apagar) + + +def anula_tipos_origem_externa_invalidos(): + """Anula tipos de origem externa inválidos + para que não impeçam a migração da matéria""" + + tipos_validos = primeira_coluna(exec_legado(''' + select tip_materia + from tipo_materia_legislativa + where ind_excluido <> 1;''')) + + exec_legado_em_subconjunto(''' + update materia_legislativa + set tip_origem_externa = NULL + 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) + + +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') + + garante_coluna_no_legado('tipo_materia_legislativa', + 'ind_num_automatica BOOLEAN NULL DEFAULT FALSE') + + garante_coluna_no_legado('tipo_materia_legislativa', + 'quorum_minimo_votacao int(11) 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', + 'cod_presenca_sessao'): + exec_legado(''' + ALTER TABLE sessao_plenaria_presenca + DROP PRIMARY KEY, + ADD cod_presenca_sessao INT auto_increment PRIMARY KEY FIRST; + ''') + assert existe_coluna_no_legado('sessao_plenaria_presenca', + 'cod_presenca_sessao') + + garante_coluna_no_legado('sessao_plenaria_presenca', + 'dat_sessao DATE NULL') + + garante_tabela_no_legado(''' + CREATE TABLE lexml_registro_publicador ( + cod_publicador INT auto_increment NOT NULL, + id_publicador INT, nom_publicador varchar(255), + adm_email varchar(50), + sigla varchar(255), + nom_responsavel varchar(255), + tipo varchar(50), + id_responsavel INT, PRIMARY KEY (cod_publicador)); + ''') + + garante_tabela_no_legado(''' + CREATE TABLE lexml_registro_provedor ( + cod_provedor INT auto_increment NOT NULL, + id_provedor INT, nom_provedor varchar(255), + sgl_provedor varchar(15), + adm_email varchar(50), + nom_responsavel varchar(255), + tipo varchar(50), + id_responsavel INT, xml_provedor longtext, + PRIMARY KEY (cod_provedor)); + ''') + + garante_tabela_no_legado(''' + CREATE TABLE tipo_situacao_militar ( + tip_situacao_militar INT auto_increment NOT NULL, + des_tipo_situacao varchar(50), + ind_excluido INT, PRIMARY KEY (tip_situacao_militar)); + ''') + + update_specs = ''' +vinculo_norma_juridica| ind_excluido = '' | trim(ind_excluido) = '0' +unidade_tramitacao | cod_parlamentar = NULL | cod_parlamentar = 0 +parlamentar | cod_nivel_instrucao = NULL | cod_nivel_instrucao = 0 +parlamentar | tip_situacao_militar = NULL | tip_situacao_militar = 0 +mandato | tip_afastamento = NULL | tip_afastamento = 0 +relatoria | tip_fim_relatoria = NULL | tip_fim_relatoria = 0 + '''.strip().splitlines() + + for spec in update_specs: + spec = spec.split('|') + exec_legado('UPDATE {} SET {} WHERE {}'.format(*spec)) + + # retira apontamentos de materia para assunto inexistente + exec_legado('delete from materia_assunto where cod_assunto = 0') + + # corrige string "None" em autor + exec_legado('update autor set des_cargo = NULL where des_cargo = "None"') + + unifica_autores_repetidos_no_legado('cod_parlamentar') + unifica_autores_repetidos_no_legado('cod_comissao') + + # é importante reverter a exclusão de autores somente depois, para que a + # unificação possa dar prioridade às informações dos autores não excluídos + reverte_exclusao_de_autores_referenciados_no_legado() + + anula_tipos_origem_externa_invalidos() + + +def iter_sql_records(sql): + class Record: + pass + cursor = exec_legado(sql) + fieldnames = [name[0] for name in cursor.description] + for row in cursor.fetchall(): + record = Record() + record.__dict__.update(zip(fieldnames, row)) + yield record + + +def save_relation(obj, nome_campo='', problema='', descricao='', + eh_stub=False, critico=False): + link = ProblemaMigracao( + content_object=obj, nome_campo=nome_campo, problema=problema, + descricao=descricao, eh_stub=eh_stub, critico=critico) + link.save() + + +def fill_vinculo_norma_juridica(): + lista = [('A', 'Altera o(a)', + 'Alterado(a) pelo(a)'), + ('R', 'Revoga integralmente o(a)', + 'Revogado(a) integralmente pelo(a)'), + ('P', 'Revoga parcialmente o(a)', + 'Revogado(a) parcialmente pelo(a)'), + ('T', 'Revoga integralmente por consolidação', + 'Revogado(a) integralmente por consolidação'), + ('C', 'Norma correlata', + 'Norma correlata'), + ('S', 'Ressalva o(a)', + 'Ressalvada pelo(a)'), + ('E', 'Reedita o(a)', + 'Reeditada pelo(a)'), + ('I', 'Reedita com alteração o(a)', + 'Reeditada com alteração pelo(a)'), + ('G', 'Regulamenta o(a)', + 'Regulamentada pelo(a)'), + ('K', 'Suspende parcialmente o(a)', + 'Suspenso(a) parcialmente pelo(a)'), + ('L', 'Suspende integralmente o(a)', + 'Suspenso(a) integralmente pelo(a)'), + ('N', 'Julga integralmente inconstitucional', + 'Julgada integralmente inconstitucional'), + ('O', 'Julga parcialmente inconstitucional', + 'Julgada parcialmente inconstitucional')] + lista_objs = [TipoVinculoNormaJuridica( + sigla=item[0], descricao_ativa=item[1], descricao_passiva=item[2]) + for item in lista] + TipoVinculoNormaJuridica.objects.bulk_create(lista_objs) + + +def fill_dados_basicos(): + # Ajusta sequencia numérica e cria base.AppConfig + letra = 'A' + try: + tipo = TipoNumeracaoProtocolo.objects.latest('dat_inicial_protocolo') + if 'POR ANO' in tipo.des_numeracao_protocolo: + letra = 'A' + elif 'POR LEGISLATURA' in tipo.des_numeracao_protocolo: + letra = 'L' + elif 'CONSECUTIVO' in tipo.des_numeracao_protocolo: + letra = 'U' + except Exception as e: + pass + appconf = AppConf(sequencia_numeracao=letra) + appconf.save() + + +# Uma anomalia no sapl 2.5 causa a duplicação de registros de votação. +# Essa duplicação deve ser eliminada para que não haja erro no sapl 3.1 +def excluir_registrovotacao_duplicados(): + duplicatas_ids = RegistroVotacao.objects.values( + 'materia', 'ordem', 'expediente').annotate( + Count('id')).order_by().filter(id__count__gt=1) + duplicatas_queryset = RegistroVotacao.objects.filter( + materia__in=[item['materia'] for item in duplicatas_ids]) + + for dup in duplicatas_queryset: + lista_dups = duplicatas_queryset.filter( + materia=dup.materia, expediente=dup.expediente, ordem=dup.ordem) + primeiro_registro = lista_dups[0] + lista_dups = lista_dups.exclude(pk=primeiro_registro.pk) + for objeto in lista_dups: + if (objeto.pk > primeiro_registro.pk): + try: + objeto.delete() + except: + assert 0 + else: + try: + primeiro_registro.delete() + primeiro_registro = objeto + except: + assert 0 + + +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;' % ( + 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): + self.field_renames, self.model_renames = get_renames() + self.choice_valida = {} + + # configura timezone de migração + nome_legado = DATABASES['legacy']['NAME'] + match = re.match('sapl_cm_(.*)', nome_legado) + sigla_casa = match.group(1) + with open(os.path.expanduser('~/migracao_sapl/sapl_dumps/tabela_timezones.yaml'), 'r') as arq: + tabela_timezones = yaml.load(arq) + municipio, uf, nome_timezone = tabela_timezones[sigla_casa] + if nome_timezone: + self.timezone = timezone(nome_timezone) + else: + self.timezone = get_timezone(municipio, uf) + + def populate_renamed_fields(self, new, old): + renames = self.field_renames[type(new)] + + for field in new._meta.fields: + old_field_name = renames.get(field.name) + field_type = field.get_internal_type() + if old_field_name: + old_value = getattr(old, old_field_name) + + if field_type == 'ForeignKey': + # not necessarily a model + if hasattr(old, '_meta') and old._meta.pk.name != 'id': + label = old.pk + else: + label = '-- SEM PK --' + fk_field_name = '{}_id'.format(field.name) + value = get_fk_related(field, old_value, label) + setattr(new, fk_field_name, value) + else: + value = getattr(old, old_field_name) + + if (field_type in ['CharField', 'TextField'] + and value in [None, 'None']): + value = '' + + # adiciona timezone faltante aos campos com tempo + # os campos TIMESTAMP do mysql são gravados em UTC + # os DATETIME e TIME não têm timezone + def campo_tempo_sem_timezone(tipo): + return (field_type == tipo + and value and not value.tzinfo) + if campo_tempo_sem_timezone('DateTimeField'): + value = self.timezone.localize(value) + if campo_tempo_sem_timezone('TimeField'): + value = value.replace(tzinfo=self.timezone) + + setattr(new, field.name, value) + + def migrar(self, obj=appconfs, interativo=True): + # warning: model/app migration order is of utmost importance + + uniformiza_banco() + + # excluindo database antigo. + if interativo: + info('Todos os dados do banco serão excluidos. ' + 'Recomendamos que faça backup do banco sapl ' + 'antes de continuar.') + info('Deseja continuar? [s/n]') + resposta = input() + if resposta.lower() in ['s', 'sim', 'y', 'yes']: + pass + else: + info('Migração cancelada.') + return 0 + info('Excluindo entradas antigas do banco.') + call([PROJECT_DIR.child('manage.py'), 'flush', + '--database=default', '--no-input'], stdout=PIPE) + + # apaga tipos de autor padrão (criados no flush acima) + TipoAutor.objects.all().delete() + + fill_vinculo_norma_juridica() + fill_dados_basicos() + info('Começando migração: %s...' % obj) + self._do_migrate(obj) + + # 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() + + def _do_migrate(self, obj): + if isinstance(obj, AppConfig): + models_to_migrate = (model for model in obj.models.values() + if model in self.field_renames) + self._do_migrate(models_to_migrate) + elif isinstance(obj, ModelBase): + # A migração vai pular TipoProposicao e só vai migrar essa model + # antes de migrar Proposicao. Isso deve acontecer por causa da + # GenericRelation existente em TipoProposicao. + if not obj.__name__ == 'TipoProposicao': + if obj.__name__ == 'Proposicao': + self.migrate_model(TipoProposicao) + self.migrate_model(obj) + elif hasattr(obj, '__iter__'): + for item in obj: + self._do_migrate(item) + else: + raise TypeError( + 'Parameter must be a Model, AppConfig or a sequence of them') + + def migrate_model(self, model): + print('Migrando %s...' % model.__name__) + + 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) + + 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) + + def get_id_do_legado(old): + return getattr(old, nome_pk) + else: + # 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 + continue + new = model() + try: + self.populate_renamed_fields(new, old) + if ajuste_antes_salvar: + ajuste_antes_salvar(new, old) + 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: + 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) + + # 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 migrar_dados(obj=appconfs, interativo=True): + dm = DataMigrator() + dm.migrar(obj, interativo) + + +# MIGRATION_ADJUSTMENTS ##################################################### + +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 + ano_novo = ano_original + 1 + protocolo = Protocolo.objects.filter(numero=old.num_protocolo, + ano=ano_novo) + if protocolo: + 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( + 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): + if old.dat_fim_mandato: + new.data_fim_mandato = old.dat_fim_mandato + if not new.data_fim_mandato: + legislatura = Legislatura.objects.latest('data_fim') + new.data_fim_mandato = legislatura.data_fim + new.data_expedicao_diploma = legislatura.data_inicio + if not new.data_inicio_mandato: + new.data_inicio_mandato = new.legislatura.data_inicio + new.data_fim_mandato = new.legislatura.data_fim + + +def adjust_ordemdia_antes_salvar(new, old): + new.votacao_aberta = False + + if not old.tip_votacao: + new.tipo_votacao = 1 + + if old.num_ordem is None: + new.numero_ordem = 999999999 + + +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' \ + ' nulo.' % old.pk + descricao = 'O valor %s foi colocado no lugar.' % new.numero_ordem + warn(problema + ' => ' + descricao) + save_relation(obj=new, problema=problema, + descricao=descricao, eh_stub=False) + reversion.set_comment('OrdemDia sem número da ordem.') + + +def adjust_parlamentar(new, old): + if old.ind_unid_deliberativa: + value = new.unidade_deliberativa + # Field is defined as not null in legacy db, + # but data includes null values + # => transform None to False + if value is None: + warn('nulo convertido para falso') + new.unidade_deliberativa = False + # migra município de residência + if old.cod_localidade_resid: + municipio_uf = list(exec_legado(''' + select nom_localidade, sgl_uf from localidade + where cod_localidade = {}'''.format(old.cod_localidade_resid))) + if municipio_uf: + new.municipio_residencia, new.uf_residencia = municipio_uf[0] + + +def adjust_participacao(new, old): + composicao = Composicao() + composicao.comissao_id, composicao.periodo_id = [ + get_fk_related(Composicao._meta.get_field(name), value) + for name, value in (('comissao', old.cod_comissao), + ('periodo', old.cod_periodo_comp))] + # check if there is already an "equal" one in the db + already_created = Composicao.objects.filter( + comissao=composicao.comissao, periodo=composicao.periodo) + if already_created: + assert len(already_created) == 1 # we must never have made 2 copies + [composicao] = already_created + else: + with reversion.create_revision(): + composicao.save() + reversion.set_comment('Objeto criado pela migração') + new.composicao = composicao + + +def adjust_proposicao_antes_salvar(new, old): + if new.data_envio: + new.ano = new.data_envio.year + + +def adjust_normarelacionada(new, old): + tipo = TipoVinculoNormaJuridica.objects.filter(sigla=old.tip_vinculo) + assert len(tipo) == 1 + new.tipo_vinculo = tipo[0] + + +def adjust_protocolo_antes_salvar(new, old): + if old.num_protocolo is None: + new.numero = old.cod_protocolo + + +def adjust_protocolo_depois_salvar(new, old): + if old.num_protocolo is None: + with reversion.create_revision(): + problema = 'Número do protocolo de PK %s é nulo' % new.pk + descricao = 'Número do protocolo alterado para %s!' % new.numero + warn(problema + ' => ' + descricao) + save_relation(obj=new, problema=problema, + descricao=descricao, eh_stub=False) + reversion.set_comment('Número de protocolo teve que ser alterado') + + +def adjust_registrovotacao_antes_salvar(new, old): + ordem_dia = OrdemDia.objects.filter( + pk=old.cod_ordem, materia=old.cod_materia) + expediente_materia = ExpedienteMateria.objects.filter( + pk=old.cod_ordem, materia=old.cod_materia) + + if ordem_dia and not expediente_materia: + new.ordem = ordem_dia[0] + if not ordem_dia and expediente_materia: + new.expediente = expediente_materia[0] + + +def adjust_tipoafastamento(new, old): + if old.ind_afastamento == 1: + new.indicador = 'A' + + +def adjust_tipoproposicao(new, old): + if old.ind_mat_ou_doc == 'M': + tipo_materia = TipoMateriaLegislativa.objects.filter( + pk=old.tip_mat_ou_doc) + if tipo_materia: + new.tipo_conteudo_related = tipo_materia[0] + else: + raise ForeignKeyFaltando + elif old.ind_mat_ou_doc == 'D': + tipo_documento = TipoDocumento.objects.filter(pk=old.tip_mat_ou_doc) + if tipo_documento: + new.tipo_conteudo_related = tipo_documento[0] + else: + raise ForeignKeyFaltando + + +def adjust_statustramitacao(new, old): + if old.ind_fim_tramitacao: + new.indicador = 'F' + elif old.ind_retorno_tramitacao: + new.indicador = 'R' + else: + new.indicador = '' + + +def adjust_statustramitacaoadm(new, old): + adjust_statustramitacao(new, old) + + +def adjust_tramitacao(new, old): + if old.sgl_turno == 'Ú': + new.turno = 'U' + + +def adjust_tipo_autor(new, old): + model_apontado = normalize(new.descricao.lower()).replace(' ', '') + content_types = ContentType.objects.filter( + model=model_apontado).exclude(app_label='legacy') + assert len(content_types) <= 1 + new.content_type = content_types[0] if content_types else None + + +def adjust_normajuridica_antes_salvar(new, old): + # Ajusta choice de esfera_federacao + # O 'S' vem de 'Selecionar'. Na versão antiga do SAPL, quando uma opção do + # combobox era selecionada, o sistema pegava a primeira letra da seleção, + # sendo F para Federal, E para Estadual, M para Municipal e o S para + # Selecionar, que era a primeira opção quando nada era selecionado. + if old.tip_esfera_federacao == 'S': + new.esfera_federacao = '' + + +def adjust_normajuridica_depois_salvar(new, old): + # Ajusta relação M2M + + if not old.cod_assunto: # it can be null or empty + return + + # lista de pks separadas por vírgulas (ignorando strings vazias) + lista_pks_assunto = [int(pk) for pk in old.cod_assunto.split(',') if pk] + + for pk_assunto in lista_pks_assunto: + try: + new.assuntos.add(AssuntoNorma.objects.get(pk=pk_assunto)) + except ObjectDoesNotExist: + pass # ignora assuntos inexistentes + + +def vincula_autor(new, old, model_relacionado, campo_relacionado, campo_nome): + pk_rel = getattr(old, campo_relacionado) + if pk_rel: + try: + new.autor_related = model_relacionado.objects.get(pk=pk_rel) + except ObjectDoesNotExist: + # ignoramos o autor órfão + 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 + + +def adjust_autor(new, old): + for args in [ + # essa ordem é importante + (Parlamentar, 'cod_parlamentar', 'nome_parlamentar'), + (Comissao, 'cod_comissao', 'nome'), + (Partido, 'cod_partido', 'nome')]: + if vincula_autor(new, old, *args): + 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) + # gera uma senha inutilizável, que precisará ser trocada + user.set_password(None) + with reversion.create_revision(): + user.save() + 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) + + +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): + new.ativa = True + else: + new.ativa = False + + +AJUSTE_ANTES_SALVAR = { + Autor: adjust_autor, + TipoAutor: adjust_tipo_autor, + AcompanhamentoMateria: adjust_acompanhamentomateria, + Comissao: adjust_comissao, + DocumentoAdministrativo: adjust_documentoadministrativo, + Mandato: adjust_mandato, + NormaJuridica: adjust_normajuridica_antes_salvar, + NormaRelacionada: adjust_normarelacionada, + OrdemDia: adjust_ordemdia_antes_salvar, + Parlamentar: adjust_parlamentar, + Participacao: adjust_participacao, + Proposicao: adjust_proposicao_antes_salvar, + Protocolo: adjust_protocolo_antes_salvar, + RegistroVotacao: adjust_registrovotacao_antes_salvar, + TipoAfastamento: adjust_tipoafastamento, + TipoProposicao: adjust_tipoproposicao, + StatusTramitacao: adjust_statustramitacao, + StatusTramitacaoAdministrativo: adjust_statustramitacaoadm, + Tramitacao: adjust_tramitacao, +} + +AJUSTE_DEPOIS_SALVAR = { + NormaJuridica: adjust_normajuridica_depois_salvar, + OrdemDia: adjust_ordemdia_depois_salvar, + Protocolo: adjust_protocolo_depois_salvar, +} + +# CHECKS #################################################################### + + +def get_ind_excluido(new): + 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) + + +def check_app_no_ind_excluido(app): + for model in app.models.values(): + assert not any(get_ind_excluido(new) for new in model.objects.all()) + print('OK!') diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index 9de759348..9ae46ef5d 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.migracao import exec_legado, warn +from sapl.legacy.migracao_dados import exec_legado, warn from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa, Proposicao) from sapl.norma.models import NormaJuridica diff --git a/sapl/legacy/migracao_usuarios.py b/sapl/legacy/migracao_usuarios.py index 39d6df4e9..962dfad6d 100644 --- a/sapl/legacy/migracao_usuarios.py +++ b/sapl/legacy/migracao_usuarios.py @@ -44,7 +44,7 @@ def decode_nome(nome): return nome -def migra_usuarios(): +def migrar_usuarios(): """ Lê o arquivo media/usuarios.yaml e importa os usuários nele listados, com senhas e perfis. diff --git a/sapl/legacy/scripts/migra_um_db.sh b/sapl/legacy/scripts/migra_um_db.sh index 3d41624d3..1a4e29920 100755 --- a/sapl/legacy/scripts/migra_um_db.sh +++ b/sapl/legacy/scripts/migra_um_db.sh @@ -4,7 +4,7 @@ if [ $# -ge 2 ]; then # proteje pasta com dumps de alterações acidentais - chmod -R -w ~/sapl_dumps + chmod -R -w ~/migracao_sapl/sapl_dumps DATE=$(date +%Y-%m-%d) DIR=~/${DATE}_logs_migracao @@ -21,11 +21,11 @@ if [ $# -ge 2 ]; then 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" < ~/sapl_dumps/$1.sql + mysql -u $2 -p "$3" < ~/migracao_sapl/sapl_dumps/$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 < ~/sapl_dumps/$1.sql + mysql -u $2 < ~/migracao_sapl/sapl_dumps/$1.sql fi; echo "O banco legado foi restaurado" |& tee -a $LOG echo >> $LOG diff --git a/sapl/legacy/scripts/scrap_original_forms.py b/sapl/legacy/scripts/scrap_original_forms.py index dbe8e4219..e7a7f3162 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.migracao import appconfs, get_renames +from sapl.legacy.migracao_dados 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 9a4149fe5..88838d36c 100644 --- a/sapl/legacy/scripts/study.py +++ b/sapl/legacy/scripts/study.py @@ -1,6 +1,6 @@ from django.apps import apps -from sapl.legacy.migracao import legacy_app +from sapl.legacy.migracao_dados 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 c426f1b3b..a983ef2b0 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.migracao import appconfs +from sapl.legacy.migracao_dados import appconfs def getsourcelines(model): diff --git a/sapl/legacy/test_migration.py b/sapl/legacy/test_migracao_dados.py similarity index 91% rename from sapl/legacy/test_migration.py rename to sapl/legacy/test_migracao_dados.py index ad1ad86d3..061264165 100644 --- a/sapl/legacy/test_migration.py +++ b/sapl/legacy/test_migracao_dados.py @@ -1,7 +1,8 @@ from random import shuffle -from .migracao import (_formatar_lista_para_sql, get_autorias_sem_repeticoes, - get_reapontamento_de_autores_repetidos) +from .migracao_dados import (_formatar_lista_para_sql, + get_autorias_sem_repeticoes, + get_reapontamento_de_autores_repetidos) def test_unifica_autores_repetidos_no_legado(): diff --git a/sapl/legacy/test_renames.py b/sapl/legacy/test_renames.py index f275efa2f..7a8766da0 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 .migracao import appconfs, get_renames, legacy_app +from .migracao_dados import appconfs, get_renames, legacy_app RENAMING_IGNORED_MODELS = [ sapl.comissoes.models.Composicao, From 0e667a67f381f919922c5b64912271d8f3e0f0e8 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 2 Mar 2018 10:02:17 -0300 Subject: [PATCH 070/121] =?UTF-8?q?Gera=20pacotes=20de=20migra=C3=A7=C3=A3?= =?UTF-8?q?o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../management/commands/migracao_25_31.py | 17 +++++++-- sapl/legacy/migracao.py | 35 ++++++++++++++++++- sapl/legacy/scripts/migra_um_db.sh | 4 +-- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/sapl/legacy/management/commands/migracao_25_31.py b/sapl/legacy/management/commands/migracao_25_31.py index 1298feeb3..27591e058 100644 --- a/sapl/legacy/management/commands/migracao_25_31.py +++ b/sapl/legacy/management/commands/migracao_25_31.py @@ -1,7 +1,7 @@ from django.core import management from django.core.management.base import BaseCommand -from sapl.legacy.migracao import migrar +from sapl.legacy.migracao import migrar, migrar_dados class Command(BaseCommand): @@ -10,13 +10,24 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument( - '-f', + '--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') - migrar(interativo=not options['force']) + somente_dados, interativo = options['dados'], not options['force'] + if somente_dados: + migrar_dados(interativo=interativo) + else: + migrar(interativo=interativo) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index a8fed932f..2690e9a53 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -1,9 +1,42 @@ +import subprocess +import tarfile + +from django.conf import settings + from sapl.legacy.migracao_dados import 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) + migrar_dados(interativo=interativo) migrar_usuarios() 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'] + + # backup do banco + print('Gerando backup do banco... ', end='', flush=True) + arq_backup = settings.MEDIA_ROOT.child('{}.backup'.format(banco)) + backup_cmd = ''' + pg_dump --host localhost --port 5432 --username postgres --no-password + --format custom --blobs --verbose --file {} {}'''.format( + arq_backup, banco) + 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) + print('SUCESSO') diff --git a/sapl/legacy/scripts/migra_um_db.sh b/sapl/legacy/scripts/migra_um_db.sh index 1a4e29920..aab47c20e 100755 --- a/sapl/legacy/scripts/migra_um_db.sh +++ b/sapl/legacy/scripts/migra_um_db.sh @@ -4,7 +4,7 @@ if [ $# -ge 2 ]; then # proteje pasta com dumps de alterações acidentais - chmod -R -w ~/migracao_sapl/sapl_dumps + # chmod -R -w ~/migracao_sapl/sapl_dumps DATE=$(date +%Y-%m-%d) DIR=~/${DATE}_logs_migracao @@ -37,7 +37,7 @@ if [ $# -ge 2 ]; then echo "--- MIGRACAO DE DADOS ---" | tee -a $LOG echo >> $LOG - DATABASE_NAME=$1 ./manage.py migracao_25_31 -f --settings sapl.legacy_migration_settings |& tee -a $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:" From aa3b6b293651e54a02dcc23bacea76b3cf032f0f Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 2 Mar 2018 14:02:25 -0300 Subject: [PATCH 071/121] =?UTF-8?q?Corrige=20unifica=C3=A7=C3=A3o=20de=20a?= =?UTF-8?q?utores=20na=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 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 374ac9f2c..f494ec365 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -317,11 +317,12 @@ def unifica_autores_repetidos_no_legado(campo_agregador): exec_legado_em_subconjunto('delete ' + from_autoria, reapontamento) # e depois inserimos apenas as sem repetições c ind_primeiro_autor ajustado nova_autoria = get_autorias_sem_repeticoes(autoria, reapontamento) - exec_legado(''' - insert into autoria - (cod_autor, cod_materia, ind_primeiro_autor, ind_excluido) - values {}'''.format(', '.join([str((a, m, i, 0)) - for a, m, i in nova_autoria]))) + if nova_autoria: + exec_legado(''' + insert into autoria + (cod_autor, cod_materia, ind_primeiro_autor, ind_excluido) + values {}'''.format(', '.join([str((a, m, i, 0)) + for a, m, i in nova_autoria]))) # Reaponta outras tabelas que referenciam autor for tabela, _ in TABELAS_REFERENCIANDO_AUTOR: From 0e859fae62c840ee51a312d7479158df0b52d1d6 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 2 Mar 2018 14:36:32 -0300 Subject: [PATCH 072/121] Relaxa data_materia em materia.Numeracao MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (devido à migração de dados) --- .../migrations/0026_auto_20180302_1411.py | 20 +++++++++++++++++++ sapl/materia/models.py | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 sapl/materia/migrations/0026_auto_20180302_1411.py diff --git a/sapl/materia/migrations/0026_auto_20180302_1411.py b/sapl/materia/migrations/0026_auto_20180302_1411.py new file mode 100644 index 000000000..9d401710e --- /dev/null +++ b/sapl/materia/migrations/0026_auto_20180302_1411.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-02 17:11 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0025_auto_20180221_1649'), + ] + + operations = [ + migrations.AlterField( + model_name='numeracao', + name='data_materia', + field=models.DateField(null=True, verbose_name='Data'), + ), + ] diff --git a/sapl/materia/models.py b/sapl/materia/models.py index 51fbcb855..ab4b3d074 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -515,7 +515,7 @@ class Numeracao(models.Model): verbose_name=_('Número')) ano_materia = models.PositiveSmallIntegerField(verbose_name=_('Ano'), choices=RANGE_ANOS) - data_materia = models.DateField(verbose_name=_('Data')) + data_materia = models.DateField(verbose_name=_('Data'), null=True) class Meta: verbose_name = _('Numeração') @@ -529,7 +529,7 @@ class Numeracao(models.Model): def __str__(self): return _('%(numero)s/%(ano)s') % { 'numero': self.numero_materia, - 'ano': self.data_materia.year} + 'ano': self.ano_materia} @reversion.register() From 1b21784329400580db46ad67d8f0ed4cf599c513 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 5 Mar 2018 16:41:56 -0300 Subject: [PATCH 073/121] =?UTF-8?q?Otimiza=20enumera=C3=A7=C3=A3o=20de=20r?= =?UTF-8?q?egistros=20na=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 | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index f494ec365..ffde783aa 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -15,9 +15,10 @@ from django.contrib.auth.models import Group from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.db import connections, transaction -from django.db.models import Count, Max +from django.db.models import Count, Max, Q from django.db.models.base import ModelBase from pytz import timezone +from unipath import Path from sapl.base.models import AppConfig as AppConf from sapl.base.models import (Autor, ProblemaMigracao, TipoAutor, @@ -639,6 +640,10 @@ def get_pk_legado(tabela): return [r[4] for r in res] +DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() +PATH_TABELA_TIMEZONES = DIR_DADOS_MIGRACAO.child('tabela_timezones.yaml') + + class DataMigrator: def __init__(self): @@ -649,7 +654,7 @@ class DataMigrator: nome_legado = DATABASES['legacy']['NAME'] match = re.match('sapl_cm_(.*)', nome_legado) sigla_casa = match.group(1) - with open(os.path.expanduser('~/migracao_sapl/sapl_dumps/tabela_timezones.yaml'), 'r') as arq: + with open(PATH_TABELA_TIMEZONES, 'r') as arq: tabela_timezones = yaml.load(arq) municipio, uf, nome_timezone = tabela_timezones[sigla_casa] if nome_timezone: @@ -712,7 +717,7 @@ class DataMigrator: else: info('Migração cancelada.') return 0 - info('Excluindo entradas antigas do banco.') + info('Excluindo entradas antigas do banco destino.') call([PROJECT_DIR.child('manage.py'), 'flush', '--database=default', '--no-input'], stdout=PIPE) @@ -761,13 +766,23 @@ class DataMigrator: 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) + if 'ind_excluido' in {f.name for f in model_legado._meta.fields}: + # se o model legado tem o campo ind_excluido + # enumera apenas os não excluídos + old_records = model_legado.objects.filter(~Q(ind_excluido=1)) + else: + old_records = model_legado.objects.all() + old_records = old_records.order_by(nome_pk) def get_id_do_legado(old): return getattr(old, nome_pk) else: # a pk no legado tem mais de um campo - old_records = iter_sql_records('select * from ' + tabela_legado) + sql = 'select * from ' + tabela_legado + if existe_coluna_no_legado(tabela_legado, 'ind_excluido'): + sql += ' where ind_excluido != 1' + old_records = iter_sql_records(sql) + get_id_do_legado = None ajuste_antes_salvar = AJUSTE_ANTES_SALVAR.get(model) @@ -777,9 +792,6 @@ class DataMigrator: 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 - continue new = model() try: self.populate_renamed_fields(new, old) From 4bd031f6171d5c67aab74a2385a8b1a14d6a27ec Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 7 Mar 2018 14:15:38 -0300 Subject: [PATCH 074/121] Ajusta util de listagem de refs a model --- sapl/legacy/scripts/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/legacy/scripts/utils.py b/sapl/legacy/scripts/utils.py index a983ef2b0..40f1abb3c 100644 --- a/sapl/legacy/scripts/utils.py +++ b/sapl/legacy/scripts/utils.py @@ -9,10 +9,10 @@ def getsourcelines(model): for line in inspect.getsourcelines(model)[0]] -def get_models_com_referencia_a_autor(): +def get_models_com_referencia_a(apontado): def tem_referencia_a_autor(model): - return any(getattr(field, 'related_model', None) == Autor + return any(getattr(field, 'related_model', None) == apontado for field in model._meta.get_fields()) return [model for app in appconfs for model in app.models.values() From 75ced3afbbfd6ee0b47282dcc033f8a259f6b499 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 7 Mar 2018 17:38:49 -0300 Subject: [PATCH 075/121] =?UTF-8?q?Melhora=20feedback=20de=20ajuste=20de?= =?UTF-8?q?=20composi=C3=A7=C3=A3o=20de=20comiss=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index ffde783aa..7cb2484ca 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -947,7 +947,11 @@ def adjust_parlamentar(new, old): def adjust_participacao(new, old): composicao = Composicao() composicao.comissao_id, composicao.periodo_id = [ - get_fk_related(Composicao._meta.get_field(name), value) + get_fk_related(Composicao._meta.get_field(name), + value, + 'composicao_comissao.cod_comp_comissao = {}'.format( + old.pk + )) for name, value in (('comissao', old.cod_comissao), ('periodo', old.cod_periodo_comp))] # check if there is already an "equal" one in the db From 0e56cf9b0dfd5f82767c87db6fd57bd8ce0ae20c Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 7 Mar 2018 17:46:29 -0300 Subject: [PATCH 076/121] =?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/comissoes/legacy.yaml | 17 ---------------- sapl/legacy/migracao_dados.py | 38 +---------------------------------- 2 files changed, 1 insertion(+), 54 deletions(-) diff --git a/sapl/comissoes/legacy.yaml b/sapl/comissoes/legacy.yaml index 59aacf503..a1093c4d2 100644 --- a/sapl/comissoes/legacy.yaml +++ b/sapl/comissoes/legacy.yaml @@ -43,20 +43,3 @@ Participacao (ComposicaoComissao): observacao: obs_composicao parlamentar: cod_parlamentar titular: ind_titular - -Reuniao: - periodo: periodo_reuniao - comissao: cod_comissao - numero: num_comissao - nome: nom_reuniao - tema: tem_reuniao - data: dat_reuniao - hora_inicio: hora_inicio_reuniao - hora_fim: hora_fim_reuniao - local_reuniao: local - observacao: obs_reuniao - ulr_audio: audio_reuniao - url_video: video_reuniao - upload_pauta: pauta_reuniao - upload_ata: ata_reuniao - upload_anexo: anexo_reuniao diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 7cb2484ca..0f2be3883 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -57,19 +57,14 @@ unique_constraints = [] one_to_one_constraints = [] primeira_vez = [] -name_sets = [set(m.__name__ for m in ac.get_models()) for ac in appconfs] - # apps do not overlap +name_sets = [set(m.__name__ for m in ac.get_models()) for ac in appconfs] for s1 in name_sets: for s2 in name_sets: if s1 is not s2: assert not s1.intersection(s2) -# apps include all legacy models legacy_app = apps.get_app_config('legacy') -legacy_model_names = set(m.__name__ for m in legacy_app.get_models()) - -model_dict = {m.__name__: m for ac in appconfs for m in ac.get_models()} # RENAMES ################################################################### @@ -595,34 +590,6 @@ def fill_dados_basicos(): appconf.save() -# Uma anomalia no sapl 2.5 causa a duplicação de registros de votação. -# Essa duplicação deve ser eliminada para que não haja erro no sapl 3.1 -def excluir_registrovotacao_duplicados(): - duplicatas_ids = RegistroVotacao.objects.values( - 'materia', 'ordem', 'expediente').annotate( - Count('id')).order_by().filter(id__count__gt=1) - duplicatas_queryset = RegistroVotacao.objects.filter( - materia__in=[item['materia'] for item in duplicatas_ids]) - - for dup in duplicatas_queryset: - lista_dups = duplicatas_queryset.filter( - materia=dup.materia, expediente=dup.expediente, ordem=dup.ordem) - primeiro_registro = lista_dups[0] - lista_dups = lista_dups.exclude(pk=primeiro_registro.pk) - for objeto in lista_dups: - if (objeto.pk > primeiro_registro.pk): - try: - objeto.delete() - except: - assert 0 - else: - try: - primeiro_registro.delete() - primeiro_registro = objeto - except: - assert 0 - - def get_last_pk(model): last_value = model.objects.all().aggregate(Max('pk')) return last_value['pk__max'] or 0 @@ -729,9 +696,6 @@ class DataMigrator: info('Começando migração: %s...' % obj) self._do_migrate(obj) - # 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() From 065a1980ce256513177368d390220ef3a627eada Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 8 Mar 2018 16:28:41 -0300 Subject: [PATCH 077/121] =?UTF-8?q?Refatora=20ordem=20de=20migra=C3=A7?= =?UTF-8?q?=C3=A3o=20de=20TipoProposicao?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit para indicar o motivo correto --- sapl/legacy/migracao_dados.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 0f2be3883..55db4999f 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -701,17 +701,24 @@ class DataMigrator: def _do_migrate(self, obj): if isinstance(obj, AppConfig): - models_to_migrate = (model for model in obj.models.values() - if model in self.field_renames) - self._do_migrate(models_to_migrate) + models = [model for model in obj.models.values() + if model in self.field_renames] + + if obj.label == 'materia': + # Devido à referência TipoProposicao.tipo_conteudo_related + # a migração de TipoProposicao precisa ser feita + # após TipoMateriaLegislativa e TipoDocumento + # (porém antes de Proposicao) + models.remove(TipoProposicao) + pos_tipo_proposicao = max( + models.index(TipoMateriaLegislativa), + models.index(TipoDocumento)) + 1 + models.insert(pos_tipo_proposicao, TipoProposicao) + assert models.index(TipoProposicao) < models.index(Proposicao) + + self._do_migrate(models) elif isinstance(obj, ModelBase): - # A migração vai pular TipoProposicao e só vai migrar essa model - # antes de migrar Proposicao. Isso deve acontecer por causa da - # GenericRelation existente em TipoProposicao. - if not obj.__name__ == 'TipoProposicao': - if obj.__name__ == 'Proposicao': - self.migrate_model(TipoProposicao) - self.migrate_model(obj) + self.migrate_model(obj) elif hasattr(obj, '__iter__'): for item in obj: self._do_migrate(item) From 1abe092e9597103dc2f621da3ea4a817327a1571 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 8 Mar 2018 16:37:11 -0300 Subject: [PATCH 078/121] Retira warning reduntante --- sapl/legacy/migracao_dados.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 55db4999f..2785deb73 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -141,7 +141,6 @@ def get_fk_related(field, value, label=None): else: msg = 'FK [%s] não encontrada para o valor %s (em %s %s)' % ( field.name, value, field.model.__name__, label or '---') - warn(msg) raise ForeignKeyFaltando(msg) From adcb657e9358df6011f8838efcf20a46aaa2415a Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 8 Mar 2018 16:55:31 -0300 Subject: [PATCH 079/121] =?UTF-8?q?Propaga=20exclus=C3=A3o=20de=20periodo?= =?UTF-8?q?=5Fcomp=5Fcomissao=20p=20composicao=5Fcomissao?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 2785deb73..7aeb1aa54 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -387,43 +387,44 @@ def checa_registros_votacao_ambiguos_e_remove_nao_usados(): PROPAGACOES_DE_EXCLUSAO = [ # sessao_legislativa - ('composicao_mesa', 'sessao_legislativa', 'cod_sessao_leg'), + ('sessao_legislativa', 'composicao_mesa', 'cod_sessao_leg'), # parlamentar - ('dependente', 'parlamentar', 'cod_parlamentar'), - ('filiacao', 'parlamentar', 'cod_parlamentar'), - ('mandato', 'parlamentar', 'cod_parlamentar'), + ('parlamentar', 'dependente', 'cod_parlamentar'), + ('parlamentar', 'filiacao', 'cod_parlamentar'), + ('parlamentar', 'mandato', 'cod_parlamentar'), # comissao - ('composicao_comissao', 'comissao', 'cod_comissao'), + ('comissao', 'composicao_comissao', 'cod_comissao'), + ('periodo_comp_comissao', 'composicao_comissao', 'cod_periodo_comp'), # 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'), + ('sessao_plenaria', 'ordem_dia', 'cod_sessao_plen'), + ('sessao_plenaria', 'expediente_materia', 'cod_sessao_plen'), + ('sessao_plenaria', 'expediente_sessao_plenaria', 'cod_sessao_plen'), + ('registro_votacao', 'registro_votacao_parlamentar', 'cod_votacao'), # as consultas no código do sapl 2.5 # votacao_ordem_dia_obter_zsql e votacao_expediente_materia_obter_zsql # indicam que os registros de votação de matérias excluídas não são # exibidos... - ('registro_votacao', 'materia_legislativa', 'cod_materia'), + ('materia_legislativa', 'registro_votacao', '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'), + ('materia_legislativa', 'tramitacao', 'cod_materia'), + ('materia_legislativa', 'autoria', 'cod_materia'), + ('materia_legislativa', 'anexada', 'cod_materia_principal'), + ('materia_legislativa', 'anexada', 'cod_materia_anexada'), + ('materia_legislativa', 'documento_acessorio', 'cod_materia'), # documento administrativo - ('tramitacao_administrativo', 'documento_administrativo', 'cod_documento'), + ('documento_administrativo', 'tramitacao_administrativo', 'cod_documento'), ] def propaga_exclusoes(): - for tabela_filha, tabela_pai, fk in PROPAGACOES_DE_EXCLUSAO: + for tabela_pai, tabela_filha, fk in PROPAGACOES_DE_EXCLUSAO: [pk_pai] = get_pk_legado(tabela_pai) exec_legado(''' update {} set ind_excluido = 1 where {} not in ( From bc4621fa1558c0e964f01328b65c39e58831218b Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 9 Mar 2018 20:51:05 -0300 Subject: [PATCH 080/121] =?UTF-8?q?Retirado=20coment=C3=A1rio=20zumbi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/parlamentares/models.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py index 9d43e6d6a..574c6735f 100644 --- a/sapl/parlamentares/models.py +++ b/sapl/parlamentares/models.py @@ -261,12 +261,9 @@ class Parlamentar(models.Model): verbose_name=_('Ativo na Casa?')) biografia = models.TextField( blank=True, verbose_name=_('Biografia')) - # XXX Esse atribuito foi colocado aqui para não atrapalhar a migração - fotografia = ImageCropField( verbose_name=_('Fotografia'), upload_to=foto_upload_path, validators=[restringe_tipos_de_arquivo_img], null=True, blank=True) - cropping = ImageRatioField( 'fotografia', '128x128', verbose_name=_('Avatar'), size_warning=True, help_text=_('A configuração do Avatar ' From c50a30ebf303b966a51a481f630d21e47ac62eef Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 9 Mar 2018 21:40:58 -0300 Subject: [PATCH 081/121] =?UTF-8?q?Registra=20ocorr=C3=AAncias=20de=20migr?= =?UTF-8?q?a=C3=A7=C3=A3o=20em=20arquivo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 163 ++++++++++++++++++---------------- 1 file changed, 87 insertions(+), 76 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 7aeb1aa54..efa4cf277 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -1,5 +1,5 @@ -import os import re +from collections import defaultdict from datetime import date from functools import lru_cache, partial from itertools import groupby @@ -15,7 +15,7 @@ from django.contrib.auth.models import Group from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.db import connections, transaction -from django.db.models import Count, Max, Q +from django.db.models import Max, Q from django.db.models.base import ModelBase from pytz import timezone from unipath import Path @@ -110,16 +110,30 @@ def get_renames(): def info(msg): print('INFO: ' + msg) +ocorrencias = defaultdict(list) -def warn(msg): - print('CUIDADO! ' + msg) + +def warn(tipo, msg, dados): + ocorrencias[tipo].append(dados) + print('CUIDADO! ' + msg.format(**dados)) class ForeignKeyFaltando(ObjectDoesNotExist): 'Uma FK aponta para um registro inexistente' - def __init__(self, msg=''): - self.msg = msg + def __init__(self, field, value, label): + self.field = field + self.value = value + self.label = label + + msg = 'FK [{field}] não encontrada para o valor {value} (em {model} / {label})' # noqa + + @property + def dados(self): + return {'field': self.field.name, + 'value': self.value, + 'model': self.field.model.__name__, + 'label': self.label} @lru_cache() @@ -128,7 +142,7 @@ def _get_all_ids_from_model(model): return set(model.objects.values_list('id', flat=True)) -def get_fk_related(field, value, label=None): +def get_fk_related(field, value, label='---'): if value is None and field.null: return None @@ -139,9 +153,7 @@ def get_fk_related(field, value, label=None): # consideramos zeros como nulos, se não está entre os ids anteriores return None else: - msg = 'FK [%s] não encontrada para o valor %s (em %s %s)' % ( - field.name, value, field.model.__name__, label or '---') - raise ForeignKeyFaltando(msg) + raise ForeignKeyFaltando(field=field, value=value, label=label) def exec_sql(sql, db='default'): @@ -609,6 +621,7 @@ def get_pk_legado(tabela): DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() PATH_TABELA_TIMEZONES = DIR_DADOS_MIGRACAO.child('tabela_timezones.yaml') +DIR_RESULTADOS = DIR_DADOS_MIGRACAO.child('resultados') class DataMigrator: @@ -618,8 +631,8 @@ class DataMigrator: self.choice_valida = {} # configura timezone de migração - nome_legado = DATABASES['legacy']['NAME'] - match = re.match('sapl_cm_(.*)', nome_legado) + self.nome_banco_legado = DATABASES['legacy']['NAME'] + match = re.match('sapl_cm_(.*)', self.nome_banco_legado) sigla_casa = match.group(1) with open(PATH_TABELA_TIMEZONES, 'r') as arq: tabela_timezones = yaml.load(arq) @@ -641,7 +654,7 @@ class DataMigrator: if field_type == 'ForeignKey': # not necessarily a model if hasattr(old, '_meta') and old._meta.pk.name != 'id': - label = old.pk + label = 'pk = {}'.format(old.pk) else: label = '-- SEM PK --' fk_field_name = '{}_id'.format(field.name) @@ -694,7 +707,18 @@ class DataMigrator: fill_vinculo_norma_juridica() fill_dados_basicos() info('Começando migração: %s...' % obj) - self._do_migrate(obj) + try: + ocorrencias.clear() + dir_ocorrencias = DIR_RESULTADOS.child(date.today().isoformat()) + dir_ocorrencias.mkdir(parents=True) + self._do_migrate(obj) + finally: + # grava ocorrências + arq_ocorrencias = dir_ocorrencias.child( + self.nome_banco_legado + '.yaml') + with open(arq_ocorrencias, 'w') as arq: + yaml.safe_dump(dict(ocorrencias), arq, allow_unicode=True) + info('Ocorrências salvas em\n {}'.format(arq_ocorrencias)) # recria tipos de autor padrão que não foram criados pela migração cria_models_tipo_autor() @@ -772,7 +796,7 @@ class DataMigrator: # tentamos preencher uma FK e o ojeto relacionado # não existe # então este é um objeo órfão: simplesmente ignoramos - warn(e.msg) + warn('fk', e.msg, e.dados) continue else: if get_id_do_legado: @@ -841,10 +865,15 @@ 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)) + msg = 'PROTOCOLO ENCONTRADO APENAS PARA O ANO SEGUINTE!!!!! '\ + 'DocumentoAdministrativo: {cod_documento}, '\ + 'numero_protocolo: {num_protocolo}, '\ + 'ano doc adm: {ano_original}' + warn('protocolo_ano_seguinte', msg, + {'cod_documento': old.cod_documento, + 'num_protocolo': old.num_protocolo, + 'ano_original': ano_original, + 'nota': nota}) else: nota = NOTA_DOCADM + ''' Não existe no sistema nenhum protocolo com estes dados @@ -852,9 +881,12 @@ 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( - old.num_protocolo, old.cod_documento)) + msg = 'Protocolo {num_protocolo} faltando (referenciado ' \ + 'no documento administrativo {cod_documento})' + warn('protocolo_faltando', msg, + {'num_protocolo': old.num_protocolo, + 'cod_documento': old.cod_documento, + 'nota': nota}) if protocolo: assert len(protocolo) == 1, 'mais de um protocolo encontrado' [new.protocolo] = protocolo @@ -883,18 +915,10 @@ def adjust_ordemdia_antes_salvar(new, old): if old.num_ordem is None: new.numero_ordem = 999999999 - - -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' \ - ' nulo.' % old.pk - descricao = 'O valor %s foi colocado no lugar.' % new.numero_ordem - warn(problema + ' => ' + descricao) - save_relation(obj=new, problema=problema, - descricao=descricao, eh_stub=False) - reversion.set_comment('OrdemDia sem número da ordem.') + warn('ordem_dia_num_ordem_nulo', + 'OrdemDia de PK {pk} tinha numero ordem nulo. ' + 'O valor %s foi colocado no lugar.' % new.numero_ordem, + {'pk': old.pk}) def adjust_parlamentar(new, old): @@ -904,7 +928,10 @@ def adjust_parlamentar(new, old): # but data includes null values # => transform None to False if value is None: - warn('nulo convertido para falso') + warn('unidade_deliberativa_nulo_p_false', + 'nulo convertido para falso na unidade_deliberativa ' + 'do parlamentar {pk_parlamentar}', + {'pk_parlamentar': old.cod_parlamentar}) new.unidade_deliberativa = False # migra município de residência if old.cod_localidade_resid: @@ -950,19 +977,12 @@ def adjust_normarelacionada(new, old): def adjust_protocolo_antes_salvar(new, old): - if old.num_protocolo is None: + if new.numero is None: new.numero = old.cod_protocolo - - -def adjust_protocolo_depois_salvar(new, old): - if old.num_protocolo is None: - with reversion.create_revision(): - problema = 'Número do protocolo de PK %s é nulo' % new.pk - descricao = 'Número do protocolo alterado para %s!' % new.numero - warn(problema + ' => ' + descricao) - save_relation(obj=new, problema=problema, - descricao=descricao, eh_stub=False) - reversion.set_comment('Número de protocolo teve que ser alterado') + warn('num_protocolo_nulo', + 'Número do protocolo de PK {cod_protocolo} era nulo ' + 'e foi alterado para sua pk ({cod_protocolo})', + {'cod_protocolo': old.cod_protocolo}) def adjust_registrovotacao_antes_salvar(new, old): @@ -982,20 +1002,22 @@ def adjust_tipoafastamento(new, old): new.indicador = 'A' +MODEL_TIPO_MATERIA_OU_DOCUMENTO = {'M': TipoMateriaLegislativa, + 'D': TipoDocumento} + + def adjust_tipoproposicao(new, old): - if old.ind_mat_ou_doc == 'M': - tipo_materia = TipoMateriaLegislativa.objects.filter( - pk=old.tip_mat_ou_doc) - if tipo_materia: - new.tipo_conteudo_related = tipo_materia[0] - else: - raise ForeignKeyFaltando - elif old.ind_mat_ou_doc == 'D': - tipo_documento = TipoDocumento.objects.filter(pk=old.tip_mat_ou_doc) - if tipo_documento: - new.tipo_conteudo_related = tipo_documento[0] - else: - raise ForeignKeyFaltando + "Aponta para o tipo relacionado de matéria ou documento" + value = old.tip_mat_ou_doc + model_tipo = MODEL_TIPO_MATERIA_OU_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 = {}'.format(old.ind_mat_ou_doc)) def adjust_statustramitacao(new, old): @@ -1057,9 +1079,12 @@ 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 + nome_model_relacionado = model_relacionado._meta.model.__name__ raise ForeignKeyFaltando( - '{} [pk={}] inexistente para autor'.format( - model_relacionado._meta.verbose_name, pk_rel)) + field=Autor.autor_related, + value=(nome_model_relacionado, pk_rel), + label='{} [pk={}] inexistente para autor'.format( + nome_model_relacionado, pk_rel)) else: new.nome = getattr(new.autor_related, campo_nome) return True @@ -1124,20 +1149,6 @@ AJUSTE_ANTES_SALVAR = { AJUSTE_DEPOIS_SALVAR = { NormaJuridica: adjust_normajuridica_depois_salvar, - OrdemDia: adjust_ordemdia_depois_salvar, - Protocolo: adjust_protocolo_depois_salvar, } # CHECKS #################################################################### - - -def get_ind_excluido(new): - 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) - - -def check_app_no_ind_excluido(app): - for model in app.models.values(): - assert not any(get_ind_excluido(new) for new in model.objects.all()) - print('OK!') From f3aea175309c7d33cfa068009d2ab989d0bc1f15 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 13 Mar 2018 13:50:02 -0300 Subject: [PATCH 082/121] =?UTF-8?q?Propaga=20exclus=C3=B5es=20para=20autor?= =?UTF-8?q?es=20n=C3=A3o=20referenciados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index efa4cf277..51c194bf4 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -252,6 +252,21 @@ def reverte_exclusao_de_autores_referenciados_no_legado(): 'update autor set ind_excluido = 0 where cod_autor in {}', autores_referenciados) + # propaga exclusões para autores não referenciados + for tabela, fk in [('parlamentar', 'cod_parlamentar'), + ('comissao', 'cod_comissao')]: + sql = ''' + update autor set ind_excluido = 1 + where {cod_parlamentar} is not null + and {cod_parlamentar} not in ( + select {cod_parlamentar} from {parlamentar} + where ind_excluido <> 1) + '''.format(parlamentar=tabela, cod_parlamentar=fk) + if autores_referenciados: + sql += ' and cod_autor not in {}'.format( + tuple(autores_referenciados)) + exec_legado(sql) + def get_reapontamento_de_autores_repetidos(autores): """ Dada uma lista ordenada de pares (cod_zzz, cod_autor) retorna: From f2bcdebc38ee9db76e53d5d5f025057b16f1f3e0 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 13 Mar 2018 15:07:19 -0300 Subject: [PATCH 083/121] =?UTF-8?q?Ajusta=20scripts=20p=20migra=C3=A7?= =?UTF-8?q?=C3=A3o=20em=20paralelo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/migra_dbs.sh | 5 +++++ sapl/legacy/scripts/migra_um_db.sh | 16 +++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/sapl/legacy/scripts/migra_dbs.sh b/sapl/legacy/scripts/migra_dbs.sh index 25a78e01c..3620da089 100755 --- a/sapl/legacy/scripts/migra_dbs.sh +++ b/sapl/legacy/scripts/migra_dbs.sh @@ -2,8 +2,13 @@ # rodar esse script na raiz do projeto + if [ $# -ge 1 ]; then + # mysql com senha parallel -eta --verbose -j+0 ./sapl/legacy/scripts/migra_um_db.sh :::: <(mysql -u $1 -p$2 -e 'show databases;' | grep '^sapl_') ::: $1 ::: $2 +elif [ $# -ge 0 ]; then + # mysql sem senha + parallel -eta --verbose -j+0 ./sapl/legacy/scripts/migra_um_db.sh :::: <(mysql -u $1 -e 'show databases;' | grep '^sapl_') ::: $1 else echo "USO:" echo " $0 [senha mysql]" diff --git a/sapl/legacy/scripts/migra_um_db.sh b/sapl/legacy/scripts/migra_um_db.sh index aab47c20e..eca35f0a3 100755 --- a/sapl/legacy/scripts/migra_um_db.sh +++ b/sapl/legacy/scripts/migra_um_db.sh @@ -6,11 +6,13 @@ if [ $# -ge 2 ]; then # proteje pasta com dumps de alterações acidentais # chmod -R -w ~/migracao_sapl/sapl_dumps + DIR_MIGRACAO=~/migracao_sapl + DATE=$(date +%Y-%m-%d) - DIR=~/${DATE}_logs_migracao - mkdir -p $DIR + DIR_LOGS=$DIR_MIGRACAO/logs/$DATE + mkdir -p $DIR_LOGS - LOG="$DIR/$1.migracao.log" + LOG="$DIR_LOGS/$1.migracao.log" rm -f $LOG echo "########################################" | tee -a $LOG @@ -20,12 +22,12 @@ if [ $# -ge 2 ]; then 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" < ~/migracao_sapl/sapl_dumps/$1.sql + 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 < ~/migracao_sapl/sapl_dumps/$1.sql + 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 From ce59f543b472bbb5775f23d63f5fb16ea1d3e3f4 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 14 Mar 2018 17:48:30 -0300 Subject: [PATCH 084/121] =?UTF-8?q?Adapata=20migra=C3=A7=C3=A3o=20a=20doc?= =?UTF-8?q?=20acessorio=20repetido?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 51c194bf4..2ac75c4ef 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -57,12 +57,17 @@ unique_constraints = [] one_to_one_constraints = [] primeira_vez = [] -# apps do not overlap -name_sets = [set(m.__name__ for m in ac.get_models()) for ac in appconfs] -for s1 in name_sets: - for s2 in name_sets: - if s1 is not s2: - assert not s1.intersection(s2) +# apps quase não têm interseção +name_sets = [(ac.label, set(m.__name__ for m in ac.get_models())) + for ac in appconfs] +for a1, s1 in name_sets: + for a2, s2 in name_sets: + if a1 is not a2: + # existe uma interseção de nomes entre comissoes e materia + if {a1, a2} == {'comissoes', 'materia'}: + assert s1.intersection(s2) == {'DocumentoAcessorio'} + else: + assert not s1.intersection(s2) legacy_app = apps.get_app_config('legacy') From 9436b371c1ee61965895d6b7c7aaec26b0be2eff Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 15 Mar 2018 17:25:31 -0300 Subject: [PATCH 085/121] =?UTF-8?q?Corrige=20migra=C3=A7=C3=A3o=20de=20sup?= =?UTF-8?q?erusu=C3=A1rio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_usuarios.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sapl/legacy/migracao_usuarios.py b/sapl/legacy/migracao_usuarios.py index 962dfad6d..666bf57ef 100644 --- a/sapl/legacy/migracao_usuarios.py +++ b/sapl/legacy/migracao_usuarios.py @@ -1,6 +1,6 @@ import yaml -from django.contrib.auth.models import Group, User +from django.contrib.auth.models import Group, User from sapl.hashers import zope_encoded_password_to_django from sapl.settings import MEDIA_ROOT @@ -88,10 +88,10 @@ def migrar_usuarios(): for perfil in perfis: if perfil in ADMINISTRADORES: # Manager - usuario.is_staff = True - usuario.save() + usuario.is_superuser = True else: usuario.groups.add(PERFIL_LEGADO_PARA_NOVO[perfil]) + usuario.save() # apaga arquivo (importante pois contém senhas) ARQUIVO_USUARIOS.remove() print('Usuários migrados com sucesso.') From 5f0e90bdd53127d8141f730f6a306358373d61da Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 16 Mar 2018 11:48:33 -0300 Subject: [PATCH 086/121] =?UTF-8?q?Torna=20script=20create=5Fadmin.py=20ex?= =?UTF-8?q?ecut=C3=A1vel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- create_admin.py | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 create_admin.py diff --git a/create_admin.py b/create_admin.py old mode 100644 new mode 100755 index bc8aa09e9..f03bbd7c8 --- a/create_admin.py +++ b/create_admin.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import os import sys From 094ffca1bdee17e6b4be5269405ef0a8fa2dff7d Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Fri, 16 Mar 2018 11:54:28 -0300 Subject: [PATCH 087/121] Fix #1766 (#1768) --- sapl/sessao/legacy.yaml | 2 ++ .../migrations/0017_auto_20180316_0731.py | 26 +++++++++++++++++++ sapl/sessao/models.py | 5 ++++ sapl/templates/sessao/layouts.yaml | 1 + 4 files changed, 34 insertions(+) create mode 100644 sapl/sessao/migrations/0017_auto_20180316_0731.py diff --git a/sapl/sessao/legacy.yaml b/sapl/sessao/legacy.yaml index 90188a76c..521a4c173 100644 --- a/sapl/sessao/legacy.yaml +++ b/sapl/sessao/legacy.yaml @@ -44,6 +44,8 @@ AbstractOrador: parlamentar: cod_parlamentar sessao_plenaria: cod_sessao_plen url_discurso: url_discurso + upload_anexo: anexo + Orador (Oradores): {} diff --git a/sapl/sessao/migrations/0017_auto_20180316_0731.py b/sapl/sessao/migrations/0017_auto_20180316_0731.py new file mode 100644 index 000000000..a81456161 --- /dev/null +++ b/sapl/sessao/migrations/0017_auto_20180316_0731.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-16 10:31 +from __future__ import unicode_literals + +from django.db import migrations, models +import sapl.sessao.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sessao', '0016_auto_20180131_1708'), + ] + + operations = [ + migrations.AddField( + model_name='orador', + name='upload_anexo', + field=models.FileField(blank=True, null=True, upload_to=sapl.sessao.models.anexo_upload_path, verbose_name='Anexo do Orador'), + ), + migrations.AddField( + model_name='oradorexpediente', + name='upload_anexo', + field=models.FileField(blank=True, null=True, upload_to=sapl.sessao.models.anexo_upload_path, verbose_name='Anexo do Orador'), + ), + ] diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py index f4f25cc14..49448eecc 100644 --- a/sapl/sessao/models.py +++ b/sapl/sessao/models.py @@ -320,6 +320,11 @@ class AbstractOrador(models.Model): # Oradores max_length=150, blank=True, verbose_name=_('URL Vídeo')) observacao = models.CharField( max_length=150, blank=True, verbose_name=_('Observação')) + upload_anexo = models.FileField( + blank=True, + null=True, + upload_to=anexo_upload_path, + verbose_name=_('Anexo do Orador')) class Meta: abstract = True diff --git a/sapl/templates/sessao/layouts.yaml b/sapl/templates/sessao/layouts.yaml index 53caa2db1..99780bb22 100644 --- a/sapl/templates/sessao/layouts.yaml +++ b/sapl/templates/sessao/layouts.yaml @@ -36,6 +36,7 @@ OradorExpediente: {% trans 'Orador do Expediente' %}: - numero_ordem parlamentar - url_discurso observacao + - upload_anexo ExpedienteMateria: {% trans 'Matéria do Expediente' %}: From 5227d4929131f3dd58310a8dd11edbba3f1519a5 Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Fri, 16 Mar 2018 11:55:57 -0300 Subject: [PATCH 088/121] Fix #1758 (#1760) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Altera quantidade de matérias exibidas pro página. * Troca de 20 por 50 --- sapl/materia/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 5be89a672..28d939af5 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -1493,7 +1493,7 @@ class AcompanhamentoExcluirView(TemplateView): class MateriaLegislativaPesquisaView(FilterView): model = MateriaLegislativa filterset_class = MateriaLegislativaFilterSet - paginate_by = 10 + paginate_by = 50 def get_filterset_kwargs(self, filterset_class): super(MateriaLegislativaPesquisaView, From e013f94b73265c5ea4125683f352e21c69fef2fb Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Fri, 16 Mar 2018 12:08:26 -0300 Subject: [PATCH 089/121] Fix #1757 (#1764) --- sapl/sessao/views.py | 365 ++++++++++------------- sapl/templates/sessao/ordemdia_list.html | 4 + 2 files changed, 166 insertions(+), 203 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 0e715e514..ff5cf9e29 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -154,9 +154,10 @@ def abrir_votacao(request, pk, spk): reverse('sapl.sessao:' + redirect_url, kwargs={'pk': spk})) -def customize_link_materia(context, pk): +def customize_link_materia(context, pk, has_permission, is_expediente): for i, row in enumerate(context['rows']): materia = context['object_list'][i].materia + obj = context['object_list'][i] url_materia = reverse('sapl.materia:materialegislativa_detail', kwargs={'pk': materia.id}) numeracao = materia.numeracao_set.first() @@ -199,6 +200,162 @@ def customize_link_materia(context, pk): # Na linha abaixo, o segundo argumento é None para não colocar # url em toda a string de title_materia context['rows'][i][1] = (title_materia, None) + + exist_resultado = obj.registrovotacao_set.filter( + materia=obj.materia).exists() + if not exist_resultado: + if obj.votacao_aberta: + url = '' + if is_expediente: + if obj.tipo_votacao == 1: + url = reverse('sapl.sessao:votacaosimbolicaexp', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + elif obj.tipo_votacao == 2: + url = reverse('sapl.sessao:votacaonominalexp', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + elif obj.tipo_votacao == 3: + url = reverse('sapl.sessao:votacaosecretaexp', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + else: + if obj.tipo_votacao == 1: + url = reverse('sapl.sessao:votacaosimbolica', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + elif obj.tipo_votacao == 2: + url = reverse('sapl.sessao:votacaonominal', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + elif obj.tipo_votacao == 3: + url = reverse('sapl.sessao:votacaosecreta', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + if has_permission: + btn_registrar = ''' +
    + + ''' % ( + url) + + resultado = btn_registrar + else: + resultado = '''Não há resultado''' + else: + if is_expediente: + url = reverse('sapl.sessao:abrir_votacao', kwargs={ + 'pk': obj.pk, + 'spk': obj.sessao_plenaria_id + }) + '?tipo_materia=expediente' + else: + url = reverse('sapl.sessao:abrir_votacao', kwargs={ + 'pk': obj.pk, + 'spk': obj.sessao_plenaria_id + }) + '?tipo_materia=ordem' + + if has_permission: + btn_abrir = ''' + Matéria não votada
    + Abrir Votação''' % (url) + resultado = btn_abrir + else: + resultado = '''Não há resultado''' + else: + resultado = obj.registrovotacao_set.get( + materia_id=obj.materia_id) + resultado_descricao = resultado.tipo_resultado_votacao.nome + resultado_observacao = resultado.observacao + + if has_permission: + url = '' + if is_expediente: + if obj.tipo_votacao == 1: + url = reverse( + 'sapl.sessao:votacaosimbolicaexpedit', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + elif obj.tipo_votacao == 2: + url = reverse('sapl.sessao:votacaonominalexpedit', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + elif obj.tipo_votacao == 3: + url = reverse('sapl.sessao:votacaosecretaexpedit', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + else: + if obj.tipo_votacao == 1: + url = reverse('sapl.sessao:votacaosimbolicaedit', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + elif obj.tipo_votacao == 2: + url = reverse('sapl.sessao:votacaonominaledit', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + elif obj.tipo_votacao == 3: + url = reverse('sapl.sessao:votacaosecretaedit', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + + resultado = ('%s
    %s
    ' % + (url, + resultado_descricao, + resultado_observacao)) + else: + if obj.tipo_votacao == 2: + if is_expediente: + url = reverse( + 'sapl.sessao:votacao_nominal_transparencia', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + \ + '?&materia=expediente' + else: + url = reverse( + 'sapl.sessao:votacao_nominal_transparencia', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + \ + '?&materia=ordem' + + resultado = ('%s
    %s
    ' % + (url, + resultado_descricao, + resultado_observacao)) + else: + resultado = ('%s
    %s' % + (resultado_descricao, + resultado_observacao)) + context['rows'][i][3] = (resultado, None) return context @@ -261,110 +418,10 @@ class MateriaOrdemDiaCrud(MasterDetailCrud): class ListView(MasterDetailCrud.ListView): paginate_by = None ordering = ['numero_ordem', 'materia', 'resultado'] - def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - return customize_link_materia(context, self.kwargs['pk']) - - def get_rows(self, object_list): - for obj in object_list: - exist_resultado = obj.registrovotacao_set.filter( - materia=obj.materia).exists() - if not exist_resultado: - if obj.votacao_aberta: - url = '' - if obj.tipo_votacao == 1: - url = reverse('sapl.sessao:votacaosimbolica', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - elif obj.tipo_votacao == 2: - url = reverse('sapl.sessao:votacaonominal', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - elif obj.tipo_votacao == 3: - url = reverse('sapl.sessao:votacaosecreta', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - if self.request.user.has_module_perms(AppConfig.label): - btn_registrar = ''' - Registrar Votação''' % ( - url) - obj.resultado = btn_registrar - else: - obj.resultado = '''Não há resultado''' - else: - url = reverse('sapl.sessao:abrir_votacao', kwargs={ - 'pk': obj.pk, - 'spk': obj.sessao_plenaria_id - }) + '?tipo_materia=ordem' - - if self.request.user.has_module_perms(AppConfig.label): - btn_abrir = ''' - Matéria não votada
    - Abrir Votação''' % (url) - obj.resultado = btn_abrir - else: - obj.resultado = '''Não há resultado''' - else: - resultado = obj.registrovotacao_set.get( - materia_id=obj.materia_id) - resultado_descricao = resultado.tipo_resultado_votacao.nome - resultado_observacao = resultado.observacao - - if self.request.user.has_module_perms(AppConfig.label): - url = '' - if obj.tipo_votacao == 1: - url = reverse('sapl.sessao:votacaosimbolicaedit', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - elif obj.tipo_votacao == 2: - url = reverse('sapl.sessao:votacaonominaledit', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - elif obj.tipo_votacao == 3: - url = reverse('sapl.sessao:votacaosecretaedit', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - obj.resultado = ('%s
    %s
    ' % - (url, - resultado_descricao, - resultado_observacao)) - else: - if obj.tipo_votacao == 2: - url = reverse( - 'sapl.sessao:votacao_nominal_transparencia', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) +\ - '?&materia=ordem' - obj.resultado = ('%s
    %s
    ' % - (url, - resultado_descricao, - resultado_observacao)) - else: - obj.resultado = ('%s
    %s' % - (resultado_descricao, - resultado_observacao)) - - return [self._as_row(obj) for obj in object_list] - + has_permition = self.request.user.has_module_perms(AppConfig.label) + return customize_link_materia(context, self.kwargs['pk'], has_permition, False) def recuperar_materia(request): tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo_materia']) @@ -399,106 +456,8 @@ class ExpedienteMateriaCrud(MasterDetailCrud): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - - return customize_link_materia(context, self.kwargs['pk']) - - def get_rows(self, object_list): - for obj in object_list: - exist_resultado = obj.registrovotacao_set.filter( - materia=obj.materia).exists() - - if not exist_resultado: - if obj.votacao_aberta: - url = '' - if obj.tipo_votacao == 1: - url = reverse('sapl.sessao:votacaosimbolicaexp', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - elif obj.tipo_votacao == 2: - url = reverse('sapl.sessao:votacaonominalexp', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - elif obj.tipo_votacao == 3: - url = reverse('sapl.sessao:votacaosecretaexp', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - - if self.request.user.has_module_perms(AppConfig.label): - btn_registrar = ''' -
    - - - ''' % (url) - obj.resultado = btn_registrar - else: - url = reverse('sapl.sessao:abrir_votacao', kwargs={ - 'pk': obj.pk, - 'spk': obj.sessao_plenaria_id - }) + '?tipo_materia=expediente' - btn_abrir = '''Matéria não votada
    ''' - - if self.request.user.has_module_perms(AppConfig.label): - btn_abrir += ''' - Abrir Votação''' % (url) - - obj.resultado = btn_abrir - else: - url = '' - resultado = obj.registrovotacao_set.get( - materia_id=obj.materia_id) - resultado_descricao = resultado.tipo_resultado_votacao.nome - resultado_observacao = resultado.observacao - if self.request.user.has_module_perms(AppConfig.label): - if obj.tipo_votacao == 1: - url = reverse( - 'sapl.sessao:votacaosimbolicaexpedit', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - elif obj.tipo_votacao == 2: - url = reverse('sapl.sessao:votacaonominalexpedit', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - elif obj.tipo_votacao == 3: - url = reverse('sapl.sessao:votacaosecretaexpedit', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) - obj.resultado = ('%s
    %s
    ' % - (url, - resultado_descricao, - resultado_observacao)) - else: - if obj.tipo_votacao == 2: - url = reverse( - 'sapl.sessao:votacao_nominal_transparencia', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.pk, - 'mid': obj.materia_id}) +\ - '?&materia=expediente' - obj.resultado = ('%s
    %s
    ' % - (url, - resultado_descricao, - resultado_observacao)) - else: - obj.resultado = ('%s
    %s' % - (resultado_descricao, - resultado_observacao)) - return [self._as_row(obj) for obj in object_list] + has_permition = self.request.user.has_module_perms(AppConfig.label) + return customize_link_materia(context, self.kwargs['pk'], has_permition, True) class CreateView(MasterDetailCrud.CreateView): form_class = ExpedienteMateriaForm diff --git a/sapl/templates/sessao/ordemdia_list.html b/sapl/templates/sessao/ordemdia_list.html index e5b3d757e..3ae16e2e8 100644 --- a/sapl/templates/sessao/ordemdia_list.html +++ b/sapl/templates/sessao/ordemdia_list.html @@ -45,6 +45,10 @@ setTimeout(function(){ window.location.reload(true) }, 500); } }); + $(window).on('beforeunload', function () { + $('tbody').sortable('disable'); + $("input[type=submit], input[type=button]").prop("disabled", "disabled"); + }); {% endblock %} From fe3ad350252bf22d37bde0b680f780eef9c9832f Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Fri, 16 Mar 2018 12:08:36 -0300 Subject: [PATCH 090/121] =?UTF-8?q?Formata=20mudan=C3=A7a=20de=20linha=20n?= =?UTF-8?q?a=20exibi=C3=A7=C3=A3o=20de=20TextField=20(#1765)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/crispy_layout_mixin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/crispy_layout_mixin.py b/sapl/crispy_layout_mixin.py index 12a876b12..9b2f0867b 100644 --- a/sapl/crispy_layout_mixin.py +++ b/sapl/crispy_layout_mixin.py @@ -132,6 +132,8 @@ def get_field_display(obj, fieldname): value._meta.app_config.name, obj.content_type.model), args=(value.id,)), value) + elif 'TextField' in str_type_from_field: + display = value.replace('\n', '
    ') else: display = str(value) return verbose_name, display From c5b39cb9af5367ab366c62000987a8dc8bd9c721 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 16 Mar 2018 15:16:59 -0300 Subject: [PATCH 091/121] HOT-FIX: adiciona anexo a tela de orador explic pessoais --- sapl/templates/sessao/layouts.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/sapl/templates/sessao/layouts.yaml b/sapl/templates/sessao/layouts.yaml index 99780bb22..0d756684c 100644 --- a/sapl/templates/sessao/layouts.yaml +++ b/sapl/templates/sessao/layouts.yaml @@ -31,6 +31,7 @@ Orador: {% trans 'Orador das Explicações Pessoais' %}: - numero_ordem parlamentar - url_discurso observacao + - upload_anexo OradorExpediente: {% trans 'Orador do Expediente' %}: From 8f6c393ee47cd87516dd3add3ed76822286edbe0 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 16 Mar 2018 17:32:42 -0300 Subject: [PATCH 092/121] =?UTF-8?q?HOT-FIX:=20conserta=20erro=20de=20sinta?= =?UTF-8?q?xe=20em=20JavaScript=20de=20tramita=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/templates/materia/em_lote/tramitacao.html | 2 +- sapl/templates/materia/tramitacao_form.html | 10 ++++++---- .../protocoloadm/tramitacaoadministrativo_form.html | 11 ++++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/sapl/templates/materia/em_lote/tramitacao.html b/sapl/templates/materia/em_lote/tramitacao.html index 333050875..08483d88d 100644 --- a/sapl/templates/materia/em_lote/tramitacao.html +++ b/sapl/templates/materia/em_lote/tramitacao.html @@ -143,7 +143,7 @@ $('input[type=submit]').click(function() { $('#id_unidade_tramitacao_local').attr('disabled', false); $('#id_unidade_tramitacao_local').parents('form').submit(); - }) + }); }); {% endblock %} diff --git a/sapl/templates/materia/tramitacao_form.html b/sapl/templates/materia/tramitacao_form.html index 82b24036a..4e79e3fd2 100644 --- a/sapl/templates/materia/tramitacao_form.html +++ b/sapl/templates/materia/tramitacao_form.html @@ -8,10 +8,12 @@ // habilita ele no momento do submit para que o valor de unidade local // não seja enviado como vazio - $('input[type=submit]').click(function() { - $('#id_unidade_tramitacao_local').attr('disabled', false); - $('#id_unidade_tramitacao_local').parents('form').submit(); - } + $(document).ready(function(){ + $('input[type=submit]').click(function() { + $('#id_unidade_tramitacao_local').attr('disabled', false); + $('#id_unidade_tramitacao_local').parents('form').submit(); + }); + }); {% endblock %} diff --git a/sapl/templates/protocoloadm/tramitacaoadministrativo_form.html b/sapl/templates/protocoloadm/tramitacaoadministrativo_form.html index 7de9f8af0..2bd266314 100644 --- a/sapl/templates/protocoloadm/tramitacaoadministrativo_form.html +++ b/sapl/templates/protocoloadm/tramitacaoadministrativo_form.html @@ -5,10 +5,11 @@ // Caso o campo esteja desabilitado (quando não é a primeira tramitação), // habilita ele no momento do submit para que o valor de unidade local // não seja enviado como vazio - - $('input[type=submit]').click(function() { - $('#id_unidade_tramitacao_local').attr('disabled', false); - $('#id_unidade_tramitacao_local').parents('form').submit(); - } + $(document).ready(function(){ + $('input[type=submit]').click(function() { + $('#id_unidade_tramitacao_local').attr('disabled', false); + $('#id_unidade_tramitacao_local').parents('form').submit(); + }); + }); {% endblock extra_js %} \ No newline at end of file From a6f64c2aebc8a564047ef0cb7d82c4fe60dbf6a6 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 16 Mar 2018 17:41:45 -0300 Subject: [PATCH 093/121] Release: 3.1.63 --- 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 6b91b8a52..776a64821 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.62 + image: interlegis/sapl:3.1.63 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 44cf36134..309f33fa6 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.62', + version='3.1.63', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 118b5dc01144836f276cf5c7feb5b8133edd2f6b Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 16 Mar 2018 12:06:16 -0300 Subject: [PATCH 094/121] =?UTF-8?q?Limita=20n=C3=BAmero=20de=20superusu?= =?UTF-8?q?=C3=A1rios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_usuarios.py | 32 ++++++++++++++++++++++++------ sapl/legacy/scripts/migra_um_db.sh | 4 ++-- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/sapl/legacy/migracao_usuarios.py b/sapl/legacy/migracao_usuarios.py index 666bf57ef..106a2def6 100644 --- a/sapl/legacy/migracao_usuarios.py +++ b/sapl/legacy/migracao_usuarios.py @@ -1,13 +1,13 @@ 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) for legado, novo in [ ('Autor', 'Autor'), - ('Operador', 'Operador Geral'), + ('Operador', 'Operador Geral'), ('Operador Comissao', 'Operador de Comissões'), ('Operador Materia', 'Operador de Matéria'), ('Operador Modulo Administrativo', 'Operador Administrativo'), @@ -82,16 +82,36 @@ def migrar_usuarios(): set(dados['roles']) - IGNORADOS) for nome, dados in usuarios.items()] + admins = [] 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 - usuario.is_superuser = True + # todos os administradores ganham perfil "Operador Geral" + usuario.groups.add(PERFIL_LEGADO_PARA_NOVO['Operador']) + admins.append(usuario) else: usuario.groups.add(PERFIL_LEGADO_PARA_NOVO[perfil]) usuario.save() - # apaga arquivo (importante pois contém senhas) - ARQUIVO_USUARIOS.remove() + + # restringe e configura administradores + if len(admins) > 2: + admins = ( + # ususários com admin no nome + [u for u in admins if 'admin' in u.username] + # senão, o usuário saploper, apenas + or [u for u in admins if 'saploper' == u.username] + # senão, simplesmente até os dois primeiros da lista + or admins[:2] + ) + for admin in admins: + admin.is_superuser = True + admin.save() + print('Usuários migrados com sucesso.') + print('#' * 100) + print('Uusários administradores:') + for admin in admins: + print(admin.username) + print('#' * 100) diff --git a/sapl/legacy/scripts/migra_um_db.sh b/sapl/legacy/scripts/migra_um_db.sh index eca35f0a3..577a2c000 100755 --- a/sapl/legacy/scripts/migra_um_db.sh +++ b/sapl/legacy/scripts/migra_um_db.sh @@ -37,9 +37,9 @@ if [ $# -ge 2 ]; then DATABASE_NAME=$1 ./manage.py migrate --settings sapl.legacy_migration_settings echo >> $LOG - echo "--- MIGRACAO DE DADOS ---" | tee -a $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 + DATABASE_NAME=$1 ./manage.py migracao_25_31 --force --settings sapl.legacy_migration_settings 2>&1 | tee -a $LOG echo >> $LOG else echo "USO:" From f299d04b4d940ab9161ad5c7a53bb2a27350fc31 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Mon, 19 Mar 2018 14:23:37 -0300 Subject: [PATCH 095/121] Fix #1769 (#1771) --- sapl/materia/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/materia/models.py b/sapl/materia/models.py index ab4b3d074..34fd44d55 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -187,7 +187,7 @@ class MateriaLegislativa(models.Model): em_tramitacao = models.BooleanField( verbose_name=_('Em Tramitação?'), default=False, - choices=EM_TRAMITACAO) + choices=YES_NO_CHOICES) polemica = models.NullBooleanField( blank=True, verbose_name=_('Matéria Polêmica?')) objeto = models.CharField( From f65648fe64a5c66c3fb39714d7d874b39c6a3142 Mon Sep 17 00:00:00 2001 From: Edward Date: Mon, 19 Mar 2018 16:47:30 -0300 Subject: [PATCH 096/121] =?UTF-8?q?Ajusta=20chamadas=20a=20m=C3=A9todos=20?= =?UTF-8?q?clean()=20dos=20formul=C3=A1rios=20(#1773)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/base/forms.py | 9 +++++ sapl/comissoes/forms.py | 14 ++++---- sapl/compilacao/forms.py | 5 +++ sapl/materia/forms.py | 71 +++++++++++++++++++++++++++++-------- sapl/norma/forms.py | 8 +++-- sapl/parlamentares/forms.py | 16 +++++---- sapl/protocoloadm/forms.py | 16 ++++++++- sapl/sessao/forms.py | 9 +++++ 8 files changed, 116 insertions(+), 32 deletions(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 092d93b59..03d158075 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -314,6 +314,9 @@ class AutorForm(ModelForm): def clean(self): super(AutorForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + User = get_user_model() cd = self.cleaned_data @@ -834,6 +837,9 @@ class RecuperarSenhaForm(PasswordResetForm): def clean(self): super(RecuperarSenhaForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + email_existente = User.objects.filter( email=self.data['email']).exists() @@ -895,6 +901,9 @@ class AlterarSenhaForm(Form): def clean(self): super(AlterarSenhaForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + data = self.cleaned_data new_password1 = data['new_password1'] diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index e3d9845c3..dd2c037da 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -64,10 +64,6 @@ class ParticipacaoCreateForm(forms.ModelForm): qs = q1 | q2 | q3 return qs - def clean(self): - super(ParticipacaoCreateForm, self).clean() - return self.cleaned_data - def verifica(self): composicao = Composicao.objects.get(id=self.initial['parent_pk']) participantes = composicao.participacao_set.all() @@ -125,6 +121,9 @@ class ComissaoForm(forms.ModelForm): def clean(self): super(ComissaoForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + if self.cleaned_data['data_extincao']: if (self.cleaned_data['data_extincao'] < self.cleaned_data['data_criacao']): @@ -160,6 +159,9 @@ class ReuniaoForm(ModelForm): def clean(self): super(ReuniaoForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + if self.cleaned_data['hora_fim']: if (self.cleaned_data['hora_fim'] < self.cleaned_data['hora_inicio']): @@ -189,10 +191,6 @@ class DocumentoAcessorioCreateForm(forms.ModelForm): def create_documentoacessorio(self): reuniao = Reuniao.objects.get(id=self.initial['parent_pk']) - def clean(self): - super(DocumentoAcessorioCreateForm, self).clean() - return self.cleaned_data - class DocumentoAcessorioEditForm(forms.ModelForm): diff --git a/sapl/compilacao/forms.py b/sapl/compilacao/forms.py index f51504f2c..dadf617b2 100644 --- a/sapl/compilacao/forms.py +++ b/sapl/compilacao/forms.py @@ -1177,6 +1177,11 @@ class DispositivoEdicaoAlteracaoForm(ModelForm): inst.dispositivo_atualizador)] def clean(self): + super(DispositivoEdicaoAlteracaoForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + """os cleans individuais do framework não puderam ser usados devido a última validação compor dois valores """ diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index d89f30578..7f9e8d114 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -145,6 +145,9 @@ class MateriaSimplificadaForm(ModelForm): def clean(self): super(MateriaSimplificadaForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + cleaned_data = self.cleaned_data data_apresentacao = cleaned_data['data_apresentacao'] @@ -167,6 +170,9 @@ class MateriaLegislativaForm(ModelForm): def clean(self): super(MateriaLegislativaForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + cleaned_data = self.cleaned_data data_apresentacao = cleaned_data['data_apresentacao'] @@ -197,6 +203,9 @@ class UnidadeTramitacaoForm(ModelForm): def clean(self): super(UnidadeTramitacaoForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + cleaned_data = self.cleaned_data for key in list(cleaned_data.keys()): @@ -255,6 +264,9 @@ class RelatoriaForm(ModelForm): def clean(self): super(RelatoriaForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + cleaned_data = self.cleaned_data try: @@ -287,7 +299,12 @@ class TramitacaoForm(ModelForm): self.fields['data_tramitacao'].initial = timezone.now().date() def clean(self): - cleaned_data = super(TramitacaoForm, self).clean() + super(TramitacaoForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + + cleaned_data = self.cleaned_data if 'data_encaminhamento' in cleaned_data: data_enc_form = cleaned_data['data_encaminhamento'] @@ -296,9 +313,6 @@ class TramitacaoForm(ModelForm): if 'data_tramitacao' in cleaned_data: data_tram_form = cleaned_data['data_tramitacao'] - if self.errors: - return self.errors - ultima_tramitacao = Tramitacao.objects.filter( materia_id=self.instance.materia_id).exclude( id=self.instance.id).order_by( @@ -367,6 +381,11 @@ class TramitacaoUpdateForm(TramitacaoForm): } def clean(self): + super(TramitacaoUpdateForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + ultima_tramitacao = Tramitacao.objects.filter( materia_id=self.instance.materia_id).order_by( '-data_tramitacao', @@ -424,8 +443,8 @@ class LegislacaoCitadaForm(ModelForm): def clean(self): super(LegislacaoCitadaForm, self).clean() - if self.errors: - return self.errors + if not self.is_valid(): + return self.cleaned_data cleaned_data = self.cleaned_data @@ -487,8 +506,8 @@ class NumeracaoForm(ModelForm): def clean(self): super(NumeracaoForm, self).clean() - if self.errors: - return self.errors + if not self.is_valid(): + return self.cleaned_data try: MateriaLegislativa.objects.get( @@ -532,8 +551,8 @@ class AnexadaForm(ModelForm): def clean(self): super(AnexadaForm, self).clean() - if self.errors: - return self.errors + if not self.is_valid(): + return self.cleaned_data cleaned_data = self.cleaned_data @@ -725,8 +744,8 @@ class DespachoInicialForm(ModelForm): def clean(self): super(DespachoInicialForm, self).clean() - if self.errors: - return self.errors + if not self.is_valid(): + return self.cleaned_data if DespachoInicial.objects.filter( materia=self.instance.materia, @@ -770,8 +789,8 @@ class AutoriaForm(ModelForm): def clean(self): cd = super(AutoriaForm, self).clean() - if self.errors: - return self.errors + if not self.is_valid(): + return self.cleaned_data autorias = Autoria.objects.filter( materia=self.instance.materia, autor=cd['autor']) @@ -993,6 +1012,9 @@ class TipoProposicaoForm(ModelForm): def clean(self): super(TipoProposicaoForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + cd = self.cleaned_data content_type = cd['content_type'] @@ -1227,6 +1249,9 @@ class ProposicaoForm(forms.ModelForm): def clean(self): super(ProposicaoForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + cd = self.cleaned_data tm, am, nm = (cd.get('tipo_materia', ''), @@ -1319,6 +1344,9 @@ class DevolverProposicaoForm(forms.ModelForm): def clean(self): super(DevolverProposicaoForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + cd = self.cleaned_data if 'justificativa_devolucao' not in cd or\ @@ -1501,6 +1529,9 @@ class ConfirmarProposicaoForm(ProposicaoForm): def clean(self): super(ConfirmarProposicaoForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + numeracao = sapl.base.models.AppConfig.attr('sequencia_numeracao') if not numeracao: @@ -1825,6 +1856,11 @@ class EtiquetaPesquisaForm(forms.Form): ) def clean(self): + super(EtiquetaPesquisaForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + cleaned_data = self.cleaned_data # Verifica se algum campo de data foi preenchido @@ -1893,7 +1929,12 @@ class FichaPesquisaForm(forms.Form): ) def clean(self): - cleaned_data = super(FichaPesquisaForm, self).clean() + super(FichaPesquisaForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + + cleaned_data = self.cleaned_data if not self.is_valid(): return cleaned_data diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index 87a44d41f..affe07b87 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -193,8 +193,8 @@ class NormaRelacionadaForm(ModelForm): def clean(self): super(NormaRelacionadaForm, self).clean() - if self.errors: - return self.errors + if not self.is_valid(): + return self.cleaned_data cleaned_data = self.cleaned_data try: @@ -263,6 +263,10 @@ class NormaPesquisaSimplesForm(forms.Form): def clean(self): super(NormaPesquisaSimplesForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + cleaned_data = self.cleaned_data data_inicial = cleaned_data['data_inicial'] diff --git a/sapl/parlamentares/forms.py b/sapl/parlamentares/forms.py index a159ca233..acee7d7e1 100644 --- a/sapl/parlamentares/forms.py +++ b/sapl/parlamentares/forms.py @@ -258,8 +258,8 @@ class FiliacaoForm(ModelForm): def clean(self): super(FiliacaoForm, self).clean() - if self.errors: - return self.errors + if not self.is_valid(): + return self.cleaned_data filiacao = super(FiliacaoForm, self).save(commit=False) validacao = validar_datas(self.cleaned_data['data'], @@ -282,6 +282,9 @@ class ComposicaoColigacaoForm(ModelForm): def clean(self): super(ComposicaoColigacaoForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + cleaned_data = self.cleaned_data pk = self.initial['coligacao_id'] if (ComposicaoColigacao.objects.filter( @@ -289,10 +292,8 @@ class ComposicaoColigacaoForm(ModelForm): partido=cleaned_data.get('partido')).exists()): msg = _('Esse partido já foi cadastrado nesta coligação.') raise ValidationError(msg) - else: - if self.errors: - return self.errors - return self.cleaned_data + + return self.cleaned_data class FrenteForm(ModelForm): @@ -352,6 +353,9 @@ class VotanteForm(ModelForm): def clean(self): super(VotanteForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + cd = self.cleaned_data username = cd['username'] diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index de647a243..bd26feb81 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -217,7 +217,7 @@ class AnularProcoloAdmForm(ModelForm): def clean(self): super(AnularProcoloAdmForm, self).clean() - cleaned_data = super(AnularProcoloAdmForm, self).clean() + cleaned_data = self.cleaned_data if not self.is_valid(): return cleaned_data @@ -409,6 +409,9 @@ class ProtocoloMateriaForm(ModelForm): def clean(self): super(ProtocoloMateriaForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + data = self.cleaned_data if self.is_valid(): if data['vincular_materia'] == 'True': @@ -485,6 +488,9 @@ class TramitacaoAdmForm(ModelForm): def clean(self): cleaned_data = super(TramitacaoAdmForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + if 'data_encaminhamento' in cleaned_data: data_enc_form = cleaned_data['data_encaminhamento'] if 'data_fim_prazo' in cleaned_data: @@ -556,6 +562,11 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm): ] def clean(self): + super(TramitacaoAdmEditForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + ultima_tramitacao = TramitacaoAdministrativo.objects.filter( documento_id=self.instance.documento_id).order_by( '-data_tramitacao', @@ -617,6 +628,9 @@ 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(): diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index 40b09c762..470d27573 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -109,6 +109,9 @@ class BancadaForm(ModelForm): def clean(self): super(BancadaForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + if self.cleaned_data['data_extincao']: if (self.cleaned_data['data_extincao'] < self.cleaned_data['data_criacao']): @@ -141,6 +144,9 @@ class BlocoForm(ModelForm): def clean(self): super(BlocoForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + if self.cleaned_data['data_extincao']: if (self.cleaned_data['data_extincao'] < self.cleaned_data['data_criacao']): @@ -523,6 +529,9 @@ class ResumoOrdenacaoForm(forms.Form): def clean(self): super(ResumoOrdenacaoForm, self).clean() + if not self.is_valid(): + return self.cleaned_data + cleaned_data = self.cleaned_data for c1 in cleaned_data: From 67fb477a450f59699da8429fcae2f5e932a1e77e Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 20 Mar 2018 10:21:29 -0300 Subject: [PATCH 097/121] =?UTF-8?q?HOT-FIX:=20conserta=20exibi=C3=A7=C3=A3?= =?UTF-8?q?o,=20adi=C3=A7=C3=A3o=20e=20edi=C3=A7=C3=A3o=20de=20parlamentar?= =?UTF-8?q?es=20em=20Frente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/templates/parlamentares/frente_form.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/templates/parlamentares/frente_form.html b/sapl/templates/parlamentares/frente_form.html index 5d9ae8fc1..bbab780ae 100644 --- a/sapl/templates/parlamentares/frente_form.html +++ b/sapl/templates/parlamentares/frente_form.html @@ -22,7 +22,7 @@ -
    Nome de UsuárioNome de LoginNome E-mail do Usuário
    {{ user.username }} {{ user.first_name }} {{ user.last_name }} {{ user.email }}
    - - - - - - - - - -
    - Tipo: IND - - Número: 1 - - Ano: 2015 -
    - Ementa: TESTE -
    - -
    Matéria Anexada - - - - - - - - - - -
    -  
    - -
    -  
    - -
    -  
    - -
    -  
    - - -
    -
    - - -
    -
    -

    -    -

    - - -

     

    - - - - - -
    - -
    -
    - Av. George Washington, 3580 - - São José da Lagoa Tapada - PB - - CEP: 12345-678 - - Telefone: (12)3456-7890 - - Fax: (09)8765-4321 -
    - - Portal: http://www.camaramunicipal.gov.br - - E-mail: faleconosco@camaramunicipal.gov.br -
    -
    - Desenvolvido pelo Interlegis - Desenvolvido em Zope -
    -
    - - - - - diff --git a/sapl/legacy/scripts/original_forms/AssuntoNorma.html b/sapl/legacy/scripts/original_forms/AssuntoNorma.html deleted file mode 100644 index 99756a7ad..000000000 --- a/sapl/legacy/scripts/original_forms/AssuntoNorma.html +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    - - -
    Assunto Norma Jurídica - - - - -
    - - - - - - - -
    Assunto (*)
    -
    Descrição
    - -
    -

    - -    -

    -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Autor.html b/sapl/legacy/scripts/original_forms/Autor.html deleted file mode 100644 index 417105dbe..000000000 --- a/sapl/legacy/scripts/original_forms/Autor.html +++ /dev/null @@ -1,491 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início
    - - - - - - - -
    Autor - - - - - - - -
    Tipo (*)
    - -
    Autor (*)
    - -
    - - -
    - Acesso ao SAPL - - - - - - - -
    - Conceder ao Autor acesso especial ao SAPL como usuário do perfil "Autor"?
    - Sim - Não -
    -  Login:   -
    -
    -
    -
    - -    -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Autoria.html b/sapl/legacy/scripts/original_forms/Autoria.html deleted file mode 100644 index abf614573..000000000 --- a/sapl/legacy/scripts/original_forms/Autoria.html +++ /dev/null @@ -1,487 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -Ajuda - -

    Matéria Legislativa

    - - - -
    - - - - - - -
    - -
    - - - - - - - - - - -
    - Tipo: Emenda - - Número: 6 - - Ano: 2014 -
    - Ementa: DEPOIS DA PARALISAÇÃO DA REFORMA DO AUTÓDROMO INTERNACIONAL NELSON PIQUET E O CONSEQUENTE CANCELAMENTO DA ETAPA DE ABERTURA DA FÓRMULA INDY EM BRASÍLIA, O GOVERNADOR DO DISTRITO FEDERAL, RODRIGO ROLLEMBERG, E O PRESIDENTE DO TRIBUNAL DE CONTAS DO DF, RENATO RAINHA, FIZERAM UMA VISITA TÉCNICA AO LOCAL NA MANHÃ DESTA QUINTA-FEIRA (12/2). APESAR DA EXPECTATIVA, NÃO HOUVE O ANÚNCIO DE UMA DATA PARA A RETOMADA DAS OBRAS. EM CONVERSA COM OS REPÓRTERES PRESENTES, ROLLEMBERG EVITOU FALAR SOBRE DATAS. “O PRAZO É O DA SEGURANÇA JURÍDICA. NÓS TEMOS A DETERMINAÇÃO DE RECUPERAR O AUTÓDROMO COMO UM EQUIPAMENTO PÚBLICO IMPORTANTE PARA A CIDADE, MAS QUEREMOS FAZER ISSO COM TODA SEGURANÇA. -
    - - -
    Autoria - - - - - - -
     
    - -
     
    - -
    -  
    - - Sim - - Não -
    -
    -

    - -

    -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Bancada.html b/sapl/legacy/scripts/original_forms/Bancada.html deleted file mode 100644 index 41042f9a9..000000000 --- a/sapl/legacy/scripts/original_forms/Bancada.html +++ /dev/null @@ -1,645 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - - Ajuda - -

    Tabelas Auxiliares

    - - - - - -
    | Voltar |
    - -
    - - - -
    - Cadastro de Bancada, Bloco, Frente ou Grupo - - - - - - - - - - - - - - - -

    - -

    - -

    - -

    - -

    - -

    - -
    - -

    - -

    - -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/CasaLegislativa.html b/sapl/legacy/scripts/original_forms/CasaLegislativa.html deleted file mode 100644 index 17f94aba0..000000000 --- a/sapl/legacy/scripts/original_forms/CasaLegislativa.html +++ /dev/null @@ -1,544 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - -
    - - - - - - -

    Tabelas Auxiliares

    - -
    Casa Legislativa - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    -

    -

    -

    -

    -

    - - -

    - -

    -

    -

    -

    - cor

    - cor

    - cor

    - - -

    -

    -

    -
    -

    - -   

    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Coligacao.html b/sapl/legacy/scripts/original_forms/Coligacao.html deleted file mode 100644 index 1b0baef09..000000000 --- a/sapl/legacy/scripts/original_forms/Coligacao.html +++ /dev/null @@ -1,486 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - - -
    - | Composição || Início |
    -
    Coligação - - - - - - - - -
    - - - - - - -
    Nome (*)
    -
    Nº Legislatura (*)
    - -
    Nº Votos Recebidos
    -

    -

    - -    -

    -
    -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Comissao.html b/sapl/legacy/scripts/original_forms/Comissao.html deleted file mode 100644 index 1d5d419ba..000000000 --- a/sapl/legacy/scripts/original_forms/Comissao.html +++ /dev/null @@ -1,604 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - -Ajuda -

    Comissões

    - - -
    - - - - - - -
    - Dados Básicos - - - - - - - - - - - -
    Nome da Comissâo  
    - -
    Sigla  
    - -
    Tipo  
    - -
    Data Criação  
    - -
    Unidade Deliberativa 
    - - Não - - Sim -
    Data Extinção
    - -
    -
    - -
    - Dados Complementares - - - - - - - - - - - - - - - - - - - -
    Local Reunião
    - -
    Data/Hora Reunião
    - -
    Tel. Sala Reunião
    - -
    Endereço Secretaria
    - -
    Tel. Secretaria
    - -
    Fax Secretaria
    - -
    Secretário
    - -
    E-mail
    - -
    Finalidade - -
    -
    - -
    - Temporária - - - - - - - - - - -
    Apelido
    - -
    Data Instalação
    - -
    Data Prevista Término
    - -
    Novo Prazo
    - -
    Data Término
    - -
    -
    -

    - -

    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/ComposicaoComissao.html b/sapl/legacy/scripts/original_forms/ComposicaoComissao.html deleted file mode 100644 index 460443369..000000000 --- a/sapl/legacy/scripts/original_forms/ComposicaoComissao.html +++ /dev/null @@ -1,508 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - -

    Comissão de Constituição e Justiça

    -
    - - - - - - - -
    - Composição - - - - - - - - - - - - - - - - -
    Parlamentar  
    - -
    Titular  
    - - Não - - Sim -
    Cargo  
    - -
    Data Designação  
    - -
    Data Desligamento
    - -
    Motivo Desligamento
    - -
    Observação
    - -
    -
    - -

    - -    -

    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - \ No newline at end of file diff --git a/sapl/legacy/scripts/original_forms/Dependente.html b/sapl/legacy/scripts/original_forms/Dependente.html deleted file mode 100644 index 81b14d925..000000000 --- a/sapl/legacy/scripts/original_forms/Dependente.html +++ /dev/null @@ -1,485 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - -Ajuda - - - - -

    Dependente

    - -
    - - - - - - - -
    Dependentes - - - - - - - - - - - - - - - -
    Nome  
    - -
    Tipo  
    - -
    Sexo  
    - - Masculino - - Feminino -
    Data Nascimento
    - -
    CPF
    - -
    RG
    - -
    Nº Título Eleitor
    - -
    -
    -

    - -    -


    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/DocumentoAcessorio.html b/sapl/legacy/scripts/original_forms/DocumentoAcessorio.html deleted file mode 100644 index 13eae1195..000000000 --- a/sapl/legacy/scripts/original_forms/DocumentoAcessorio.html +++ /dev/null @@ -1,684 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - - - - - -Ajuda - -

    Matéria Legislativa

    - - - -
    - -
    - - - - - - - - - - -
    - Tipo: Emenda - - Número: 6 - - Ano: 2014 -
    - Ementa: DEPOIS DA PARALISAÇÃO DA REFORMA DO AUTÓDROMO INTERNACIONAL NELSON PIQUET E O CONSEQUENTE CANCELAMENTO DA ETAPA DE ABERTURA DA FÓRMULA INDY EM BRASÍLIA, O GOVERNADOR DO DISTRITO FEDERAL, RODRIGO ROLLEMBERG, E O PRESIDENTE DO TRIBUNAL DE CONTAS DO DF, RENATO RAINHA, FIZERAM UMA VISITA TÉCNICA AO LOCAL NA MANHÃ DESTA QUINTA-FEIRA (12/2). APESAR DA EXPECTATIVA, NÃO HOUVE O ANÚNCIO DE UMA DATA PARA A RETOMADA DAS OBRAS. EM CONVERSA COM OS REPÓRTERES PRESENTES, ROLLEMBERG EVITOU FALAR SOBRE DATAS. “O PRAZO É O DA SEGURANÇA JURÍDICA. NÓS TEMOS A DETERMINAÇÃO DE RECUPERAR O AUTÓDROMO COMO UM EQUIPAMENTO PÚBLICO IMPORTANTE PARA A CIDADE, MAS QUEREMOS FAZER ISSO COM TODA SEGURANÇA. -
    - - -
    -
    - Documento Acessório - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -   -
    - -
    -  
    -
    -  
    - -
    -  
    - - Pesquisar -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    - - -
    - -

    - -    - -

    -
    - - -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/DocumentoAcessorioAdministrativo.html b/sapl/legacy/scripts/original_forms/DocumentoAcessorioAdministrativo.html deleted file mode 100644 index e6c0b0a3a..000000000 --- a/sapl/legacy/scripts/original_forms/DocumentoAcessorioAdministrativo.html +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - -
    -
    - - -

    - Logotipo da Casa Legislativa -

    -
    -

    Câmara Municipal de Demonstração

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    -
    - Busca por palavra-chave - - -
    -
    -
    -
    -
    - -
    - usuário: saploper - -
    -
    - -
    - - -
    - - - - - - - - - -

    Documento Administrativo

    - -
    - -
    Documento Administrativo - - - - - - - - - - - -
    - Tipo: CNV - - Número: 1 - - Ano: 2015 -
    - Assunto: AAAAA -
    - - -
    Documento Acessório - - - - - - - - - - - - - - - - - - -

    - -

    - -

    - - -

    - -

    - -
    -

    - -
    - - -
    - -

    - -    -

    - - - -
    -
    -
    -
    -
    -
    - Av. George Washington, 3580 - - São José da Lagoa Tapada - PB - - CEP: 12345-678 - - Telefone: (12)3456-7890 - - Fax: (09)8765-4321 -
    - - Portal: http://www.camaramunicipal.gov.br - - E-mail: faleconosco@camaramunicipal.gov.br -
    -
    - Desenvolvido pelo Interlegis - Desenvolvido em Zope -
    -
    -
    - - - - diff --git a/sapl/legacy/scripts/original_forms/DocumentoAdministrativo.html b/sapl/legacy/scripts/original_forms/DocumentoAdministrativo.html deleted file mode 100644 index 319ce746a..000000000 --- a/sapl/legacy/scripts/original_forms/DocumentoAdministrativo.html +++ /dev/null @@ -1,429 +0,0 @@ - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - -
    -
    - - -

    - Logotipo da Casa Legislativa -

    -
    -

    Câmara Municipal de Demonstração

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    -
    - Busca por palavra-chave - - -
    -
    -
    -
    -
    - -
    - usuário: saploper - -
    -
    - -
    - - -
    - - - - - - - - -Ajuda -

    Documentos Administrativos

    - -
    - -
    - Formulário de Cadastro - - - - - -
    - Indentificação Básica - - - - - - - - - - - - - - - - - - - - - -

    - -

    - - -

    - - -

    - - - -

    - -
      - -

    - -
     
    - - Sim - - Não -

    - - -
    -
    - -
    - Outras Informações - - - - - - - -

    - -

    - - -
    - -
    -
    -

    - -    -

    -
    -
    - -
    -
    -
    -
    -
    - Av. George Washington, 3580 - - São José da Lagoa Tapada - PB - - CEP: 12345-678 - - Telefone: (12)3456-7890 - - Fax: (09)8765-4321 -
    - - Portal: http://www.camaramunicipal.gov.br - - E-mail: faleconosco@camaramunicipal.gov.br -
    -
    - Desenvolvido pelo Interlegis - Desenvolvido em Zope -
    -
    -
    - - - - diff --git a/sapl/legacy/scripts/original_forms/ExpedienteMateria.html b/sapl/legacy/scripts/original_forms/ExpedienteMateria.html deleted file mode 100644 index 18688b1b4..000000000 --- a/sapl/legacy/scripts/original_forms/ExpedienteMateria.html +++ /dev/null @@ -1,250 +0,0 @@ - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - -
    -Ajuda -

    Matérias do Expediente

    - -

    2ª Reunião Ordinária da 3ª Sessão Legislativa da 14ª Legislatura
    14 de Abril de 2015 (Terça-feira) - -

    - -
    -
    - Cadastro de Matérias do Expediente - - - - - - - - - - - - - - - - - - -
    -
    - -
    -
    - -
    -
    - - -
    -
    - -
    -
    - -
    - -
    - -
    -
    - - - Simbólica - - Nominal - - Secreta -
    -
    -
    - -
    -
    -

    - -   -   - -

    - - - -
    -
    - diff --git a/sapl/legacy/scripts/original_forms/Filiacao.html b/sapl/legacy/scripts/original_forms/Filiacao.html deleted file mode 100644 index 94988e2d4..000000000 --- a/sapl/legacy/scripts/original_forms/Filiacao.html +++ /dev/null @@ -1,656 +0,0 @@ - - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - -Ajuda - - - - -

    Filiação

    - -
    - - - - - - -
    - Filiações Partidárias - - - - - - -
    Partido  
    -
    Data Filiação  
    - -
    Data Desfiliação
    - - -
    - -

    - -    - -

    - - - - - - - - - - -
    -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - - - diff --git a/sapl/legacy/scripts/original_forms/LegislacaoCitada.html b/sapl/legacy/scripts/original_forms/LegislacaoCitada.html deleted file mode 100644 index 5fec95b9e..000000000 --- a/sapl/legacy/scripts/original_forms/LegislacaoCitada.html +++ /dev/null @@ -1,529 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - -

    Matéria Legislativa

    - -
    - - - -
    Legislação Citada - - - - - - - - - - - - - - - - - - - - - - - -
    -  
    -
    -  
    -
    -  
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    - - - - - - - - - -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Legislatura.html b/sapl/legacy/scripts/original_forms/Legislatura.html deleted file mode 100644 index 66d1588cc..000000000 --- a/sapl/legacy/scripts/original_forms/Legislatura.html +++ /dev/null @@ -1,437 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    - -
    Legislatura - - - - -
    - - - - - - - - - - -
    Nº Legislatura (*)
    -
    Data Início (*)
    - -
    (dd/mm/aaaa)
    Data Fim (*)
    - -
    (dd/mm/aaaa)
    Data Eleição (*)
    - -
    (dd/mm/aaaa)
    - -

    - -    -

    -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/LexmlRegistroProvedor.html b/sapl/legacy/scripts/original_forms/LexmlRegistroProvedor.html deleted file mode 100644 index bff82389c..000000000 --- a/sapl/legacy/scripts/original_forms/LexmlRegistroProvedor.html +++ /dev/null @@ -1,376 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - -
    - Provedor LexML - - - - - - - - - - - - - - - - - - - - - - - - -
    Id do provedor (*)
    - -
    Nome do provedor
    - -
    Id do responsável
    - -
    Nome do responsável
    - -
    E-mail do responsável
    - -
    - Endereço do provedor OAI - - http://sapl3.interlegis.leg.br/oai -
    XML fornecido pela equipe do LexML:
    - -
    - -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/LexmlRegistroPublicador.html b/sapl/legacy/scripts/original_forms/LexmlRegistroPublicador.html deleted file mode 100644 index 6336408b8..000000000 --- a/sapl/legacy/scripts/original_forms/LexmlRegistroPublicador.html +++ /dev/null @@ -1,360 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    -
    - Publicador LexML - - - - - - - - - - - - - - -
    Id do publicador (*)
    - -
    Nome do publicador
    - -
    Sigla do publicador
    - -
    Id do responsável
    - -
    Nome do responsável
    - -
    E-mail do responsável
    - -
    - -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Mandato.html b/sapl/legacy/scripts/original_forms/Mandato.html deleted file mode 100644 index fe966bee9..000000000 --- a/sapl/legacy/scripts/original_forms/Mandato.html +++ /dev/null @@ -1,611 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - - - - - - - - - - - - -

    Mandato

    - - - - -
    - - - - -
    Mandato - - - - - - - - - - - - - - - -
    Legislatura  
    - -
    Coligação
    - -
    Votos Recebidos
    -
    - Natureza do Mandato 
    - - Titular - - Suplente -
    Início do Mandato  
    - -
    Fim do Mandato  
    - -
    Expedição do Diploma
    - -
    Observação
    -
    -
    -

    - -

    - - - - - - -

    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/MateriaLegislativa.html b/sapl/legacy/scripts/original_forms/MateriaLegislativa.html deleted file mode 100644 index 07c174401..000000000 --- a/sapl/legacy/scripts/original_forms/MateriaLegislativa.html +++ /dev/null @@ -1,952 +0,0 @@ - - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Demonstração - - - DF -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - - - -Ajuda -

    Matéria Legislativa

    - - - -
    - - - - - - -
    - Identificação Básica - - - - - - - - - - - - - - - - - - - -

    - - - -

    - - -

    - -

    - -

    - - -

    - - Oral - - Escrita -

    - - -
    -
    - - Gerar ODT -
    -
    -
    - Proposição Eletrônica - - - - -
    - Esta matéria não foi gerada a partir de uma proposição eletrônica. -
    -
    - - -
    - Outras Informações - - - - - - - - - - - - - - - - - -

    - -

    - -

    - - Sim - - Não -

    - -

    -

    - - Sim - - Não -

    - -

    - -

    - - Sim - - Não -

    - -
    -
    -
    - Origem Externa - - - - - - - - - - -

    - -

    - -

    -
    -

    - -

    - -
    -
    -
    - Dados Textuais - - - - - - - - - - -
      - -
    - -
    - -
    -
    - -

    - - -

    -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - - - diff --git a/sapl/legacy/scripts/original_forms/NormaJuridica.html b/sapl/legacy/scripts/original_forms/NormaJuridica.html deleted file mode 100644 index 4c1a1f4ab..000000000 --- a/sapl/legacy/scripts/original_forms/NormaJuridica.html +++ /dev/null @@ -1,788 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - - - - - -Ajuda - -

    Norma Jurídica

    - - - - -
    - -
    - Identificação Básica - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     
    - -
     
    - -
     
    - - -
     
    - -
     
    - -

    - - Sim - - Não -

    -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -

    - - - -
    -
    - -
     
    - -

    - -

    - -
    -
    - -
    -
    - Assuntos (Classificação) [+] -
    - - - - - - - - - - -
    - -
    - -
    - -
    -
    -
    -
    - - -

    - - -

    - - - - - - -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Numeracao.html b/sapl/legacy/scripts/original_forms/Numeracao.html deleted file mode 100644 index 494a31e33..000000000 --- a/sapl/legacy/scripts/original_forms/Numeracao.html +++ /dev/null @@ -1,542 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - -Ajuda - -

    Matéria Legislativa

    - -
    - - - - - -
    - -
    - - - - - - - - - - -
    - Tipo: Emenda - - Número: 6 - - Ano: 2014 -
    - Ementa: DEPOIS DA PARALISAÇÃO DA REFORMA DO AUTÓDROMO INTERNACIONAL NELSON PIQUET E O CONSEQUENTE CANCELAMENTO DA ETAPA DE ABERTURA DA FÓRMULA INDY EM BRASÍLIA, O GOVERNADOR DO DISTRITO FEDERAL, RODRIGO ROLLEMBERG, E O PRESIDENTE DO TRIBUNAL DE CONTAS DO DF, RENATO RAINHA, FIZERAM UMA VISITA TÉCNICA AO LOCAL NA MANHÃ DESTA QUINTA-FEIRA (12/2). APESAR DA EXPECTATIVA, NÃO HOUVE O ANÚNCIO DE UMA DATA PARA A RETOMADA DAS OBRAS. EM CONVERSA COM OS REPÓRTERES PRESENTES, ROLLEMBERG EVITOU FALAR SOBRE DATAS. “O PRAZO É O DA SEGURANÇA JURÍDICA. NÓS TEMOS A DETERMINAÇÃO DE RECUPERAR O AUTÓDROMO COMO UM EQUIPAMENTO PÚBLICO IMPORTANTE PARA A CIDADE, MAS QUEREMOS FAZER ISSO COM TODA SEGURANÇA. -
    - - -
    Numeração - - - - - - - - - -
    -  
    - -
    -  
    -
    -  
    -
    -
    - -
    -
    - -

    - -

    - -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Oradores.html b/sapl/legacy/scripts/original_forms/Oradores.html deleted file mode 100644 index c050e8dd2..000000000 --- a/sapl/legacy/scripts/original_forms/Oradores.html +++ /dev/null @@ -1,572 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - -Ajuda -

    Oradores das Explicações Pessoais

    -

    2ª Reunião Ordinária da 3ª Sessão Legislativa da 14ª Legislatura
    14 de Abril de 2015 (Terça-feira) - -

    - -
    - - - - - - - - - - - - - - - - -
    Nenhum orador cadastrado.
    -
    -
    -
    -Cadastro de Oradores do Expediente - - - - - - - - - - - - - - -
    - - - - - - - - -
    - -
    -
    -
    -Cadastro de Discurso - - - - - - - - -
    - - - - - -
    - - - - - - - -
    -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/OradoresExpediente.html b/sapl/legacy/scripts/original_forms/OradoresExpediente.html deleted file mode 100644 index c81fba1a4..000000000 --- a/sapl/legacy/scripts/original_forms/OradoresExpediente.html +++ /dev/null @@ -1,572 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - -Ajuda -

    Oradores do Expediente

    -

    2ª Reunião Ordinária da 3ª Sessão Legislativa da 14ª Legislatura
    14 de Abril de 2015 (Terça-feira) - -

    - -
    - - - - - - - - - - - - - - - - -
    Nenhum orador cadastrado.
    -
    -
    -
    -Cadastro de Oradores do Expediente - - - - - - - - - - - - - - -
    - - - - - - - - -
    - -
    -
    -
    -Cadastro de Discurso - - - - - - - - -
    - - - - - -
    - - - - - - - -
    -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/OrdemDia.html b/sapl/legacy/scripts/original_forms/OrdemDia.html deleted file mode 100644 index 6d86301e0..000000000 --- a/sapl/legacy/scripts/original_forms/OrdemDia.html +++ /dev/null @@ -1,249 +0,0 @@ - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - -
    - Ajuda -

    Matérias da Ordem do Dia

    - -

    2ª Reunião Ordinária da 3ª Sessão Legislativa da 14ª Legislatura
    14 de Abril de 2015 (Terça-feira) - -

    - -
    -
    - Cadastro de Matérias da Ordem do Dia - - - - - - - - - - - - - - - - - - -
    -
    - -
    -
    - -
    -
    - - -
    -
    - -
    -
    - -
    - -
    - -
    -
    - - Simbólica - - Nominal - - Secreta -
    -
    -
    - -
    -
    -

    - -   -   - -

    - - - -
    -
    - diff --git a/sapl/legacy/scripts/original_forms/Orgao.html b/sapl/legacy/scripts/original_forms/Orgao.html deleted file mode 100644 index 5711e7965..000000000 --- a/sapl/legacy/scripts/original_forms/Orgao.html +++ /dev/null @@ -1,406 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    -
    Órgão - - - - - -
    - - - - - - - - - - -
    Nome (*)
    -
    Sigla (*) - Unidade Deliberativa (*)
    - - Não - - Sim -
    Endereço
    -
    Telefone
    -
    -

    - -    -

    -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Origem.html b/sapl/legacy/scripts/original_forms/Origem.html deleted file mode 100644 index 2efaf6c19..000000000 --- a/sapl/legacy/scripts/original_forms/Origem.html +++ /dev/null @@ -1,386 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    - -
    Origem - - - - -
    - - - - - -
    Nome (*)
    -
    Sigla (*)
    -
    -

    - -    -

    -
    -
    -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/PainelEletronico.html b/sapl/legacy/scripts/original_forms/PainelEletronico.html deleted file mode 100644 index 6976877ed..000000000 --- a/sapl/legacy/scripts/original_forms/PainelEletronico.html +++ /dev/null @@ -1,646 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - -
    - - - - -

    Tabelas Auxiliares

    - -
    - Propriedades do Painel Eletrônico - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - - cor da fonte do painel -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - -
    -
    - - cor da Fonte do painel -
    -
    - -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - - cor da fonte do painel -
    -
    - -
    -
    - -
    -
    - - Texto IntegralAbrir arquivo de som - -
    -
    -
    - -
    -
    - -
    -
    - -
    -

    - -   

    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Parlamentar.html b/sapl/legacy/scripts/original_forms/Parlamentar.html deleted file mode 100644 index 2c634f4cd..000000000 --- a/sapl/legacy/scripts/original_forms/Parlamentar.html +++ /dev/null @@ -1,763 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - - - - -Ajuda - -

    Parlamentares

    - -
    - - - - - - - -
    - Cadastro do Parlamentar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Nome Parlamentar  
    - -
    - Login  
    - -
    - Ativo na Casa? 
    - - Sim - - Não -
    Nome Completo 
    - -
    Nível Instrução
    - -
    Sexo 
    - - Masculino - - Feminino -
    Data Nascimento
    - - (dd/mm/aaaa) -
    C.P.F
    - -
    R.G.
    - -
    Título de Eleitor
    -
    Situação Militar
    -
    Profissão
    -
    HomePage
    -
    Correio Eletrônico
    -
    Nº Gabinete
    -
    Telefone
    -
    Fax
    -
    Endereço Residencial
    -
    CEP
    -
    Município
    - -
    UF
    -
    Telefone Residencial
    -
    Fax Residencial
    -
    Locais de Atuação
    -
    Fotografia:
    - - -
    Biografia
    - -
    Observação
    - -
    - - -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Partido.html b/sapl/legacy/scripts/original_forms/Partido.html deleted file mode 100644 index a91710511..000000000 --- a/sapl/legacy/scripts/original_forms/Partido.html +++ /dev/null @@ -1,436 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    - -
    - -
    Partido Político - - - - -
    - - - - - - - - - -
    Nome (*)
    -
    Sigla (*)
    -
    Data Criação
    - - (dd/mm/aaaa)
    Data Extinção
    - - (dd/mm/aaaa)
    -
    -

    - -    -

    -
    -
    -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/PeriodoCompComissao.html b/sapl/legacy/scripts/original_forms/PeriodoCompComissao.html deleted file mode 100644 index 0c0d5b859..000000000 --- a/sapl/legacy/scripts/original_forms/PeriodoCompComissao.html +++ /dev/null @@ -1,412 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    - - -
    Período Composição de Comissão - - - - -
    - - - - - -
    Data Início (*)
    - - (dd/mm/aaaa)
    Data Fim (*)
    - - (dd/mm/aaaa)
    -

    - -    -

    -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/PeriodoCompMesa.html b/sapl/legacy/scripts/original_forms/PeriodoCompMesa.html deleted file mode 100644 index a88375b01..000000000 --- a/sapl/legacy/scripts/original_forms/PeriodoCompMesa.html +++ /dev/null @@ -1,411 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - -

    Tabelas Auxiliares

    - - - - - -
    | Iní­cio |
    - -
    - - - - - -
    Perí­odo Composição da Mesa Diretora - - - - - -
    Data Iní­cio  
    -
    Data Fim  
    -
    -

    - -

    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Proposicao.html b/sapl/legacy/scripts/original_forms/Proposicao.html deleted file mode 100644 index f3570355e..000000000 --- a/sapl/legacy/scripts/original_forms/Proposicao.html +++ /dev/null @@ -1,646 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - - -Ajuda - -

    Proposição

    - - - - - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tipo  
    - -
    - - - -
    Descrição  
    - -
    Matéria Vinculada
    - -
    Número
    - -
    Ano
    - -
    - Texto original (PDF)
    - -
    - Modelo ODT
    - -
    - -

    - - -

    - -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Protocolo.html b/sapl/legacy/scripts/original_forms/Protocolo.html deleted file mode 100644 index c1f97eb70..000000000 --- a/sapl/legacy/scripts/original_forms/Protocolo.html +++ /dev/null @@ -1,429 +0,0 @@ - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - -
    -
    - - -

    - Logotipo da Casa Legislativa -

    -
    -

    Câmara Municipal de Demonstração

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    -
    - Busca por palavra-chave - - -
    -
    -
    -
    -
    - -
    - usuário: saploper - -
    -
    - -
    - - -
    - - - - - - - - -Ajuda -

    Documentos Administrativos

    - -
    - -
    - Formulário de Cadastro - - - - - -
    - Indentificação Básica - - - - - - - - - - - - - - - - - - - - - -

    - -

    - - -

    - - -

    - - - -

    - -
      - -

    - -
     
    - - Sim - - Não -

    - - -
    -
    - -
    - Outras Informações - - - - - - - -

    - -

    - - -
    - -
    -
    -

    - -    -

    -
    -
    - -
    -
    -
    -
    -
    - Av. George Washington, 3580 - - São José da Lagoa Tapada - PB - - CEP: 12345-678 - - Telefone: (12)3456-7890 - - Fax: (09)8765-4321 -
    - - Portal: http://www.camaramunicipal.gov.br - - E-mail: faleconosco@camaramunicipal.gov.br -
    -
    - Desenvolvido pelo Interlegis - Desenvolvido em Zope -
    -
    -
    - - - - diff --git a/sapl/legacy/scripts/original_forms/RegistroVotacao.html b/sapl/legacy/scripts/original_forms/RegistroVotacao.html deleted file mode 100644 index 56814e2e2..000000000 --- a/sapl/legacy/scripts/original_forms/RegistroVotacao.html +++ /dev/null @@ -1,280 +0,0 @@ - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - -
    -Ajuda -

    Votação

    -

    1ª Reunião Ordinária da 3ª Sessão Legislativa da 14ª Legislatura
    12 de Fevereiro de 2015 (Quinta-feira) - -

    - -
    - - - - - - - - - - - - -
    - Votação Simbólica - - - - - - - - - - - - - - - - - - - - - -
    - Matéria: IND 90 2009 - Indicação
    - Ementa: INDICAÇÃO -
    -   - - -   - - -   - - -   - -
    - - -   - - Não - - Sim -
    -   - -
    - - -
    -
    - -     -
    -
    -
    -
    - - diff --git a/sapl/legacy/scripts/original_forms/Relatoria.html b/sapl/legacy/scripts/original_forms/Relatoria.html deleted file mode 100644 index c80c41e2e..000000000 --- a/sapl/legacy/scripts/original_forms/Relatoria.html +++ /dev/null @@ -1,515 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - -

    Matéria Legislativa

    - -
    - - - - - - -
    - -
    - - - - - - - - - - -
    - Tipo: Emenda - - Número: 6 - - Ano: 2014 -
    - Ementa: DEPOIS DA PARALISAÇÃO DA REFORMA DO AUTÓDROMO INTERNACIONAL NELSON PIQUET E O CONSEQUENTE CANCELAMENTO DA ETAPA DE ABERTURA DA FÓRMULA INDY EM BRASÍLIA, O GOVERNADOR DO DISTRITO FEDERAL, RODRIGO ROLLEMBERG, E O PRESIDENTE DO TRIBUNAL DE CONTAS DO DF, RENATO RAINHA, FIZERAM UMA VISITA TÉCNICA AO LOCAL NA MANHÃ DESTA QUINTA-FEIRA (12/2). APESAR DA EXPECTATIVA, NÃO HOUVE O ANÚNCIO DE UMA DATA PARA A RETOMADA DAS OBRAS. EM CONVERSA COM OS REPÓRTERES PRESENTES, ROLLEMBERG EVITOU FALAR SOBRE DATAS. “O PRAZO É O DA SEGURANÇA JURÍDICA. NÓS TEMOS A DETERMINAÇÃO DE RECUPERAR O AUTÓDROMO COMO UM EQUIPAMENTO PÚBLICO IMPORTANTE PARA A CIDADE, MAS QUEREMOS FAZER ISSO COM TODA SEGURANÇA. -
    - - -
    Relatoria - - - - - - - - - - - - - - - -
    -  
    - -
    -
    - -
    -  
    - -
    -
    - -
    -
    - -
    -
    -

    Não é possível incluir relatoria, a matéria deve estar em uma Comissão!
    - -

    - -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/SessaoLegislativa.html b/sapl/legacy/scripts/original_forms/SessaoLegislativa.html deleted file mode 100644 index 6940da731..000000000 --- a/sapl/legacy/scripts/original_forms/SessaoLegislativa.html +++ /dev/null @@ -1,468 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    - -
    -
    Sessão Legislativa - - - - - - - -
    - - - - - - - - - - - -
    Número (*)
    -
    Tipo
    -
    Data Início (*)
    - - (dd/mm/aaaa)
    Data Fim (*)
    - - (dd/mm/aaaa)
    Início Intervalo
    - - (dd/mm/aaaa)
    Fim Intervalo
    - - (dd/mm/aaaa)

    -

    - -    -

    -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/SessaoPlenaria.html b/sapl/legacy/scripts/original_forms/SessaoPlenaria.html deleted file mode 100644 index 9890277bd..000000000 --- a/sapl/legacy/scripts/original_forms/SessaoPlenaria.html +++ /dev/null @@ -1,734 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - - - - - - - -Ajuda - -

    Sessão Plenária

    - -

    3ª Reunião Ordinária da 3ª Sessão Legislativa da 14ª Legislatura
    08 de Maio de 2015 (Sexta-feira) - -

    - - - - - - - - - - - - - -
    - - - - - - - -
    -Dados Básicos - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  
    - - -      -
    -  
    - -
    -
    - -
    -  
    - -
    -  
    - Data: - -  Horário: (hh:mm) - -  Sessão iniciada? -
     
    -
    - Data: - - -  Horário: (hh:mm) - -  Sessão finalizada? -
     

    - - - - -

    - - - - -
    -
    -
    -
    -
    -
    -
    -

    - - - -

    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - - - diff --git a/sapl/legacy/scripts/original_forms/StatusTramitacao.html b/sapl/legacy/scripts/original_forms/StatusTramitacao.html deleted file mode 100644 index f468514d2..000000000 --- a/sapl/legacy/scripts/original_forms/StatusTramitacao.html +++ /dev/null @@ -1,398 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    -
    Status Tramitação - - - - - -
    - - - - - - - - -
    Sigla (*)
    -
    Indicador da Tramitação
    -
    Descrição (*)
    -
    -
    -
    - -    -

    -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/StatusTramitacaoAdministrativo.html b/sapl/legacy/scripts/original_forms/StatusTramitacaoAdministrativo.html deleted file mode 100644 index ab83b12e2..000000000 --- a/sapl/legacy/scripts/original_forms/StatusTramitacaoAdministrativo.html +++ /dev/null @@ -1,226 +0,0 @@ - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - -
    -
    - - -

    - Logotipo da Casa Legislativa -

    -
    -

    Câmara Municipal de Demonstração

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    -
    - Busca por palavra-chave - - -
    -
    -
    -
    -
    - -
    - usuário: saploper - -
    -
    - -
    - - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    -
    Status Tramitação Administrativo - - - - - -
    - - - - - - - - -
    Sigla (*)
    -
    Indicador da Tramitação
    -
    Descrição (*)
    -
    -
    -
    - -    -

    -
    -
    -
    -
    -
    -
    -
    -
    - Av. George Washington, 3580 - - São José da Lagoa Tapada - PB - - CEP: 12345-678 - - Telefone: (12)3456-7890 - - Fax: (09)8765-4321 -
    - - Portal: http://www.camaramunicipal.gov.br - - E-mail: faleconosco@camaramunicipal.gov.br -
    -
    - Desenvolvido pelo Interlegis - Desenvolvido em Zope -
    -
    -
    - - - - diff --git a/sapl/legacy/scripts/original_forms/TipoAutor.html b/sapl/legacy/scripts/original_forms/TipoAutor.html deleted file mode 100644 index 959bcb866..000000000 --- a/sapl/legacy/scripts/original_forms/TipoAutor.html +++ /dev/null @@ -1,412 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    -
    Tipo Autor - - - - -
    - - - - - -
    Tipo (*) -
    - - Parlamentar -
    - - Comissão -
    - - Outros -
    Descrição (*)
    - - -
    -

    - -    - -

    - -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/TipoComissao.html b/sapl/legacy/scripts/original_forms/TipoComissao.html deleted file mode 100644 index 7ad6c2d91..000000000 --- a/sapl/legacy/scripts/original_forms/TipoComissao.html +++ /dev/null @@ -1,404 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    - - -
    Tipo Comissão - - - - -
    - - - - - - - - - -
    Nome (*)
    -
    Sigla (*)
    -
    Dispositivo Regimental
    - -
    Natureza (*)
    -
    -

    - -    -

    -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/TipoDocumentoAdministrativo.html b/sapl/legacy/scripts/original_forms/TipoDocumentoAdministrativo.html deleted file mode 100644 index d0615cd13..000000000 --- a/sapl/legacy/scripts/original_forms/TipoDocumentoAdministrativo.html +++ /dev/null @@ -1,388 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    - - - -
    Tipo Documento Administrativo - - - - -
    - - - - - -
    Sigla (*)
    -
    Descrição (*)
    -
    -

    - -    -

    -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/TipoExpediente.html b/sapl/legacy/scripts/original_forms/TipoExpediente.html deleted file mode 100644 index 4bba50675..000000000 --- a/sapl/legacy/scripts/original_forms/TipoExpediente.html +++ /dev/null @@ -1,368 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -Ajuda -

    Tabelas Auxiliares

    - - - - - - - -
    - | Início | -
    - -
    -
    - Tipo de Expediente - - - - - - - - - -
    - - -
    - -    -
    -
    -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/TipoNormaJuridica.html b/sapl/legacy/scripts/original_forms/TipoNormaJuridica.html deleted file mode 100644 index 26b69ca2e..000000000 --- a/sapl/legacy/scripts/original_forms/TipoNormaJuridica.html +++ /dev/null @@ -1,432 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    - - -
    Tipo Norma Jurídica - - - - -
    - - - - - - -
    Descrição (*)
    -
    Sigla (*)
    -
    Equivalente LexML (*)
    - -
    -

    - -    -

    -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/TipoProposicao.html b/sapl/legacy/scripts/original_forms/TipoProposicao.html deleted file mode 100644 index e12faf6db..000000000 --- a/sapl/legacy/scripts/original_forms/TipoProposicao.html +++ /dev/null @@ -1,460 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    - -
    Tipo Proposição - - - - -
    - - - - - - - - - - - - - - - - - -
    Descrição
    -
    Gera
    - Matéria
    - Documento
    -
    Tipo Matéria
    -
    Modelo XML
    -
    -

    - -    -

    -
    -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/TipoResultadoVotacao.html b/sapl/legacy/scripts/original_forms/TipoResultadoVotacao.html deleted file mode 100644 index 5d40db62b..000000000 --- a/sapl/legacy/scripts/original_forms/TipoResultadoVotacao.html +++ /dev/null @@ -1,368 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -Ajuda -

    Tabelas Auxiliares

    - - - - - - - -
    - | Início | -
    - -
    -
    - Tipo de Resultado da Votação - - - - - - - - - -
    - - -
    - -    -
    -
    -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/TipoSessaoPlenaria.html b/sapl/legacy/scripts/original_forms/TipoSessaoPlenaria.html deleted file mode 100644 index 0defb9d54..000000000 --- a/sapl/legacy/scripts/original_forms/TipoSessaoPlenaria.html +++ /dev/null @@ -1,378 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -Ajuda -

    Tabelas Auxiliares

    - - - - - - - -
    - | Início | -
    - -
    -
    - Tipo de Sessão Plenária - - - - - - - - - - -
    - - - - - -
    - -    -
    -
    -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/TipoSituacaoNorma.html b/sapl/legacy/scripts/original_forms/TipoSituacaoNorma.html deleted file mode 100644 index b0e1bd8a9..000000000 --- a/sapl/legacy/scripts/original_forms/TipoSituacaoNorma.html +++ /dev/null @@ -1,357 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -Ajuda - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    - -
    - -
    Situação de Norma Jurídica - - - - -
    Situação  
    -
    -
    -

    - -

    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/Tramitacao.html b/sapl/legacy/scripts/original_forms/Tramitacao.html deleted file mode 100644 index 80529566f..000000000 --- a/sapl/legacy/scripts/original_forms/Tramitacao.html +++ /dev/null @@ -1,842 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - -Ajuda -

    Matéria Legislativa

    - - - - - - - - - -
    - - - - - - -
    - -
    - - - - - - - - - - -
    - Tipo: Emenda - - Número: 6 - - Ano: 2014 -
    - Ementa: DEPOIS DA PARALISAÇÃO DA REFORMA DO AUTÓDROMO INTERNACIONAL NELSON PIQUET E O CONSEQUENTE CANCELAMENTO DA ETAPA DE ABERTURA DA FÓRMULA INDY EM BRASÍLIA, O GOVERNADOR DO DISTRITO FEDERAL, RODRIGO ROLLEMBERG, E O PRESIDENTE DO TRIBUNAL DE CONTAS DO DF, RENATO RAINHA, FIZERAM UMA VISITA TÉCNICA AO LOCAL NA MANHÃ DESTA QUINTA-FEIRA (12/2). APESAR DA EXPECTATIVA, NÃO HOUVE O ANÚNCIO DE UMA DATA PARA A RETOMADA DAS OBRAS. EM CONVERSA COM OS REPÓRTERES PRESENTES, ROLLEMBERG EVITOU FALAR SOBRE DATAS. “O PRAZO É O DA SEGURANÇA JURÍDICA. NÓS TEMOS A DETERMINAÇÃO DE RECUPERAR O AUTÓDROMO COMO UM EQUIPAMENTO PÚBLICO IMPORTANTE PARA A CIDADE, MAS QUEREMOS FAZER ISSO COM TODA SEGURANÇA. -
    - - -
    Tramitação - - - - - - - - - - - - - - - - - - - -
    -  
    - - - -
    -  
    - -
    -  
    - -
    -
    - -
    -  
    - - Sim - - Não -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -

    - -

    - -
    - -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/TramitacaoAdministrativo.html b/sapl/legacy/scripts/original_forms/TramitacaoAdministrativo.html deleted file mode 100644 index 3541373cd..000000000 --- a/sapl/legacy/scripts/original_forms/TramitacaoAdministrativo.html +++ /dev/null @@ -1,410 +0,0 @@ - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - -
    -
    - - -

    - Logotipo da Casa Legislativa -

    -
    -

    Câmara Municipal de Demonstração

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    -
    - Busca por palavra-chave - - -
    -
    -
    -
    -
    - -
    - usuário: saploper - -
    -
    - -
    - - -
    - - - - -

    Documento Administrativo

    - - - - - - - - -
    - - - - - - - -
    Documento Administrativo - - - - - - - - - - - -
    - Tipo: CNV - - Número: 1 - - Ano: 2015 -
    - Assunto: AAAAA -
    - - -
    Tramitação - - - - - - - - - - - - - - - - - - - - -

    - - - -

    - -

    -

    -

    - -

    - - -

    - -
    -
    -

    -    -

    -
    -
    -
    -
    -
    -
    -
    - Av. George Washington, 3580 - - São José da Lagoa Tapada - PB - - CEP: 12345-678 - - Telefone: (12)3456-7890 - - Fax: (09)8765-4321 -
    - - Portal: http://www.camaramunicipal.gov.br - - E-mail: faleconosco@camaramunicipal.gov.br -
    -
    - Desenvolvido pelo Interlegis - Desenvolvido em Zope -
    -
    -
    - - - - diff --git a/sapl/legacy/scripts/original_forms/UnidadeTramitacao.html b/sapl/legacy/scripts/original_forms/UnidadeTramitacao.html deleted file mode 100644 index ed2fea4ae..000000000 --- a/sapl/legacy/scripts/original_forms/UnidadeTramitacao.html +++ /dev/null @@ -1,854 +0,0 @@ - - - - - - - - - - - - - Sistema de Apoio ao Processo Legislativo - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - -
    -

    - Câmara Municipal de Piraí - - - RJ -

    -

    Sistema de Apoio ao Processo Legislativo

    -
    -
    -
    - -
    - - - - - -
    - - -

    Tabelas Auxiliares

    - - - - - -
    | Início |
    -
    - Unidade Tramitação - - - - - - - - - - - -
    Órgão
    -
    Correspondente SPDO
    - -
    Comissão
    - -
    Parlamentar
    - -
    -
    -

    - -    -

    - -
    -
    -
    -
    - -
    -
    - - -
    -
    -
    - - - diff --git a/sapl/legacy/scripts/original_forms/_auxiliares.txt b/sapl/legacy/scripts/original_forms/_auxiliares.txt deleted file mode 100644 index 992ec93ce..000000000 --- a/sapl/legacy/scripts/original_forms/_auxiliares.txt +++ /dev/null @@ -1,24 +0,0 @@ -AssuntoNormaJuridica -Autor -Bancada -CasaLegislativa -Coligacao -LexmlProvedor -LexmlPublicador -Orgao -Origem -PainelEletronico -Partido -PeriodoCompComissao -PeriodoCompMesa -SessaoLegislativa -StatusTramitacao -TipoAutor -TipoComissao -TipoExpediente -TipoNormaJuridica -TipoProposicao -TipoResultadoVotacao -TipoSessaoPlenaria -TipoSituacaoNorma -UnidadeTramitacao diff --git a/sapl/legacy/scripts/original_forms/_not_found_among_sapl25_models.txt b/sapl/legacy/scripts/original_forms/_not_found_among_sapl25_models.txt deleted file mode 100644 index 0f2f2e62c..000000000 --- a/sapl/legacy/scripts/original_forms/_not_found_among_sapl25_models.txt +++ /dev/null @@ -1,6 +0,0 @@ -CasaLegislativa -Bancada -PainelEletronico - -TipoSituacaoNorma -PeriodoCompMesa diff --git a/sapl/legacy/scripts/original_forms/_principais.txt b/sapl/legacy/scripts/original_forms/_principais.txt deleted file mode 100644 index ad6343feb..000000000 --- a/sapl/legacy/scripts/original_forms/_principais.txt +++ /dev/null @@ -1,7 +0,0 @@ -Comissao -MateriaLegislativa -NormaJuridica -Parlamentar -Proposicao -Protocolo -SessaoPlenaria diff --git a/sapl/legacy/scripts/scrap_original_forms.py b/sapl/legacy/scripts/scrap_original_forms.py deleted file mode 100644 index e7a7f3162..000000000 --- a/sapl/legacy/scripts/scrap_original_forms.py +++ /dev/null @@ -1,283 +0,0 @@ -import os -import pprint -import re -import string - -import pkg_resources -import yaml -from bs4 import BeautifulSoup -from bs4.element import NavigableString, Tag -from django.apps.config import AppConfig - -from sapl.crispy_layout_mixin import heads_and_tails -from sapl.legacy.migracao_dados import appconfs, get_renames -from sapl.legacy.scripts.utils import getsourcelines -from sapl.utils import listify - -# to prevent removal by automatic organize imports on this file -assert appconfs - -field_renames, model_renames = get_renames() - - -def _read_line(tr): - for td in tr.find_all('td'): - label = td.text.strip().split('\n')[0].strip( - '\xa0' + string.whitespace) - if label.endswith('(*)'): - label = label[:-3].strip() - names = [c.attrs['name'] - for c in td.findAll() - if isinstance(c, Tag) and 'name' in c.attrs] - if names: - name = names[0].split('_', 1)[-1] - yield name, label - - -def extract_title_and_fieldsets(model): - filename = os.path.join(os.path.dirname(__file__), - 'original_forms/%s.html' % model.__name__) - try: - with open(filename, 'r') as file: - html_doc = file.read() - except IOError: - return None, [] - - soup = BeautifulSoup(html_doc, 'html.parser') - forms = soup.find_all('form') - [form] = [f for f in forms if ('method', 'post') in f.attrs.items()] - # children are either tags or strings... - assert set(type(c) for c in form.children) == {Tag, NavigableString} - # ... and all strings are empty - assert all(not c.strip() - for c in form.children if isinstance(c, NavigableString)) - - title = soup.find('h1', {'class': 'firstHeading'}) - title = title.text.strip() if title else None - fieldsets = [dict( - legend=fieldset.find('legend').text if fieldset.find('legend') else '', - lines=[list(_read_line(tr)) for tr in fieldset.find_all('tr')]) - for fieldset in form.find_all('fieldset')] - - return title, fieldsets - - -def get_names_labels(fieldsets): - for fieldset in fieldsets: - for line in fieldset['lines']: - for name, label in line: - yield name, label - - -def print_title_and_fieldsets(model): - title, fieldsets = extract_title_and_fieldsets(model) - print('#### %s ####\n' % title) - for fieldset in fieldsets: - print(fieldset['legend']) - for line in fieldset['lines']: - print(' ' + ' | '.join('%s : %s' % (id, label) - for id, label in line)) - - -def extract_verbose_names(model): - title, fieldsets = extract_title_and_fieldsets(model) - names_to_labels = dict(get_names_labels(fieldsets)) - - field_names = [f.name for f in model._meta.fields if f.name != 'id'] - - labels = {} - field_names_to_old = field_renames[model] - for name in field_names: - old_name = field_names_to_old[name] - label = names_to_labels.get(old_name, None) - if label: - labels[name] = label - del names_to_labels[old_name] - for name, label in labels.items(): - field_names.remove(name) - non_matched = field_names, names_to_labels - return title, labels, non_matched - - -@listify -def source_with_verbose_names(model): - source = getsourcelines(model) - title, labels, non_matched = extract_verbose_names(model) - - field_regex = ' *(.+) = (models\.[^\(]*)\((.*verbose_name=_\(.*\)|.*)\)' - new_lines = [] - class_meta_already_exists = False - for line in source[1:]: - for regex, split in [ - (field_regex + ' *# (.+)', lambda groups: groups), - (field_regex, lambda groups: groups + ('',))]: - match = re.match(regex, line) - if match: - name, path, args, legacy_name = split(match.groups()) - if name in labels and 'verbose_name' not in args: - args = [args] if args.strip() else [] - args.append("verbose_name=_('%s')" % labels[name]) - args = ', '.join(args) - new_lines.append( - (' %s = %s(%s)' % (name, path, args), legacy_name)) - break - else: - if 'class Meta:' in line: - class_meta_already_exists = True - new_lines.append((line, '')) - yield source[0].rstrip() - cols = max(map(len, [line for line, _ in new_lines])) - for line, legacy_name in new_lines: - line = line.rstrip().ljust(cols) - if legacy_name: - yield line + ' # ' + legacy_name - else: - yield line - - # class Meta - if class_meta_already_exists: - return - - if title == 'Tabelas Auxiliares': - title = '' - title = title if title else '' - - def add_s(name): - return ' '.join( - p if p.endswith('s') else p + 's' for p in name.split()) - - def remove_s(name): - return ' '.join(p[:-1] if p.endswith('s') else p for p in name.split()) - - if not title: - # default title from model name - title_singular = ' '.join(re.findall('[A-Z][^A-Z]*', model.__name__)) - title_singular = re.sub('cao\\b', 'ção', title_singular) - title_singular = re.sub('ao\\b', 'ão', title_singular) - title_plural = add_s( - title_singular.replace('ção', 'ções').replace('ão', 'ões')) - - elif title.endswith('s'): - title_singular = remove_s( - title.replace('ções', 'ção').replace('ões', 'ão')) - title_plural = title - else: - title_singular = title - title_plural = add_s(title.replace('ção', 'ções').replace('ão', 'ões')) - - yield """ - class Meta: - verbose_name = _('%s') - verbose_name_plural = _('%s')""" % (title_singular, title_plural) - - -def print_app_with_verbose_names(app): - print('##################################################################') - header = '# -*- coding: utf-8 -*-\n' - for line in getsourcelines(app.models_module): - if line in ['# -*- coding: utf-8 -*-', - 'from django.utils.translation import ugettext as _', ]: - continue - elif line == 'from django.db import models': - header += '''from django.db import models -from django.utils.translation import ugettext_lazy as _ -''' - elif 'class' in line: - break - else: - header += line + '\n' - print(header.strip()) - for model in app.models.values(): - print('\n') - for p in source_with_verbose_names(model): - print(p) - - -def list_models_with_no_scrapped_data(app): - for model in app.models.values(): - if not any(extract_verbose_names(model)[:2]): - print(model.__name__) - - -@listify -def colsplit(names): - n = len(names) - d, r = 12 // n, 12 % n - spans = [d + 1] * r + [d] * (n - r) - return zip(names, spans) - - -def model_name_as_snake(model): - return re.sub('([A-Z]+)', r'_\1', model.__name__).lower().strip('_') - - -old_names_adjustments = yaml.load(pkg_resources.resource_string( - __name__, 'old_names_adjustments.yaml')) - - -@listify -def extract_fieldsets_for_current(model): - __, fieldsets = extract_title_and_fieldsets(model) - if not fieldsets: - return - - try: - reverse_field_renames = {v: k for k, v in field_renames[model].items()} - adjustments = old_names_adjustments.get(model.__name__) - if adjustments: - reverse_field_renames.update(adjustments) - - for fieldset in fieldsets: - rows = [ - colsplit( - [reverse_field_renames.get(name, '%s_FIXME' % name) - for name, ___ in line]) - for line in fieldset['lines'] if line - ] - yield [fieldset['legend']] + rows - except Exception as e: - print_title_and_fieldsets(model) - raise Exception(e, model) - - -class Under: - - def __init__(self, arg): - self.arg = arg - - def __repr__(self): - return "_('%s')" % self.arg - - -GAP = 12 -pretty_printer = pprint.PrettyPrinter(width=80 - GAP) - - -def print_crispy_form(model_or_app): - if isinstance(model_or_app, AppConfig): - for model in model_or_app.models.values(): - print_crispy_form(model) - else: - model = model_or_app - - fieldsets = extract_fieldsets_for_current(model) - if fieldsets: - print(""" -class %(name)sForm(forms.ModelForm): - - class Meta: - model = %(name)s - exclude = [] - - def __init__(self, *args, **kwargs): - super(%(name)sForm, self).__init__(*args, **kwargs) - self.helper = FormHelper() - self.helper.layout = SaplFormLayout( -""" % {'name': model.__name__}) - - for legend, rows in heads_and_tails(fieldsets): - lines = pretty_printer.pformat([Under(legend)] + rows) + ',\n\n' - for line in lines.splitlines(): - print(' ' * GAP + line if line.strip() else '') - - print(" )") diff --git a/sapl/legacy/scripts/study.py b/sapl/legacy/scripts/study.py deleted file mode 100644 index 88838d36c..000000000 --- a/sapl/legacy/scripts/study.py +++ /dev/null @@ -1,12 +0,0 @@ -from django.apps import apps - -from sapl.legacy.migracao_dados 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]: - print(model, model.objects.values_list( - 'ind_excluido', flat=True).distinct()) - -legacy_models_without_ind_excluido = [ - m for m in legacy_app.models.values() - if not any(f.name == 'ind_excluido' for f in m._meta.fields)] diff --git a/sapl/legacy/scripts/utils.py b/sapl/legacy/scripts/utils.py index 40f1abb3c..0cf623be5 100644 --- a/sapl/legacy/scripts/utils.py +++ b/sapl/legacy/scripts/utils.py @@ -4,16 +4,11 @@ from sapl.base.models import Autor from sapl.legacy.migracao_dados import appconfs -def getsourcelines(model): - return [line.rstrip('\n').decode('utf-8') - for line in inspect.getsourcelines(model)[0]] - - def get_models_com_referencia_a(apontado): - def tem_referencia_a_autor(model): + def tem_referencia_a_apontado(model): return any(getattr(field, 'related_model', None) == apontado for field in model._meta.get_fields()) return [model for app in appconfs for model in app.models.values() - if tem_referencia_a_autor(model)] + if tem_referencia_a_apontado(model)] From 508e3407a8883e1da8651a0745395dc81ba4c357 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 26 Mar 2018 14:29:19 -0300 Subject: [PATCH 115/121] HOT-FIX: adiciona fechamento de tag --- sapl/templates/materia/materialegislativa_filter.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/templates/materia/materialegislativa_filter.html b/sapl/templates/materia/materialegislativa_filter.html index 96a7eb55a..2d54016ba 100644 --- a/sapl/templates/materia/materialegislativa_filter.html +++ b/sapl/templates/materia/materialegislativa_filter.html @@ -137,7 +137,7 @@

    Acompanhar Matéria - + {% endfor %} {% else %} From da8d410647c03cf48eca2b4e6a608d2b40409ff2 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Mon, 26 Mar 2018 14:43:45 -0300 Subject: [PATCH 116/121] =?UTF-8?q?corrige=20atribui=C3=A7=C3=A3o=20de=20n?= =?UTF-8?q?=C3=B3=20raiz=20de=20dispositivos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/compilacao/models.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sapl/compilacao/models.py b/sapl/compilacao/models.py index ac1939f80..f677cf97a 100644 --- a/sapl/compilacao/models.py +++ b/sapl/compilacao/models.py @@ -1086,6 +1086,9 @@ class Dispositivo(BaseModel, TimestampedMixin): update_fields=None, clean=True): self.dispositivo_raiz = self.get_raiz() + if self.dispositivo_raiz == self: + self.dispositivo_raiz = None + self.contagem_continua = self.tipo_dispositivo.contagem_continua return super().save( From d83a57357ad4bb789b936fc0b160e4ec0f7f2c96 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 26 Mar 2018 15:31:35 -0300 Subject: [PATCH 117/121] =?UTF-8?q?HOT-FIX:=20melhora=20desempenho=20de=20?= =?UTF-8?q?busca=20de=20mat=C3=A9ria=20legislatura?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/materia/views.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 35c46ecca..99d34e6b3 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -1529,6 +1529,20 @@ class MateriaLegislativaPesquisaView(FilterView): if 'o' in self.request.GET and not self.request.GET['o']: qs = qs.order_by('-ano', 'tipo__sigla', '-numero') + qs = qs.prefetch_related("autoria_set", + "autoria_set__autor", + "numeracao_set", + "anexadas", + "tipo", + "texto_articulado", + "tramitacao_set", + "tramitacao_set__status", + "tramitacao_set__unidade_tramitacao_local", + "tramitacao_set__unidade_tramitacao_destino", + "normajuridica_set", + "registrovotacao_set", + "documentoacessorio_set") + kwargs.update({ 'queryset': qs, }) From f32cb0e99aff9e0b5737f1139e3e0e39fc5480ac Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 26 Mar 2018 16:25:48 -0300 Subject: [PATCH 118/121] =?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/materia/views.py | 22 ++++++++++------------ sapl/parlamentares/models.py | 7 ++++--- sapl/utils.py | 16 ---------------- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 99d34e6b3..08a6a50ef 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -11,8 +11,6 @@ from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse from django.db.models import Max -from django.forms.forms import Form -from django.forms.utils import ErrorDict from django.http import HttpResponse, JsonResponse from django.http.response import Http404, HttpResponseRedirect from django.shortcuts import get_object_or_404, redirect @@ -31,9 +29,8 @@ from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT, STATUS_TA_PRIVATE) from sapl.compilacao.views import IntegracaoTaView from sapl.crispy_layout_mixin import SaplFormLayout, form_actions -from sapl.crud.base import (ACTION_CREATE, ACTION_DELETE, ACTION_DETAIL, - ACTION_LIST, ACTION_UPDATE, RP_DETAIL, RP_LIST, - Crud, CrudAux, MasterDetailCrud, +from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, + MasterDetailCrud, PermissionRequiredForAppCrudMixin, make_pagination) from sapl.materia.forms import (AnexadaForm, AutoriaForm, AutoriaMultiCreateForm, @@ -44,8 +41,8 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm, from sapl.norma.models import LegislacaoCitada from sapl.parlamentares.models import Legislatura from sapl.protocoloadm.models import Protocolo -from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label, - autor_modal, gerar_hash_arquivo, get_base_url, +from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, + gerar_hash_arquivo, get_base_url, get_mime_type_from_file_extension, montar_row_autor, show_results_filter_set) @@ -57,9 +54,10 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, MateriaLegislativaFilterSet, MateriaLegislativaForm, MateriaSimplificadaForm, PrimeiraTramitacaoEmLoteFilterSet, ReceberProposicaoForm, RelatoriaForm, - TramitacaoEmLoteFilterSet, filtra_tramitacao_destino, + TramitacaoEmLoteFilterSet, UnidadeTramitacaoForm, + filtra_tramitacao_destino, filtra_tramitacao_destino_and_status, - filtra_tramitacao_status, UnidadeTramitacaoForm) + filtra_tramitacao_status) from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, DespachoInicial, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao, @@ -700,11 +698,11 @@ class ProposicaoCrud(Crud): messages.success(request, _( 'Proposição enviada com sucesso.')) Numero = MateriaLegislativa.objects.filter(tipo=p.tipo.tipo_conteudo_related, - ano = p.ano).last().numero + 1 + ano=p.ano).last().numero + 1 messages.success(request, _( '%s : nº %s de %s
    Atenção! Este número é apenas um provável ' 'número que pode não corresponder com a realidade' - %(p.tipo, Numero, p.ano))) + % (p.tipo, Numero, p.ano))) elif action == 'return': if not p.data_envio: @@ -1726,7 +1724,7 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): qr = self.request.GET.copy() context['unidade_destino'] = UnidadeTramitacao.objects.all() context['status_tramitacao'] = StatusTramitacao.objects.all() - context['turnos_tramitacao'] = TURNO_TRAMITACAO_CHOICES + context['turnos_tramitacao'] = Tramitacao.TURNO_CHOICES context['urgente_tramitacao'] = YES_NO_CHOICES context['unidade_local'] = UnidadeTramitacao.objects.all() diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py index 574c6735f..769093046 100644 --- a/sapl/parlamentares/models.py +++ b/sapl/parlamentares/models.py @@ -8,8 +8,8 @@ from model_utils import Choices from sapl.base.models import Autor from sapl.decorators import vigencia_atual -from sapl.utils import (INDICADOR_AFASTAMENTO, LISTA_DE_UFS, YES_NO_CHOICES, - SaplGenericRelation, get_settings_auth_user_model, +from sapl.utils import (LISTA_DE_UFS, YES_NO_CHOICES, SaplGenericRelation, + get_settings_auth_user_model, intervalos_tem_intersecao, restringe_tipos_de_arquivo_img, texto_upload_path) @@ -400,7 +400,8 @@ class TipoAfastamento(models.Model): descricao = models.CharField(max_length=50, verbose_name=_('Descrição')) indicador = models.CharField( max_length=1, verbose_name=_('Indicador'), default='F', - choices=INDICADOR_AFASTAMENTO) + choices=[('A', _('Afastamento')), + ('F', _('Fim de Mandato')), ]) dispositivo = models.CharField( max_length=50, blank=True, verbose_name=_('Dispositivo')) diff --git a/sapl/utils.py b/sapl/utils.py index a62625452..9d576bcea 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -276,22 +276,6 @@ def create_barcode(value, width=170, height=50): YES_NO_CHOICES = [(True, _('Sim')), (False, _('Não'))] -TURNO_TRAMITACAO_CHOICES = [ - ('P', _('Primeiro')), - ('S', _('Segundo')), - ('U', _('Único')), - ('L', _('Suplementar')), - ('F', _('Final')), - ('A', _('Votação única em Regime de Urgência')), - ('B', _('1ª Votação')), - ('C', _('2ª e 3ª Votação')), -] - -INDICADOR_AFASTAMENTO = [ - ('A', _('Afastamento')), - ('F', _('Fim de Mandato')), -] - def listify(function): @wraps(function) From 3c812ed67e1da690a8bd16fb80d79e18eeae5641 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 26 Mar 2018 18:43:16 -0300 Subject: [PATCH 119/121] =?UTF-8?q?Remove=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/base/admin.py | 21 -------- .../migrations/0016_auto_20180326_1840.py | 32 +++++++++++++ sapl/base/models.py | 48 ------------------- .../management/commands/recria_constraints.py | 10 ---- sapl/legacy/migracao_dados.py | 11 +---- sapl/rules/map_rules.py | 3 -- sapl/rules/tests/test_rules.py | 24 ++-------- 7 files changed, 37 insertions(+), 112 deletions(-) create mode 100644 sapl/base/migrations/0016_auto_20180326_1840.py delete mode 100644 sapl/legacy/management/commands/recria_constraints.py diff --git a/sapl/base/admin.py b/sapl/base/admin.py index 2f7cd0ed4..88633b0fb 100644 --- a/sapl/base/admin.py +++ b/sapl/base/admin.py @@ -3,35 +3,14 @@ from django.core.urlresolvers import reverse from django.shortcuts import redirect from django.utils.translation import ugettext_lazy as _ from reversion.models import Revision - -from sapl.base.models import ProblemaMigracao from sapl.utils import register_all_models_in_admin register_all_models_in_admin(__name__) -admin.site.unregister(ProblemaMigracao) - admin.site.site_title = 'Administração - SAPL' admin.site.site_header = 'Administração - SAPL' -@admin.register(ProblemaMigracao) -class ProblemaMigracaoAdmin(admin.ModelAdmin): - list_display = ["content_type", "object_id", "nome_campo", "problema", - "descricao", "get_url"] - - def get_url(self, obj): - - info = (obj.content_object._meta.app_label, - obj.content_object._meta.model_name) - endereco = reverse('admin:%s_%s_change' % info, - args=(obj.content_object.pk,)) - return "%s" % (endereco, endereco) - - get_url.short_description = "Endereço" - get_url.allow_tags = True - - class RevisionAdmin(admin.ModelAdmin): list_display = ('user', 'comment', 'date_created') search_fields = ('=user__username', '=user__email') diff --git a/sapl/base/migrations/0016_auto_20180326_1840.py b/sapl/base/migrations/0016_auto_20180326_1840.py new file mode 100644 index 000000000..870b58dc8 --- /dev/null +++ b/sapl/base/migrations/0016_auto_20180326_1840.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-26 21:40 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0015_appconfig_receber_recibo_proposicao'), + ] + + operations = [ + migrations.RemoveField( + model_name='argumento', + name='constraint', + ), + migrations.RemoveField( + model_name='problemamigracao', + name='content_type', + ), + migrations.DeleteModel( + name='Argumento', + ), + migrations.DeleteModel( + name='Constraint', + ), + migrations.DeleteModel( + name='ProblemaMigracao', + ), + ] diff --git a/sapl/base/models.py b/sapl/base/models.py index 3a80e4d7b..d2a6035a8 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -5,7 +5,6 @@ from django.db import models from django.db.models.signals import post_migrate from django.db.utils import DEFAULT_DB_ALIAS from django.utils.translation import ugettext_lazy as _ - from sapl.utils import (LISTA_DE_UFS, YES_NO_CHOICES, get_settings_auth_user_model, models_with_gr_for_model) @@ -59,53 +58,6 @@ class CasaLegislativa(models.Model): 'municipio': self.municipio} -@reversion.register() -class ProblemaMigracao(models.Model): - content_type = models.ForeignKey(ContentType, - verbose_name=_('Tipo de Content')) - object_id = models.PositiveIntegerField(verbose_name=_('ID do Objeto')) - content_object = GenericForeignKey('content_type', 'object_id') - nome_campo = models.CharField(max_length=100, - blank=True, - verbose_name=_('Nome do(s) Campo(s)')) - problema = models.CharField(max_length=300, verbose_name=_('Problema')) - descricao = models.CharField(max_length=300, verbose_name=_('Descrição')) - eh_stub = models.BooleanField(verbose_name=_('É stub?')) - critico = models.BooleanField( - default=False, verbose_name=_('Crítico')) - - class Meta: - verbose_name = _('Problema na Migração') - verbose_name_plural = _('Problemas na Migração') - - -@reversion.register() -class Constraint(models.Model): - nome_tabela = models.CharField( - max_length=50, verbose_name=_('Nome da tabela')) - nome_constraint = models.CharField( - max_length=100, verbose_name=_('Nome da constraint')) - nome_model = models.CharField( - max_length=50, verbose_name=_('Nome da model')) - tipo_constraint = models.CharField( - max_length=50, verbose_name=_('Tipo da constraint')) - - class Meta: - verbose_name = _('Constraint removida') - verbose_name_plural = _('Constraints removidas') - - -@reversion.register() -class Argumento(models.Model): - constraint = models.ForeignKey(Constraint) - argumento = models.CharField( - max_length=50, verbose_name=_('Argumento')) - - class Meta: - verbose_name = _('Argumento da constraint') - verbose_name_plural = _('Argumentos da constraint') - - @reversion.register() class AppConfig(models.Model): diff --git a/sapl/legacy/management/commands/recria_constraints.py b/sapl/legacy/management/commands/recria_constraints.py deleted file mode 100644 index d1d8d606d..000000000 --- a/sapl/legacy/management/commands/recria_constraints.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.core.management.base import BaseCommand - - -class Command(BaseCommand): - - help = (u'Recria constraints do PostgreSQL excluidas durante ' - 'migração de dados') - - def handle(self, *args, **options): - pass diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 2ac75c4ef..6aa051e62 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -21,8 +21,7 @@ from pytz import timezone from unipath import Path from sapl.base.models import AppConfig as AppConf -from sapl.base.models import (Autor, ProblemaMigracao, TipoAutor, - cria_models_tipo_autor) +from sapl.base.models import Autor, TipoAutor, cria_models_tipo_autor from sapl.comissoes.models import Comissao, Composicao, Participacao from sapl.legacy.models import TipoNumeracaoProtocolo from sapl.materia.models import (AcompanhamentoMateria, Proposicao, @@ -564,14 +563,6 @@ def iter_sql_records(sql): yield record -def save_relation(obj, nome_campo='', problema='', descricao='', - eh_stub=False, critico=False): - link = ProblemaMigracao( - content_object=obj, nome_campo=nome_campo, problema=problema, - descricao=descricao, eh_stub=eh_stub, critico=critico) - link.save() - - def fill_vinculo_norma_juridica(): lista = [('A', 'Altera o(a)', 'Alterado(a) pelo(a)'), diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index d9d199276..c7589eecf 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -198,9 +198,6 @@ rules_group_geral = { ]), (base.CasaLegislativa, __listdetailchange__ + [RP_ADD]), - (base.ProblemaMigracao, []), - (base.Argumento, []), - (base.Constraint, []), (base.TipoAutor, __base__), (base.Autor, __base__), diff --git a/sapl/rules/tests/test_rules.py b/sapl/rules/tests/test_rules.py index aa97cb5e5..07302bae5 100644 --- a/sapl/rules/tests/test_rules.py +++ b/sapl/rules/tests/test_rules.py @@ -6,8 +6,7 @@ from django.contrib.contenttypes.models import ContentType from django.utils import six from django.utils.translation import ugettext_lazy as _ -from sapl.base.models import (Argumento, CasaLegislativa, Constraint, - ProblemaMigracao) +from sapl.base.models import CasaLegislativa from sapl.compilacao.models import (PerfilEstruturalTextoArticulado, TipoDispositivo, TipoDispositivoRelationship) @@ -57,41 +56,26 @@ def test_models_in_rules_patterns(model_item): # __falsos_positivos__ __fp__in__test_permission_of_models_in_rules_patterns = { map_rules.RP_ADD: [CasaLegislativa, - ProblemaMigracao, - Argumento, - Constraint, TipoDispositivo, TipoDispositivoRelationship, PerfilEstruturalTextoArticulado], - map_rules.RP_CHANGE: [ProblemaMigracao, - Argumento, - Constraint, - AcompanhamentoMateria, + map_rules.RP_CHANGE: [AcompanhamentoMateria, TipoDispositivo, TipoDispositivoRelationship, PerfilEstruturalTextoArticulado], map_rules.RP_DELETE: [CasaLegislativa, - ProblemaMigracao, - Argumento, - Constraint, TipoDispositivo, TipoDispositivoRelationship, PerfilEstruturalTextoArticulado], - map_rules.RP_LIST: [ProblemaMigracao, - Argumento, - Constraint, - AcompanhamentoMateria, + map_rules.RP_LIST: [AcompanhamentoMateria, TipoDispositivo, TipoDispositivoRelationship, PerfilEstruturalTextoArticulado], - map_rules.RP_DETAIL: [ProblemaMigracao, - Argumento, - Constraint, - AcompanhamentoMateria, + map_rules.RP_DETAIL: [AcompanhamentoMateria, TipoDispositivo, TipoDispositivoRelationship, PerfilEstruturalTextoArticulado] From 726031c9fb9191c842a0c2ef9bfae752a89ced2a Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 27 Mar 2018 14:35:07 -0300 Subject: [PATCH 120/121] Fix #1800 --- .../migrations/0018_auto_20180327_1433.py | 23 +++++++++++++++++++ sapl/sessao/models.py | 10 -------- 2 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 sapl/sessao/migrations/0018_auto_20180327_1433.py diff --git a/sapl/sessao/migrations/0018_auto_20180327_1433.py b/sapl/sessao/migrations/0018_auto_20180327_1433.py new file mode 100644 index 000000000..692debf28 --- /dev/null +++ b/sapl/sessao/migrations/0018_auto_20180327_1433.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2018-03-27 17:33 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('sessao', '0017_auto_20180316_0731'), + ] + + operations = [ + migrations.RemoveField( + model_name='registrovotacao', + name='data_hora_atualizacao', + ), + migrations.RemoveField( + model_name='registrovotacao', + name='data_hora_criacao', + ), + ] diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py index 49448eecc..90736d6e0 100644 --- a/sapl/sessao/models.py +++ b/sapl/sessao/models.py @@ -417,16 +417,6 @@ class RegistroVotacao(models.Model): observacao = models.TextField( blank=True, verbose_name=_('Observações')) - data_hora_criacao = models.DateTimeField( - blank=True, null=True, - auto_now_add=True, - verbose_name=_('Data Criação')) - - data_hora_atualizacao = models.DateTimeField( - blank=True, null=True, - auto_now=True, - verbose_name=_('Data')) - class Meta: verbose_name = _('Votação') verbose_name_plural = _('Votações') From e0ac91c8851eb4f958a1dd74e5ebfe1a421bc04d Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 27 Mar 2018 14:56:13 -0300 Subject: [PATCH 121/121] Atualiza docs SAPL (#1795) --- docs/instalacao31.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/instalacao31.rst b/docs/instalacao31.rst index e53bd6545..0b159b91d 100644 --- a/docs/instalacao31.rst +++ b/docs/instalacao31.rst @@ -74,6 +74,12 @@ Clonar o projeto do github, ou fazer um fork e depois clonar * Para apenas clonar do repositório do Interlegis:: cd /var/interlegis + + git clone -b 3.1.x --single-branch git://github.com/interlegis/sapl + + O comando acima irá clonar a última versão estável do SAPL (3.1.x) + Para clonar todo o repositório utilize o comando abaixo: + git clone git://github.com/interlegis/sapl * Para fazer um fork e depois clonar, siga as instruções em https://help.github.com/articles/fork-a-repo que basicamente são: