From 11384f4ebadd0cbc26250c7cb1896310b99714f9 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 29 May 2018 10:05:29 -0300 Subject: [PATCH 001/107] =?UTF-8?q?Exec=20migrate=20s=C3=B3=20depois=20de?= =?UTF-8?q?=20testar=20tag=20marco?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/management/commands/migracao_25_31.py | 2 -- sapl/legacy/migracao.py | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/legacy/management/commands/migracao_25_31.py b/sapl/legacy/management/commands/migracao_25_31.py index 4541425c4..e3864ad0f 100644 --- a/sapl/legacy/management/commands/migracao_25_31.py +++ b/sapl/legacy/management/commands/migracao_25_31.py @@ -1,4 +1,3 @@ -from django.core import management from django.core.management.base import BaseCommand from sapl.legacy.migracao import migrar @@ -9,5 +8,4 @@ class Command(BaseCommand): help = 'Migração de dados do SAPL 2.5 para o SAPL 3.1' def handle(self, *args, **options): - management.call_command('migrate') migrar(interativo=False) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index ffd0d2a18..c2d863b36 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -2,6 +2,7 @@ import subprocess from getpass import getpass import requests +from django.core import management from unipath import Path from sapl.legacy.migracao_dados import (REPO, TAG_MARCO, gravar_marco, info, @@ -24,6 +25,7 @@ def migrar(interativo=False): assert TAG_ZOPE in REPO.tags, adornar_msg( 'Antes de migrar ' 'é necessário fazer a exportação de documentos do zope') + management.call_command('migrate') migrar_dados(interativo=interativo) migrar_usuarios(REPO.working_dir) migrar_documentos(REPO) From e71f549d94374e1ff27c198262cdd59922c63c94 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 29 May 2018 15:28:29 -0300 Subject: [PATCH 002/107] =?UTF-8?q?Adapta=20exporta=C3=A7=C3=A3o=20do=20zo?= =?UTF-8?q?pe=20para=20DocumentosSapl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit e encoding flexível --- .../scripts/exporta_zope/exporta_zope.py | 59 +++++++++++++++---- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 20c7d21e7..424d0c7f4 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -275,35 +275,62 @@ def find_sapl(app): id, meta_type = obj['id'], obj['meta_type'] if id.startswith('cm_') and meta_type == 'Folder': cm_zzz = br(app[id]) - sapl = br(cm_zzz.get('sapl', None)) - if sapl and 'sapl_documentos' in sapl and 'acl_users' in sapl: - return sapl + return find_sapl(cm_zzz) + elif id == 'sapl' and meta_type in ['SAPL', 'Folder']: + sapl = br(app['sapl']) + return sapl -def dump_propriedades(docs, path, salvar, encoding='iso-8859-1'): +def detectar_encoding(fonte): + desc = magic.from_buffer(fonte) + for termo, enc in [('ISO-8859', 'latin1'), ('UTF-8', 'utf-8')]: + if termo in desc: + return enc + return None + + +def autodecode(fonte): + if isinstance(fonte, str): + enc = detectar_encoding(fonte) + return fonte.decode(enc) if enc else fonte + else: + return fonte + + +def dump_propriedades(docs, path, salvar): props_sapl = br(docs['props_sapl']) ids = [p['id'] for p in props_sapl['_properties']] props = {id: props_sapl[id] for id in ids} - props = {id: p.decode(encoding) if isinstance(p, str) else p - for id, p in props.items()} + props = {id: autodecode(p) for id, p in props.items()} save_as_yaml(path, 'sapl_documentos/propriedades.yaml', props, salvar) def dump_usuarios(sapl, path, salvar): users = br(br(sapl['acl_users'])['data']) - users = {k: br(v) for k, v in users['data'].items()} + users = {autodecode(k): br(v) for k, v in users['data'].items()} save_as_yaml(path, 'usuarios.yaml', users, salvar) -def _dump_sapl(data_fs_path, destino, salvar): +def _dump_sapl(data_fs_path, documentos_fs_path, destino, salvar): assert Path(data_fs_path).exists() + assert Path(documentos_fs_path).exists() + app, close_db = get_app(data_fs_path) try: sapl = find_sapl(app) - # extrai folhas XSLT - dump_folder(br(sapl['XSLT']), destino, salvar) # extrai usuários com suas senhas e perfis dump_usuarios(sapl, destino, salvar) + # garantindo que a pasta XSLT não está aqui + assert 'XSLT' not in sapl + finally: + close_db() + + app, close_db = get_app(documentos_fs_path) + try: + sapl = find_sapl(app) + # extrai folhas XSLT + if 'XSLT' in sapl: + dump_folder(br(sapl['XSLT']), destino, salvar) # extrai documentos docs = br(sapl['sapl_documentos']) @@ -355,9 +382,15 @@ def build_salvar(repo): def dump_sapl(sigla): sigla = sigla[-3:] # ignora prefixo (por ex. 'sapl_cm_') - data_fs_path = DIR_DADOS_MIGRACAO.child('datafs', - 'Data_cm_{}.fs'.format(sigla)) + data_fs_path, documentos_fs_path = [ + DIR_DADOS_MIGRACAO.child( + 'datafs', '{}_cm_{}.fs'.format(prefixo, sigla)) + for prefixo in ('Data', 'DocumentosSapl')] + assert data_fs_path.exists(), 'Origem não existe: {}'.format(data_fs_path) + if not documentos_fs_path.exists(): + documentos_fs_path = data_fs_path + nome_banco_legado = 'sapl_cm_{}'.format(sigla) destino = DIR_DADOS_MIGRACAO.child('repos', nome_banco_legado) destino.mkdir(parents=True) @@ -372,7 +405,7 @@ def dump_sapl(sigla): salvar = build_salvar(repo) try: finalizado = False - _dump_sapl(data_fs_path, destino, salvar) + _dump_sapl(data_fs_path, documentos_fs_path, destino, salvar) finalizado = True finally: # grava mundaças From 695206b8a47f143ab7608e94109f90459b01a5d3 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 30 May 2018 11:05:12 -0300 Subject: [PATCH 003/107] =?UTF-8?q?Corrige=20dump=20de=20XSLT=20na=20expor?= =?UTF-8?q?ta=C3=A7=C3=A3o=20do=20zope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 424d0c7f4..7507ffb87 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -320,8 +320,6 @@ def _dump_sapl(data_fs_path, documentos_fs_path, destino, salvar): sapl = find_sapl(app) # extrai usuários com suas senhas e perfis dump_usuarios(sapl, destino, salvar) - # garantindo que a pasta XSLT não está aqui - assert 'XSLT' not in sapl finally: close_db() From 76824dcc7a1af590bea5418304e33e7e2879ad73 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 30 May 2018 11:32:50 -0300 Subject: [PATCH 004/107] =?UTF-8?q?Retira=20restri=C3=A7=C3=A3o=20de=20num?= =?UTF-8?q?=20de=20superusers=20ao=20migrar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_usuarios.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sapl/legacy/migracao_usuarios.py b/sapl/legacy/migracao_usuarios.py index be0478c82..51b3348c8 100644 --- a/sapl/legacy/migracao_usuarios.py +++ b/sapl/legacy/migracao_usuarios.py @@ -95,16 +95,7 @@ def migrar_usuarios(dir_repo): usuario.groups.add(PERFIL_LEGADO_PARA_NOVO[perfil]) usuario.save() - # 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] - ) + # configura administradores for admin in admins: admin.is_superuser = True admin.save() From da44d3c7c9e5c105fca962fa2b6c248d7fd152ae Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 30 May 2018 14:29:00 -0300 Subject: [PATCH 005/107] =?UTF-8?q?Autodecodifica=20nomes=20de=20usu=C3=A1?= =?UTF-8?q?rios=20ao=20exportar=20zope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 7507ffb87..a29a0b83b 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -17,12 +17,12 @@ from functools import partial import git import magic import yaml -import ZODB.DB -import ZODB.FileStorage from unipath import Path -from ZODB.broken import Broken +import ZODB.DB +import ZODB.FileStorage from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE +from ZODB.broken import Broken EXTENSOES = { 'application/msword': '.doc', @@ -308,6 +308,8 @@ def dump_propriedades(docs, path, salvar): def dump_usuarios(sapl, path, salvar): users = br(br(sapl['acl_users'])['data']) users = {autodecode(k): br(v) for k, v in users['data'].items()} + for dados in users.values(): + dados['name'] = autodecode(dados['name']) save_as_yaml(path, 'usuarios.yaml', users, salvar) From 3de1e2b99d6dadf77661dffb87bf567ca5c7722c Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Sat, 2 Jun 2018 12:23:14 -0300 Subject: [PATCH 006/107] =?UTF-8?q?Pula=20pastas=20*=5Fold=20na=20exporta?= =?UTF-8?q?=C3=A7=C3=A3o=20do=20zope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 3 +++ 1 file changed, 3 insertions(+) mode change 100755 => 100644 sapl/legacy/scripts/exporta_zope/exporta_zope.py diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py old mode 100755 new mode 100644 index a29a0b83b..75c21b033 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -186,6 +186,9 @@ def dump_folder(folder, path, salvar, enum=enumerate_folder): if not os.path.exists(path): os.makedirs(path) for id, obj, meta_type in enum(folder): + # pula pastas *_old (presentes em várias bases) + if id.endswith('_old') and meta_type in ['Folder', 'BTreeFolder2']: + continue dump = DUMP_FUNCTIONS.get(meta_type, '?') if dump == '?': nao_identificados[meta_type].append(path + '/' + id) From 37720a91ce1c6e3defab104a9914994185ae36b8 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Sat, 2 Jun 2018 14:08:44 -0300 Subject: [PATCH 007/107] =?UTF-8?q?Reconhece=20arquivos=20corrompidos=20na?= =?UTF-8?q?=20exporta=C3=A7=C3=A3o=20do=20zope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scripts/exporta_zope/exporta_zope.py | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) mode change 100644 => 100755 sapl/legacy/scripts/exporta_zope/exporta_zope.py diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py old mode 100644 new mode 100755 index 75c21b033..12819f512 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -17,12 +17,13 @@ from functools import partial import git import magic import yaml -from unipath import Path - import ZODB.DB import ZODB.FileStorage -from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE +from unipath import Path from ZODB.broken import Broken +from ZODB.POSException import POSKeyError + +from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE EXTENSOES = { 'application/msword': '.doc', @@ -95,6 +96,9 @@ def guess_extension(fullname, buffer): return '.DESCONHECIDO.{}'.format(mime.replace('/', '__')) +CONTEUDO_ARQUIVO_CORROMPIDO = 'ARQUIVO CORROMPIDO' + + def get_conteudo_file(doc): # A partir daqui usamos dict.pop('...') nos __Broken_state__ # para contornar um "vazamento" de memória que ocorre @@ -105,25 +109,30 @@ def get_conteudo_file(doc): # # Essa medida descarta quase todos os dados retornados # e só funciona na primeira passagem + try: + pdata = br(doc.pop('data')) + if isinstance(pdata, str): + # Retrocedemos se pdata ja eh uma str (necessario em Images) + doc['data'] = pdata + pdata = doc - pdata = br(doc.pop('data')) - if isinstance(pdata, str): - # Retrocedemos se pdata ja eh uma str (necessario em Images) - doc['data'] = pdata - pdata = doc - - output = cStringIO.StringIO() - while pdata: - output.write(pdata.pop('data')) - pdata = br(pdata.pop('next', None)) + output = cStringIO.StringIO() + while pdata: + output.write(pdata.pop('data')) + pdata = br(pdata.pop('next', None)) - return output.getvalue() + return output.getvalue() + except POSKeyError: + return CONTEUDO_ARQUIVO_CORROMPIDO def dump_file(doc, path, salvar, get_conteudo=get_conteudo_file): name = doc['__name__'] fullname = os.path.join(path, name) conteudo = get_conteudo(doc) + if conteudo == CONTEUDO_ARQUIVO_CORROMPIDO: + fullname = fullname + '.CORROMPIDO' + print('ATENÇÃO: arquivo corrompido: {}'.format(fullname)) if conteudo: # pula arquivos vazios salvar(fullname, conteudo) From e3317eebe7e25abd0c975c6e0a5765879617e274 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 11 Jun 2018 11:15:57 -0300 Subject: [PATCH 008/107] =?UTF-8?q?Ajusta=20nome=20de=20arquivo=20corrompi?= =?UTF-8?q?do=20na=20exporta=C3=A7=C3=A3o=20do=20zope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 12819f512..f1a4b791f 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -131,7 +131,7 @@ def dump_file(doc, path, salvar, get_conteudo=get_conteudo_file): fullname = os.path.join(path, name) conteudo = get_conteudo(doc) if conteudo == CONTEUDO_ARQUIVO_CORROMPIDO: - fullname = fullname + '.CORROMPIDO' + fullname = fullname + '_CORROMPIDO' print('ATENÇÃO: arquivo corrompido: {}'.format(fullname)) if conteudo: # pula arquivos vazios From 8d16524d858427d4d02df823d5ff58c037451b88 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 11 Jun 2018 11:20:38 -0300 Subject: [PATCH 009/107] =?UTF-8?q?Adiciona=20tag=20zope=20ao=20exportar?= =?UTF-8?q?=20zope=20mesmo=20sem=20mudan=C3=A7a?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index f1a4b791f..d6af2c535 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -17,14 +17,14 @@ from functools import partial import git import magic import yaml +from unipath import Path + import ZODB.DB import ZODB.FileStorage -from unipath import Path +from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE from ZODB.broken import Broken from ZODB.POSException import POSKeyError -from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE - EXTENSOES = { 'application/msword': '.doc', 'application/pdf': '.pdf', @@ -427,8 +427,8 @@ def dump_sapl(sigla): # se de fato existe mudança status = 'completa' if finalizado else 'parcial' repo.index.commit(u'Exportação do zope {}'.format(status)) - if finalizado: - repo.git.execute('git tag -f'.split() + [TAG_ZOPE]) + if finalizado: + repo.git.execute('git tag -f'.split() + [TAG_ZOPE]) if __name__ == "__main__": From a3d5321e097642c3c288c1fc27fb478d6262c7ed Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 12 Jun 2018 13:37:37 -0300 Subject: [PATCH 010/107] Ajusta sessao_plenaria_presenca.dat_sessao antes de migrar --- sapl/legacy/migracao_dados.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 88758c8b1..87646cd07 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -626,12 +626,13 @@ def uniformiza_banco(): ''') 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 +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 +sessao_plenaria_presenca | dat_sessao = NULL | dat_sessao = 0 '''.strip().splitlines() for spec in update_specs: @@ -794,7 +795,7 @@ def roda_comando_shell(cmd): assert res == 0, 'O comando falhou: {}'.format(cmd) -def migrar_dados(interativo=True): +def migrar_dados(interativo=False): # restaura dump arq_dump = Path(DIR_DADOS_MIGRACAO.child( From f5246f1d4c594d4b522db14851b60dbfa19383b9 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 13 Jun 2018 09:16:05 -0300 Subject: [PATCH 011/107] =?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/legacy/migracao.py | 2 +- sapl/legacy/migracao_dados.py | 13 +------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index c2d863b36..746dff6f8 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -26,7 +26,7 @@ def migrar(interativo=False): 'Antes de migrar ' 'é necessário fazer a exportação de documentos do zope') management.call_command('migrate') - migrar_dados(interativo=interativo) + migrar_dados() migrar_usuarios(REPO.working_dir) migrar_documentos(REPO) gravar_marco() diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 87646cd07..fb5020437 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -795,7 +795,7 @@ def roda_comando_shell(cmd): assert res == 0, 'O comando falhou: {}'.format(cmd) -def migrar_dados(interativo=False): +def migrar_dados(): # restaura dump arq_dump = Path(DIR_DADOS_MIGRACAO.child( @@ -814,17 +814,6 @@ def migrar_dados(interativo=False): 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 destino.') call([PROJECT_DIR.child('manage.py'), 'flush', '--database=default', '--no-input'], stdout=PIPE) From 5a27d9127b19addb637070501bb8209f8c0a0c4e Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 13 Jun 2018 09:38:20 -0300 Subject: [PATCH 012/107] =?UTF-8?q?Loga=20ocorrencias=20em=20toda=20a=20mi?= =?UTF-8?q?gra=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 56 +++++++++++++++++------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index fb5020437..c6ca892f0 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -796,36 +796,36 @@ def roda_comando_shell(cmd): def migrar_dados(): - - # restaura dump - arq_dump = Path(DIR_DADOS_MIGRACAO.child( - 'dumps_mysql', '{}.sql'.format(NOME_BANCO_LEGADO))) - assert arq_dump.exists(), 'Dump do mysql faltando: {}'.format(arq_dump) - info('Restaurando dump mysql de [{}]'.format(arq_dump)) - normaliza_dump_mysql(arq_dump) - roda_comando_shell('mysql -uroot < {}'.format(arq_dump)) - - # executa ajustes pré-migração, se existirem - arq_ajustes_pre_migracao = DIR_DADOS_MIGRACAO.child( - 'ajustes_pre_migracao', '{}.sql'.format(sigla_casa)) - if arq_ajustes_pre_migracao.exists(): - exec_legado(arq_ajustes_pre_migracao.read_file()) - - uniformiza_banco() - - # excluindo database antigo. - info('Excluindo entradas antigas do banco destino.') - 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: ...') try: ocorrencias.clear() + + # restaura dump + arq_dump = Path(DIR_DADOS_MIGRACAO.child( + 'dumps_mysql', '{}.sql'.format(NOME_BANCO_LEGADO))) + assert arq_dump.exists(), 'Dump do mysql faltando: {}'.format(arq_dump) + info('Restaurando dump mysql de [{}]'.format(arq_dump)) + normaliza_dump_mysql(arq_dump) + roda_comando_shell('mysql -uroot < {}'.format(arq_dump)) + + # executa ajustes pré-migração, se existirem + arq_ajustes_pre_migracao = DIR_DADOS_MIGRACAO.child( + 'ajustes_pre_migracao', '{}.sql'.format(sigla_casa)) + if arq_ajustes_pre_migracao.exists(): + exec_legado(arq_ajustes_pre_migracao.read_file()) + + uniformiza_banco() + + # excluindo database antigo. + info('Excluindo entradas antigas do banco destino.') + 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: ...') migrar_todos_os_models() except Exception as e: ocorrencias['traceback'] = str(traceback.format_exc()) From 0a38515b60b0ea330c4980fa919215abeab39b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Sconetto?= Date: Wed, 13 Jun 2018 17:56:26 -0300 Subject: [PATCH 013/107] Fix #1999 (#2009) --- sapl/painel/views.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sapl/painel/views.py b/sapl/painel/views.py index 0cb151382..a185fed3b 100644 --- a/sapl/painel/views.py +++ b/sapl/painel/views.py @@ -315,10 +315,7 @@ def get_presentes(pk, response, materia): presentes_list = [] for p in presentes: - now_year = timezone.now().year - # Recupera a legislatura vigente - legislatura = Legislatura.objects.get(data_inicio__year__lte=now_year, - data_fim__year__gte=now_year) + legislatura = sessao.legislatura # Recupera os mandatos daquele parlamentar mandatos = p.parlamentar.mandato_set.filter(legislatura=legislatura) From c7f69e09ca341606feda30ac663c7f059931ba6f Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 13 Jun 2018 19:26:00 -0300 Subject: [PATCH 014/107] =?UTF-8?q?Pula=20diret=C3=B3rios=20corrompidos=20?= =?UTF-8?q?ao=20exportar=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index d6af2c535..7494dca17 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -146,8 +146,16 @@ def get_conteudo_dtml_method(doc): def enumerate_by_key_list(folder, key_list, type_key): for entry in folder.get(key_list, []): id, meta_type = entry['id'], entry[type_key] - obj = br(folder.get(id, None)) - yield id, obj, meta_type + try: + obj = br(folder.get(id, None)) + except POSKeyError: + print('#' * 80) + print('#' * 80) + print('ATENÇÃO: DIRETÓRIO corrompido: {}'.format(id)) + print('#' * 80) + print('#' * 80) + else: + yield id, obj, meta_type enumerate_folder = partial(enumerate_by_key_list, From f81b678bac859a5cd9625146ef4c8328ecf23db9 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 13 Jun 2018 19:27:22 -0300 Subject: [PATCH 015/107] =?UTF-8?q?Suspende=20compacta=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20media=20ao=20migrar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index 746dff6f8..9ed09360f 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -30,7 +30,7 @@ def migrar(interativo=False): migrar_usuarios(REPO.working_dir) migrar_documentos(REPO) gravar_marco() - compactar_media() + # compactar_media() def compactar_media(): From 6a3f2c77a4df9de4a09bc3c0ee7e2ed84540ca03 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 13 Jun 2018 21:33:32 -0300 Subject: [PATCH 016/107] =?UTF-8?q?Migra=20dados=20de=20reuni=C3=A3o=20de?= =?UTF-8?q?=20comiss=C3=A3o=20(do=20sapl=203.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/comissoes/legacy.yaml | 7 ++++ .../migrations/0015_auto_20180613_2023.py | 25 ++++++++++++++ .../migrations/0016_auto_20180613_2121.py | 21 ++++++++++++ sapl/comissoes/models.py | 11 ++++-- sapl/comissoes/views.py | 34 +++++++++++-------- sapl/legacy/migracao_dados.py | 22 ++++++++++-- sapl/legacy/models.py | 14 ++++++++ 7 files changed, 115 insertions(+), 19 deletions(-) create mode 100644 sapl/comissoes/migrations/0015_auto_20180613_2023.py create mode 100644 sapl/comissoes/migrations/0016_auto_20180613_2121.py diff --git a/sapl/comissoes/legacy.yaml b/sapl/comissoes/legacy.yaml index 66ed8b060..8e1040510 100644 --- a/sapl/comissoes/legacy.yaml +++ b/sapl/comissoes/legacy.yaml @@ -42,3 +42,10 @@ Participacao (ComposicaoComissao): observacao: obs_composicao parlamentar: cod_parlamentar titular: ind_titular + +Reuniao (ReuniaoComissao): + comissao: cod_comissao + numero: num_reuniao + data: dat_inicio_reuniao + observacao: txt_observacao + diff --git a/sapl/comissoes/migrations/0015_auto_20180613_2023.py b/sapl/comissoes/migrations/0015_auto_20180613_2023.py new file mode 100644 index 000000000..b6602cfc3 --- /dev/null +++ b/sapl/comissoes/migrations/0015_auto_20180613_2023.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-06-13 23:23 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0014_auto_20180503_1055'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='hora_fim', + field=models.TimeField(null=True, verbose_name='Horário de Término (hh:mm)'), + ), + migrations.AlterField( + model_name='reuniao', + name='hora_inicio', + field=models.TimeField(null=True, verbose_name='Horário de Início (hh:mm)'), + ), + ] diff --git a/sapl/comissoes/migrations/0016_auto_20180613_2121.py b/sapl/comissoes/migrations/0016_auto_20180613_2121.py new file mode 100644 index 000000000..77c1894f8 --- /dev/null +++ b/sapl/comissoes/migrations/0016_auto_20180613_2121.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-06-14 00:21 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0015_auto_20180613_2023'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='periodo', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='comissoes.Periodo', verbose_name='Periodo da Composicão da Comissão'), + ), + ] diff --git a/sapl/comissoes/models.py b/sapl/comissoes/models.py index 0c3240fc6..a2477ef1d 100644 --- a/sapl/comissoes/models.py +++ b/sapl/comissoes/models.py @@ -184,13 +184,16 @@ 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) + 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) @@ -198,6 +201,7 @@ def anexo_upload_path(instance, filename): class Reuniao(models.Model): periodo = models. ForeignKey( Periodo, + null=True, on_delete=models.PROTECT, verbose_name=_('Periodo da Composicão da Comissão')) comissao = models.ForeignKey( @@ -211,8 +215,10 @@ class Reuniao(models.Model): max_length=150, blank=True, verbose_name=_('Tema da Reunião')) data = models.DateField(verbose_name=_('Data')) hora_inicio = models.TimeField( + null=True, verbose_name=_('Horário de Início (hh:mm)')) hora_fim = models.TimeField( + null=True, verbose_name=_('Horário de Término (hh:mm)')) local_reuniao = models.CharField( max_length=100, blank=True, verbose_name=_('Local da Reunião')) @@ -287,12 +293,13 @@ class Reuniao(models.Model): @reversion.register() class DocumentoAcessorio(models.Model): - reuniao = models.ForeignKey(Reuniao, + 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')) + 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')) diff --git a/sapl/comissoes/views.py b/sapl/comissoes/views.py index c5870389e..78e639168 100644 --- a/sapl/comissoes/views.py +++ b/sapl/comissoes/views.py @@ -8,20 +8,20 @@ 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 (ComissaoForm, ComposicaoForm, DocumentoAcessorioCreateForm, - DocumentoAcessorioEditForm, ParticipacaoCreateForm, - ParticipacaoEditForm, ReuniaoForm, PeriodoForm) +from sapl.comissoes.apps import AppConfig +from sapl.comissoes.forms import (ComissaoForm, ComposicaoForm, + DocumentoAcessorioCreateForm, + DocumentoAcessorioEditForm, + ParticipacaoCreateForm, ParticipacaoEditForm, + PeriodoForm, ReuniaoForm) +from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, + MasterDetailCrud, + PermissionRequiredForAppCrudMixin) from sapl.materia.models import MateriaLegislativa, Tramitacao - from .models import (CargoComissao, Comissao, Composicao, DocumentoAcessorio, - Participacao, Periodo, TipoComissao, Reuniao) -from sapl.comissoes.apps import AppConfig + Participacao, Periodo, Reuniao, TipoComissao) def pegar_url_composicao(pk): @@ -30,6 +30,7 @@ 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 @@ -42,6 +43,7 @@ TipoComissaoCrud = CrudAux.build( TipoComissao, 'tipo_comissao', list_field_names=[ 'sigla', 'nome', 'natureza', 'dispositivo_regimental']) + class PeriodoComposicaoCrud(CrudAux): model = Periodo @@ -77,6 +79,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 @@ -93,12 +96,11 @@ class ComposicaoCrud(MasterDetailCrud): class CreateView(MasterDetailCrud.CreateView): form_class = ComposicaoForm - + def get_initial(self): comissao = Comissao.objects.get(id=self.kwargs['pk']) return {'comissao': comissao} - class ListView(MasterDetailCrud.ListView): template_name = "comissoes/composicao_list.html" paginate_by = None @@ -180,6 +182,7 @@ class MateriasTramitacaoListView(ListView): context['object'] = Comissao.objects.get(id=self.kwargs['pk']) return context + class ReuniaoCrud(MasterDetailCrud): model = Reuniao parent_field = 'comissao' @@ -187,7 +190,7 @@ class ReuniaoCrud(MasterDetailCrud): public = [RP_LIST, RP_DETAIL, ] class BaseMixin(MasterDetailCrud.BaseMixin): - list_field_names = [ 'nome', 'tema', 'data'] + list_field_names = ['data', 'nome', 'tema'] class ListView(MasterDetailCrud.ListView): paginate_by = 10 @@ -228,9 +231,9 @@ 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 DocumentoAcessorioCrud(MasterDetailCrud): @@ -256,6 +259,7 @@ class DocumentoAcessorioCrud(MasterDetailCrud): form_class = DocumentoAcessorioEditForm class DeleteView(MasterDetailCrud.DeleteView): + def delete(self, *args, **kwargs): obj = self.get_object() obj.delete() diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index c6ca892f0..96bb0905f 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -29,7 +29,7 @@ from unipath import Path from sapl.base.models import AppConfig as AppConf from sapl.base.models import Autor, TipoAutor, cria_models_tipo_autor -from sapl.comissoes.models import Comissao, Composicao, Participacao +from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao from sapl.legacy import scripts from sapl.legacy.models import NormaJuridica as OldNormaJuridica from sapl.legacy.models import TipoNumeracaoProtocolo @@ -58,6 +58,8 @@ from .timezonesbrasil import get_timezone appconfs = [apps.get_app_config(n) for n in [ 'parlamentares', 'comissoes', + # base precisa vir depois dos apps parlamentares e comissoes + # pois Autor os referencia 'base', 'materia', 'norma', @@ -99,7 +101,7 @@ def get_renames(): model_name, old_name = match.groups() else: old_name = None - model = getattr(app.models_module, model_name) + model = app.get_model(model_name) if old_name: model_renames[model] = old_name field_renames[model] = renames @@ -212,6 +214,10 @@ class ForeignKeyFaltando(ObjectDoesNotExist): 'Uma FK aponta para um registro inexistente' def __init__(self, field, valor, old): + if (field.related_model.__name__ == 'Comissao' + and old.__class__.__name__ == 'ReuniaoComissao' + and valor == 1): + __import__('pdb').set_trace() self.field = field self.valor = valor self.old = old @@ -1237,6 +1243,17 @@ def adjust_tiporesultadovotacao(new, old): {'pk': new.pk, 'nome': new.nome}) +def str_to_time(fonte): + if not fonte.strip(): + return None + tempo = datetime.datetime.strptime(fonte, '%H:%M') + return tempo.time() if tempo else None + + +def adjust_reuniao_comissao(new, old): + new.hora_inicio = str_to_time(old.hr_inicio_reuniao) + + def remove_style(conteudo): if 'style' not in conteudo: return conteudo # atalho que acelera muito os casos sem style @@ -1274,6 +1291,7 @@ AJUSTE_ANTES_SALVAR = { Tramitacao: adjust_tramitacao, TipoResultadoVotacao: adjust_tiporesultadovotacao, ExpedienteSessao: adjust_expediente_sessao, + Reuniao: adjust_reuniao_comissao, } AJUSTE_DEPOIS_SALVAR = { diff --git a/sapl/legacy/models.py b/sapl/legacy/models.py index 7d341624d..cd6d433df 100644 --- a/sapl/legacy/models.py +++ b/sapl/legacy/models.py @@ -779,6 +779,20 @@ class Relatoria(models.Model): db_table = 'relatoria' +class ReuniaoComissao(models.Model): + cod_reuniao = models.AutoField(primary_key=True) + cod_comissao = models.IntegerField() + num_reuniao = models.IntegerField() + dat_inicio_reuniao = models.DateField() + hr_inicio_reuniao = models.CharField(max_length=5, blank=True, null=True) + txt_observacao = models.TextField(blank=True, null=True) + ind_excluido = models.IntegerField() + + class Meta: + managed = False + db_table = 'reuniao_comissao' + + class SessaoLegislativa(models.Model): cod_sessao_leg = models.AutoField(primary_key=True) num_legislatura = models.IntegerField() From e9f38dd062232c5ddc876ff806f8249e83b5b678 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 14 Jun 2018 10:58:55 -0300 Subject: [PATCH 017/107] Corrige mapeamento dos campos legados de models abstratos --- sapl/legacy/migracao_dados.py | 22 +++++++++------------- sapl/sessao/legacy.yaml | 12 ++++++------ 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 96bb0905f..24ee536e0 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -87,15 +87,24 @@ for a1, s1 in name_sets: # RENAMES ################################################################### MODEL_RENAME_PATTERN = re.compile('(.+) \((.+)\)') +MODEL_RENAME_INCLUDE_PATTERN = re.compile('<(.+)>') def get_renames(): field_renames = {} model_renames = {} + includes = {} 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(): + # armazena ou substitui includes + if MODEL_RENAME_INCLUDE_PATTERN.match(model_name): + includes[model_name] = renames + continue + elif isinstance(renames, str): + renames = includes[renames] + # detecta mudança de nome match = MODEL_RENAME_PATTERN.match(model_name) if match: model_name, old_name = match.groups() @@ -106,19 +115,6 @@ def get_renames(): 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 diff --git a/sapl/sessao/legacy.yaml b/sapl/sessao/legacy.yaml index e7b55095a..6df4dd90d 100644 --- a/sapl/sessao/legacy.yaml +++ b/sapl/sessao/legacy.yaml @@ -15,7 +15,7 @@ SessaoPlenaria: url_audio: url_audio url_video: url_video -AbstractOrdemDia: +: data_ordem: dat_ordem materia: cod_materia numero_ordem: num_ordem @@ -24,7 +24,7 @@ AbstractOrdemDia: sessao_plenaria: cod_sessao_plen tipo_votacao: tip_votacao -ExpedienteMateria: {} +ExpedienteMateria: TipoExpediente: nome: nom_expediente @@ -39,17 +39,17 @@ IntegranteMesa (MesaSessaoPlenaria): parlamentar: cod_parlamentar sessao_plenaria: cod_sessao_plen -AbstractOrador: +: numero_ordem: num_ordem parlamentar: cod_parlamentar sessao_plenaria: cod_sessao_plen url_discurso: url_discurso -Orador (Oradores): {} +Orador (Oradores): -OradorExpediente (OradoresExpediente): {} +OradorExpediente (OradoresExpediente): -OrdemDia: {} +OrdemDia: PresencaOrdemDia (OrdemDiaPresenca): parlamentar: cod_parlamentar From 392dd92df6b2966b476d1c365036c228bcee62f4 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 14 Jun 2018 11:05:46 -0300 Subject: [PATCH 018/107] =?UTF-8?q?Congela=20ocorr=C3=AAncias=20ao=20final?= =?UTF-8?q?=20da=20migra=C3=A7=C3=A3o=20de=20dados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 24ee536e0..da0ca270a 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -800,6 +800,7 @@ def roda_comando_shell(cmd): def migrar_dados(): try: ocorrencias.clear() + ocorrencias.default_factory = list # restaura dump arq_dump = Path(DIR_DADOS_MIGRACAO.child( @@ -833,7 +834,8 @@ def migrar_dados(): ocorrencias['traceback'] = str(traceback.format_exc()) raise e finally: - # grava ocorrências + # congela e grava ocorrências + ocorrencias.default_factory = None arq_ocorrencias = Path(REPO.working_dir, 'ocorrencias.yaml') with open(arq_ocorrencias, 'w') as arq: pyaml.dump(ocorrencias, arq, vspacing=1) From 6b9d6d11da17537f58015ebf576902f9e8d9fb53 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 14 Jun 2018 14:33:31 -0300 Subject: [PATCH 019/107] =?UTF-8?q?Vincula=20docs=20de=20reuni=C3=B5es=20a?= =?UTF-8?q?os=20dados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_documentos.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index 2bb17c53e..a759e3667 100644 --- a/sapl/legacy/migracao_documentos.py +++ b/sapl/legacy/migracao_documentos.py @@ -8,6 +8,7 @@ from django.db import transaction from image_cropping.fields import ImageCropField from sapl.base.models import CasaLegislativa +from sapl.comissoes.models import Reuniao from sapl.legacy.migracao_dados import exec_legado from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa, Proposicao) @@ -26,6 +27,8 @@ DOCS = { MateriaLegislativa: [('texto_original', 'materia/{}_texto_integral')], DocumentoAcessorio: [('arquivo', 'materia/{}')], NormaJuridica: [('texto_integral', 'norma_juridica/{}_texto_integral')], + Reuniao: [('upload_pauta', 'reuniao_comissao/{}_pauta'), + ('upload_ata', 'reuniao_comissao/{}_ata')], SessaoPlenaria: [('upload_pauta', 'pauta_sessao/{}_pauta_sessao'), ('upload_ata', 'ata_sessao/{}_ata_sessao'), ('upload_anexo', 'anexo_sessao/{}_texto_anexado')], @@ -40,9 +43,12 @@ DOCS = {model: [(campo, join('sapl_documentos', origem)) for model, campos in DOCS.items()} -def mover_documento(repo, origem, destino): +def mover_documento(repo, origem, destino, ignora_origem_ausente=False): origem, destino = [join(repo.working_dir, c) if not os.path.isabs(c) else c for c in (origem, destino)] + if ignora_origem_ausente and not os.path.exists(origem): + print('Origem ignorada ao mover documento: {}'.format(origem)) + return os.makedirs(os.path.dirname(destino), exist_ok=True) repo.git.mv(origem, destino) @@ -52,7 +58,8 @@ def migrar_logotipo(repo, casa, propriedades): [(campo, origem)] = DOCS[CasaLegislativa] # a extensão do logo pode ter sido ajustada pelo tipo real do arquivo nome_nas_propriedades = os.path.splitext(propriedades['id_logo'])[0] - arquivos = glob(join(repo.working_dir, origem.format(nome_nas_propriedades))) + arquivos = glob( + join(repo.working_dir, origem.format(nome_nas_propriedades))) if arquivos: assert len(arquivos) == 1, 'Há mais de um logotipo para a casa' [logo] = arquivos @@ -145,7 +152,8 @@ def migrar_documentos(repo): # Isto significa que para rodar novamente esta função é preciso # restaurar o repo ao estado anterior - mover_documento(repo, 'XSLT', 'sapl/public/XSLT') + mover_documento(repo, 'XSLT', 'sapl/public/XSLT', + ignora_origem_ausente=True) migrar_propriedades_da_casa(repo) From c610220003aabb28c50a478dfb60017bce534311 Mon Sep 17 00:00:00 2001 From: cristian-longhi Date: Thu, 14 Jun 2018 16:45:16 -0300 Subject: [PATCH 020/107] =?UTF-8?q?Exibe=20assunto=20e=20interessado=20se?= =?UTF-8?q?=20o=20comprovante=20=C3=A9=20de=20protocolo=20admnistrativo=20?= =?UTF-8?q?(#2016)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/templates/protocoloadm/comprovante.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sapl/templates/protocoloadm/comprovante.html b/sapl/templates/protocoloadm/comprovante.html index 1de22d402..e4258c263 100644 --- a/sapl/templates/protocoloadm/comprovante.html +++ b/sapl/templates/protocoloadm/comprovante.html @@ -70,6 +70,15 @@ Autor {{ protocolo.autor }} + {% else %} + + Assunto + {{ protocolo.assunto_ementa }} + + + Interessado + {{ protocolo.interessado }} + {% endif %} Natureza From 13cc50fd4988f63c10986ac3bbd70138d6e0ddc6 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Thu, 14 Jun 2018 16:45:43 -0300 Subject: [PATCH 021/107] Fix #2001 (#2015) --- sapl/templates/painel/index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/templates/painel/index.html b/sapl/templates/painel/index.html index 3ba84b141..6e4242df4 100644 --- a/sapl/templates/painel/index.html +++ b/sapl/templates/painel/index.html @@ -121,6 +121,8 @@

+ + From 55e37aec70ab8ae91ec3c0325bc715d1b1ee992f Mon Sep 17 00:00:00 2001 From: Edward Date: Thu, 14 Jun 2018 17:11:46 -0300 Subject: [PATCH 022/107] 2018 mudanca titulo lote (#2019) * Fix #2014 * Fixes #2018 --- sapl/materia/forms.py | 67 ++++++++++++++++++- sapl/materia/urls.py | 5 +- sapl/materia/views.py | 23 ++++++- .../materia/em_lote/excluir_tramitacao.html | 7 ++ .../templates/materia/em_lote/tramitacao.html | 2 +- sapl/templates/navbar.yaml | 3 + 6 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 sapl/templates/materia/em_lote/excluir_tramitacao.html diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index d14fad28c..20518cfdd 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -32,7 +32,8 @@ from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, to_row) from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto, MateriaLegislativa, Orgao, RegimeTramitacao, - TipoDocumento, TipoProposicao) + TipoDocumento, TipoProposicao, StatusTramitacao, + UnidadeTramitacao) from sapl.norma.models import (LegislacaoCitada, NormaJuridica, TipoNormaJuridica) from sapl.parlamentares.models import Legislatura @@ -2032,3 +2033,67 @@ class FichaSelecionaForm(forms.Form): form_actions(label='Gerar Impresso') ) ) + + +class ExcluirTramitacaoEmLote(forms.Form): + + data_tramitacao = forms.DateField(required=True, + label=_('Data da Tramitação')) + + unidade_tramitacao_local = forms.ModelChoiceField(label=_('Unidade Local'), + required=True, + queryset=UnidadeTramitacao.objects.all(), + empty_label='------') + + unidade_tramitacao_destino = forms.ModelChoiceField(label=_('Unidade Destino'), + required=True, + queryset=UnidadeTramitacao.objects.all(), + empty_label='------') + + status = forms.ModelChoiceField(label=_('Status'), + required=True, + queryset=StatusTramitacao.objects.all(), + empty_label='------') + + def clean(self): + super(ExcluirTramitacaoEmLote, self).clean() + + cleaned_data = self.cleaned_data + + if not self.is_valid(): + return cleaned_data + + data_tramitacao = cleaned_data['data_tramitacao'] + unidade_tramitacao_local = cleaned_data['unidade_tramitacao_local'] + unidade_tramitacao_destino = cleaned_data['unidade_tramitacao_destino'] + status = cleaned_data['status'] + + tramitacao_set = Tramitacao.objects.filter(data_tramitacao=data_tramitacao, + unidade_tramitacao_local=unidade_tramitacao_local, + unidade_tramitacao_destino=unidade_tramitacao_destino, + status=status) + if not tramitacao_set.exists(): + raise forms.ValidationError( + _("Não existem tramitações com os dados informados.")) + + return cleaned_data + + def __init__(self, *args, **kwargs): + super(ExcluirTramitacaoEmLote, self).__init__(*args, **kwargs) + + row1 = to_row( + [('data_tramitacao', 6), + ('status', 6),]) + row2 = to_row( + [('unidade_tramitacao_local', 6), + ('unidade_tramitacao_destino', 6)]) + + self.helper = FormHelper() + self.helper.layout = Layout( + Fieldset(_('Dados das Tramitações'), + row1, + row2, + HTML(" "), + form_actions(label='Excluir') + ) + ) diff --git a/sapl/materia/urls.py b/sapl/materia/urls.py index 934c4dbac..f2c89c908 100644 --- a/sapl/materia/urls.py +++ b/sapl/materia/urls.py @@ -23,7 +23,8 @@ from sapl.materia.views import (AcompanhamentoConfirmarView, TipoFimRelatoriaCrud, TipoMateriaCrud, TipoProposicaoCrud, TramitacaoCrud, TramitacaoEmLoteView, UnidadeTramitacaoCrud, - proposicao_texto, recuperar_materia) + proposicao_texto, recuperar_materia, + ExcluirTramitacaoEmLoteView) from sapl.norma.views import NormaPesquisaSimplesView from .apps import AppConfig @@ -90,6 +91,8 @@ urlpatterns_materia = [ name='primeira_tramitacao_em_lote'), url(r'^materia/tramitacao-em-lote', TramitacaoEmLoteView.as_view(), name='tramitacao_em_lote'), + url(r'^materia/excluir-tramitacao-em-lote', ExcluirTramitacaoEmLoteView.as_view(), + name='excluir_tramitacao_em_lote'), ] diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 807db3d9c..0a8b466c4 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -57,7 +57,8 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, TramitacaoEmLoteFilterSet, UnidadeTramitacaoForm, filtra_tramitacao_destino, filtra_tramitacao_destino_and_status, - filtra_tramitacao_status) + filtra_tramitacao_status, + ExcluirTramitacaoEmLote) from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, DespachoInicial, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao, @@ -1972,3 +1973,23 @@ class FichaSelecionaView(PermissionRequiredMixin, FormView): return gerar_pdf_impressos(self.request, context, 'materia/impressos/ficha_pdf.html') + + +class ExcluirTramitacaoEmLoteView(PermissionRequiredMixin, FormView): + + template_name = 'materia/em_lote/excluir_tramitacao.html' + permission_required = ('materia.add_tramitacao',) + form_class = ExcluirTramitacaoEmLote + form_valid_message = _('Tramitações excluídas com sucesso!') + + def get_success_url(self): + return reverse('sapl.materia:excluir_tramitacao_em_lote') + + def form_valid(self, form): + + tramitacao_set = Tramitacao.objects.filter(data_tramitacao=form.cleaned_data['data_tramitacao'], + unidade_tramitacao_local=form.cleaned_data['unidade_tramitacao_local'], + unidade_tramitacao_destino=form.cleaned_data['unidade_tramitacao_destino'], + status=form.cleaned_data['status']) + tramitacao_set.delete() + return redirect(self.get_success_url()) \ No newline at end of file diff --git a/sapl/templates/materia/em_lote/excluir_tramitacao.html b/sapl/templates/materia/em_lote/excluir_tramitacao.html new file mode 100644 index 000000000..b74faa593 --- /dev/null +++ b/sapl/templates/materia/em_lote/excluir_tramitacao.html @@ -0,0 +1,7 @@ +{% extends "crud/detail.html" %} +{% load i18n crispy_forms_tags %} + +{% block actions %}{% endblock %} +{% block detail_content %} + {% crispy form %} +{% endblock detail_content %} \ No newline at end of file diff --git a/sapl/templates/materia/em_lote/tramitacao.html b/sapl/templates/materia/em_lote/tramitacao.html index 08483d88d..9ed94c84d 100644 --- a/sapl/templates/materia/em_lote/tramitacao.html +++ b/sapl/templates/materia/em_lote/tramitacao.html @@ -91,7 +91,7 @@


- 2. Selecione as matérias para primeira tramitação: + 2. Selecione as matérias para tramitação:

diff --git a/sapl/templates/navbar.yaml b/sapl/templates/navbar.yaml index c997e2e41..b80cb7acd 100644 --- a/sapl/templates/navbar.yaml +++ b/sapl/templates/navbar.yaml @@ -54,6 +54,9 @@ - title: {% trans 'Tramitação em Lote' %} url: sapl.materia:primeira_tramitacao_em_lote check_permission: materia.list_tramitacao {% comment %} FIXME transformar para checagens de menu_[funcionalidade]{% endcomment%} + - title: {% trans 'Excluir Tramitação em Lote' %} + url: sapl.materia:excluir_tramitacao_em_lote + check_permission: materia.list_tramitacao {% comment %} FIXME transformar para checagens de menu_[funcionalidade]{% endcomment%} - title: {% trans 'Normas Jurídicas' %} children: From 8c72d253a0aeca79b29c8ff8945bea6d3b72b875 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 14 Jun 2018 17:12:41 -0300 Subject: [PATCH 023/107] Revert "2018 mudanca titulo lote (#2019)" This reverts commit 55e37aec70ab8ae91ec3c0325bc715d1b1ee992f. --- sapl/materia/forms.py | 67 +------------------ sapl/materia/urls.py | 5 +- sapl/materia/views.py | 23 +------ .../materia/em_lote/excluir_tramitacao.html | 7 -- .../templates/materia/em_lote/tramitacao.html | 2 +- sapl/templates/navbar.yaml | 3 - 6 files changed, 4 insertions(+), 103 deletions(-) delete mode 100644 sapl/templates/materia/em_lote/excluir_tramitacao.html diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 20518cfdd..d14fad28c 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -32,8 +32,7 @@ from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, to_row) from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto, MateriaLegislativa, Orgao, RegimeTramitacao, - TipoDocumento, TipoProposicao, StatusTramitacao, - UnidadeTramitacao) + TipoDocumento, TipoProposicao) from sapl.norma.models import (LegislacaoCitada, NormaJuridica, TipoNormaJuridica) from sapl.parlamentares.models import Legislatura @@ -2033,67 +2032,3 @@ class FichaSelecionaForm(forms.Form): form_actions(label='Gerar Impresso') ) ) - - -class ExcluirTramitacaoEmLote(forms.Form): - - data_tramitacao = forms.DateField(required=True, - label=_('Data da Tramitação')) - - unidade_tramitacao_local = forms.ModelChoiceField(label=_('Unidade Local'), - required=True, - queryset=UnidadeTramitacao.objects.all(), - empty_label='------') - - unidade_tramitacao_destino = forms.ModelChoiceField(label=_('Unidade Destino'), - required=True, - queryset=UnidadeTramitacao.objects.all(), - empty_label='------') - - status = forms.ModelChoiceField(label=_('Status'), - required=True, - queryset=StatusTramitacao.objects.all(), - empty_label='------') - - def clean(self): - super(ExcluirTramitacaoEmLote, self).clean() - - cleaned_data = self.cleaned_data - - if not self.is_valid(): - return cleaned_data - - data_tramitacao = cleaned_data['data_tramitacao'] - unidade_tramitacao_local = cleaned_data['unidade_tramitacao_local'] - unidade_tramitacao_destino = cleaned_data['unidade_tramitacao_destino'] - status = cleaned_data['status'] - - tramitacao_set = Tramitacao.objects.filter(data_tramitacao=data_tramitacao, - unidade_tramitacao_local=unidade_tramitacao_local, - unidade_tramitacao_destino=unidade_tramitacao_destino, - status=status) - if not tramitacao_set.exists(): - raise forms.ValidationError( - _("Não existem tramitações com os dados informados.")) - - return cleaned_data - - def __init__(self, *args, **kwargs): - super(ExcluirTramitacaoEmLote, self).__init__(*args, **kwargs) - - row1 = to_row( - [('data_tramitacao', 6), - ('status', 6),]) - row2 = to_row( - [('unidade_tramitacao_local', 6), - ('unidade_tramitacao_destino', 6)]) - - self.helper = FormHelper() - self.helper.layout = Layout( - Fieldset(_('Dados das Tramitações'), - row1, - row2, - HTML(" "), - form_actions(label='Excluir') - ) - ) diff --git a/sapl/materia/urls.py b/sapl/materia/urls.py index f2c89c908..934c4dbac 100644 --- a/sapl/materia/urls.py +++ b/sapl/materia/urls.py @@ -23,8 +23,7 @@ from sapl.materia.views import (AcompanhamentoConfirmarView, TipoFimRelatoriaCrud, TipoMateriaCrud, TipoProposicaoCrud, TramitacaoCrud, TramitacaoEmLoteView, UnidadeTramitacaoCrud, - proposicao_texto, recuperar_materia, - ExcluirTramitacaoEmLoteView) + proposicao_texto, recuperar_materia) from sapl.norma.views import NormaPesquisaSimplesView from .apps import AppConfig @@ -91,8 +90,6 @@ urlpatterns_materia = [ name='primeira_tramitacao_em_lote'), url(r'^materia/tramitacao-em-lote', TramitacaoEmLoteView.as_view(), name='tramitacao_em_lote'), - url(r'^materia/excluir-tramitacao-em-lote', ExcluirTramitacaoEmLoteView.as_view(), - name='excluir_tramitacao_em_lote'), ] diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 0a8b466c4..807db3d9c 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -57,8 +57,7 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, TramitacaoEmLoteFilterSet, UnidadeTramitacaoForm, filtra_tramitacao_destino, filtra_tramitacao_destino_and_status, - filtra_tramitacao_status, - ExcluirTramitacaoEmLote) + filtra_tramitacao_status) from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, DespachoInicial, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao, @@ -1973,23 +1972,3 @@ class FichaSelecionaView(PermissionRequiredMixin, FormView): return gerar_pdf_impressos(self.request, context, 'materia/impressos/ficha_pdf.html') - - -class ExcluirTramitacaoEmLoteView(PermissionRequiredMixin, FormView): - - template_name = 'materia/em_lote/excluir_tramitacao.html' - permission_required = ('materia.add_tramitacao',) - form_class = ExcluirTramitacaoEmLote - form_valid_message = _('Tramitações excluídas com sucesso!') - - def get_success_url(self): - return reverse('sapl.materia:excluir_tramitacao_em_lote') - - def form_valid(self, form): - - tramitacao_set = Tramitacao.objects.filter(data_tramitacao=form.cleaned_data['data_tramitacao'], - unidade_tramitacao_local=form.cleaned_data['unidade_tramitacao_local'], - unidade_tramitacao_destino=form.cleaned_data['unidade_tramitacao_destino'], - status=form.cleaned_data['status']) - tramitacao_set.delete() - return redirect(self.get_success_url()) \ No newline at end of file diff --git a/sapl/templates/materia/em_lote/excluir_tramitacao.html b/sapl/templates/materia/em_lote/excluir_tramitacao.html deleted file mode 100644 index b74faa593..000000000 --- a/sapl/templates/materia/em_lote/excluir_tramitacao.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "crud/detail.html" %} -{% load i18n crispy_forms_tags %} - -{% block actions %}{% endblock %} -{% block detail_content %} - {% crispy form %} -{% endblock detail_content %} \ No newline at end of file diff --git a/sapl/templates/materia/em_lote/tramitacao.html b/sapl/templates/materia/em_lote/tramitacao.html index 9ed94c84d..08483d88d 100644 --- a/sapl/templates/materia/em_lote/tramitacao.html +++ b/sapl/templates/materia/em_lote/tramitacao.html @@ -91,7 +91,7 @@


- 2. Selecione as matérias para tramitação: + 2. Selecione as matérias para primeira tramitação:
diff --git a/sapl/templates/navbar.yaml b/sapl/templates/navbar.yaml index b80cb7acd..c997e2e41 100644 --- a/sapl/templates/navbar.yaml +++ b/sapl/templates/navbar.yaml @@ -54,9 +54,6 @@ - title: {% trans 'Tramitação em Lote' %} url: sapl.materia:primeira_tramitacao_em_lote check_permission: materia.list_tramitacao {% comment %} FIXME transformar para checagens de menu_[funcionalidade]{% endcomment%} - - title: {% trans 'Excluir Tramitação em Lote' %} - url: sapl.materia:excluir_tramitacao_em_lote - check_permission: materia.list_tramitacao {% comment %} FIXME transformar para checagens de menu_[funcionalidade]{% endcomment%} - title: {% trans 'Normas Jurídicas' %} children: From ea48e6956654030d6a2cc3fac4fbce768f3ad078 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 14 Jun 2018 17:13:40 -0300 Subject: [PATCH 024/107] HOT-FIX: Fixes #2018 --- sapl/templates/materia/em_lote/tramitacao.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/templates/materia/em_lote/tramitacao.html b/sapl/templates/materia/em_lote/tramitacao.html index 08483d88d..9ed94c84d 100644 --- a/sapl/templates/materia/em_lote/tramitacao.html +++ b/sapl/templates/materia/em_lote/tramitacao.html @@ -91,7 +91,7 @@


- 2. Selecione as matérias para primeira tramitação: + 2. Selecione as matérias para tramitação:
From f257c13dd145699b9477f14ffd43d59b36234dfb Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 14 Jun 2018 20:33:31 -0300 Subject: [PATCH 025/107] =?UTF-8?q?Corrige=20busca=20do=20sapl=20dentro=20?= =?UTF-8?q?do=20Data.fs=20na=20exporta=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 7494dca17..270c90583 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -17,14 +17,14 @@ from functools import partial import git import magic import yaml -from unipath import Path - import ZODB.DB import ZODB.FileStorage -from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE +from unipath import Path from ZODB.broken import Broken from ZODB.POSException import POSKeyError +from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE + EXTENSOES = { 'application/msword': '.doc', 'application/pdf': '.pdf', @@ -291,8 +291,10 @@ def get_app(data_fs_path): def find_sapl(app): - for obj in app['_objects']: - id, meta_type = obj['id'], obj['meta_type'] + ids_meta_types = [(obj['id'], obj['meta_type']) for obj in app['_objects']] + # estar ordenado é muito importante para que a busca dê prioridade + # a um id "cm_zzz" antes do id "sapl" + for id, meta_type in sorted(ids_meta_types): if id.startswith('cm_') and meta_type == 'Folder': cm_zzz = br(app[id]) return find_sapl(cm_zzz) From bec2532f9029fb8d32169bc613d681a4a7449238 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 14 Jun 2018 20:34:41 -0300 Subject: [PATCH 026/107] =?UTF-8?q?Migra=20reuni=C3=B5es=20apenas=20quando?= =?UTF-8?q?=20existirem=20no=20legado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Só acontece em bases de sapl 3.0 --- sapl/legacy/migracao_dados.py | 4 ++++ sapl/legacy/migracao_documentos.py | 26 ++++++++++---------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index da0ca270a..41c7b9934 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -857,6 +857,10 @@ def move_para_depois_de(lista, movido, referencias): def get_models_a_migrar(): models = [model for app in appconfs for model in app.models.values() if model in field_renames] + # retira reuniões quando não existe na base legada + # (só existe no sapl 3.0) + if 'reuniao_comissao' not in list(exec_legado('show tables')): + models.remove(Reuniao) # Devido à referência TipoProposicao.tipo_conteudo_related # a migração de TipoProposicao precisa ser feita # após TipoMateriaLegislativa e TipoDocumento diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index a759e3667..fd692aa47 100644 --- a/sapl/legacy/migracao_documentos.py +++ b/sapl/legacy/migracao_documentos.py @@ -22,13 +22,10 @@ from sapl.sessao.models import SessaoPlenaria DOCS = { - CasaLegislativa: [('logotipo', 'props_sapl/{}.*')], Parlamentar: [('fotografia', 'parlamentar/fotos/{}_foto_parlamentar')], MateriaLegislativa: [('texto_original', 'materia/{}_texto_integral')], DocumentoAcessorio: [('arquivo', 'materia/{}')], NormaJuridica: [('texto_integral', 'norma_juridica/{}_texto_integral')], - Reuniao: [('upload_pauta', 'reuniao_comissao/{}_pauta'), - ('upload_ata', 'reuniao_comissao/{}_ata')], SessaoPlenaria: [('upload_pauta', 'pauta_sessao/{}_pauta_sessao'), ('upload_ata', 'ata_sessao/{}_ata_sessao'), ('upload_anexo', 'anexo_sessao/{}_texto_anexado')], @@ -38,8 +35,14 @@ DOCS = { DocumentoAcessorioAdministrativo: [('arquivo', 'administrativo/{}')], } +# acrescenta reuniões (que só existem no sapl 3.0) +if 'reuniao_comissao' in set(exec_legado('show tables')): + DOCS[Reuniao] = [('upload_pauta', 'reuniao_comissao/{}_pauta'), + ('upload_ata', 'reuniao_comissao/{}_ata')], + + DOCS = {model: [(campo, join('sapl_documentos', origem)) - for campo, origem, in campos] + for campo, origem in campos] for model, campos in DOCS.items()} @@ -55,7 +58,7 @@ def mover_documento(repo, origem, destino, ignora_origem_ausente=False): def migrar_logotipo(repo, casa, propriedades): print('.... Migrando logotipo da casa ....') - [(campo, origem)] = DOCS[CasaLegislativa] + campo, origem = 'logotipo', 'sapl_documentos/props_sapl/{}.*' # a extensão do logo pode ter sido ajustada pelo tipo real do arquivo nome_nas_propriedades = os.path.splitext(propriedades['id_logo'])[0] arquivos = glob( @@ -102,10 +105,10 @@ def migrar_propriedades_da_casa(repo): migrar_logotipo(repo, casa, propriedades) casa.save() - repo.git.rm(caminho) def migrar_docs_por_ids(repo, model): + for campo, base_origem in DOCS[model]: print('#### Migrando {} de {} ####'.format(campo, model.__name__)) @@ -161,16 +164,7 @@ def migrar_documentos(repo): # (necessário para o cropping de imagem) repo.git.execute('git annex get sapl_documentos/parlamentar'.split()) - for model in [ - Parlamentar, - MateriaLegislativa, - DocumentoAcessorio, - NormaJuridica, - SessaoPlenaria, - Proposicao, - DocumentoAdministrativo, - DocumentoAcessorioAdministrativo, - ]: + for model in DOCS: migrar_docs_por_ids(repo, model) sobrando = [join(dir, file) From 5d7bdd5a5500cacf41fb019dbbd2cb5cf8a42be3 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Sat, 16 Jun 2018 15:36:53 -0300 Subject: [PATCH 027/107] Ajusta refs a XSLT ao migrar SDE --- sapl/legacy/migracao.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index 9ed09360f..dd54a103e 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -51,6 +51,9 @@ def salva_conteudo_do_sde(proposicao, conteudo): proposicao, 'proposicao_sde_{}.xml'.format(proposicao.pk)) caminho_absoluto = Path(REPO.working_dir, caminho_relativo) caminho_absoluto.parent.mkdir(parents=True) + # ajusta caminhos para folhas de estilo + conteudo = conteudo.replace(b'"XSLT/HTML', b'"/XSLT/HTML') + conteudo = conteudo.replace(b"'XSLT/HTML", b"'/XSLT/HTML") with open(caminho_absoluto, 'wb') as arq: arq.write(conteudo) proposicao.texto_original = caminho_relativo From f1519b9f0c7596a361c931108cdc940b45996a2f Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Sat, 16 Jun 2018 15:37:17 -0300 Subject: [PATCH 028/107] Adiciona backup do banco ao repo ao migrar --- sapl/legacy/migracao_dados.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 41c7b9934..895380493 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -1357,6 +1357,7 @@ def gravar_marco(): # salva mudanças REPO.git.add([dir_dados.name]) + REPO.git.add([arq_backup.name]) if 'master' not in REPO.heads or REPO.index.diff('HEAD'): # se de fato existe mudança REPO.index.commit('Grava marco') From de8d813ef20fe4a177eeed5ce0219e5739860666 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Sat, 16 Jun 2018 19:26:00 -0300 Subject: [PATCH 029/107] =?UTF-8?q?Adiciona=20verifica=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20mtime=20ao=20exportar=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scripts/exporta_zope/exporta_zope.py | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 270c90583..33a007230 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -13,6 +13,7 @@ import sys from collections import defaultdict from contextlib import contextmanager from functools import partial +from os.path import exists import git import magic @@ -147,7 +148,7 @@ def enumerate_by_key_list(folder, key_list, type_key): for entry in folder.get(key_list, []): id, meta_type = entry['id'], entry[type_key] try: - obj = br(folder.get(id, None)) + obj = folder.get(id, None) except POSKeyError: print('#' * 80) print('#' * 80) @@ -170,7 +171,7 @@ def enumerate_btree(folder): tree = folder['_tree'] contagem_real = 0 # para o caso em que não haja itens for contagem_real, (id, obj) in enumerate(tree.iteritems(), start=1): - obj, meta_type = br(obj), type(obj).__name__ + meta_type = type(obj).__name__ yield id, obj, meta_type # verificação de consistência if contagem_esperada != contagem_real: @@ -197,10 +198,10 @@ def logando_nao_identificados(): print('#' * 80) -def dump_folder(folder, path, salvar, enum=enumerate_folder): +def dump_folder(folder, path, salvar, mtimes, enum=enumerate_folder): name = folder['id'] path = os.path.join(path, name) - if not os.path.exists(path): + if not exists(path): os.makedirs(path) for id, obj, meta_type in enum(folder): # pula pastas *_old (presentes em várias bases) @@ -210,8 +211,16 @@ def dump_folder(folder, path, salvar, enum=enumerate_folder): if dump == '?': nao_identificados[meta_type].append(path + '/' + id) elif dump: - id_interno = dump(obj, path, salvar) - assert id == id_interno + if isinstance(dump, partial) and dump.func == dump_folder: + dump(br(obj), path, salvar, mtimes) + else: + # se o objeto for mais recente que o da última exportação + mtime = obj._p_mtime + fullname = os.path.join(path, id) + if mtime > mtimes.get(fullname): + id_interno = dump(br(obj), path, salvar) + assert id == id_interno + mtimes[fullname] = mtime return name @@ -223,7 +232,7 @@ def read_sde(element): def read_properties(): for id, obj, meta_type in enumerate_properties(element): - yield id, decode_iso8859(obj) + yield id, decode_iso8859(br(obj)) def read_children(): for id, obj, meta_type in enumerate_folder(element): @@ -237,7 +246,7 @@ def read_sde(element): # ignoramos os scrips python de eventos dos templates yield {'id': id, 'meta_type': meta_type, - 'dados': read_sde(obj)} + 'dados': read_sde(br(obj))} data = dict(read_properties()) children = list(read_children()) @@ -335,9 +344,12 @@ def dump_usuarios(sapl, path, salvar): save_as_yaml(path, 'usuarios.yaml', users, salvar) -def _dump_sapl(data_fs_path, documentos_fs_path, destino, salvar): - assert Path(data_fs_path).exists() - assert Path(documentos_fs_path).exists() +def _dump_sapl(data_fs_path, documentos_fs_path, destino, salvar, mtimes): + assert exists(data_fs_path) + assert exists(documentos_fs_path) + # precisamos trabalhar com strings e não Path's para as comparações de mtimes + data_fs_path, documentos_fs_path, destino = map(str, ( + data_fs_path, documentos_fs_path, destino)) app, close_db = get_app(data_fs_path) try: @@ -352,12 +364,12 @@ def _dump_sapl(data_fs_path, documentos_fs_path, destino, salvar): sapl = find_sapl(app) # extrai folhas XSLT if 'XSLT' in sapl: - dump_folder(br(sapl['XSLT']), destino, salvar) + dump_folder(br(sapl['XSLT']), destino, salvar, mtimes) # extrai documentos docs = br(sapl['sapl_documentos']) with logando_nao_identificados(): - dump_folder(docs, destino, salvar) + dump_folder(docs, destino, salvar, mtimes) dump_propriedades(docs, destino, salvar) finally: close_db() @@ -392,7 +404,7 @@ def build_salvar(repo): print('- hash encontrado - {}'.format(fullname)) else: fullname = ajusta_extensao(fullname, conteudo) - if os.path.exists(fullname): + if exists(fullname): # destrava arquivo pré-existente (o conteúdo mudou) repo_execute(repo, 'git annex unlock', fullname) with open(fullname, 'w') as arq: @@ -409,8 +421,8 @@ def dump_sapl(sigla): 'datafs', '{}_cm_{}.fs'.format(prefixo, sigla)) for prefixo in ('Data', 'DocumentosSapl')] - assert data_fs_path.exists(), 'Origem não existe: {}'.format(data_fs_path) - if not documentos_fs_path.exists(): + assert exists(data_fs_path), 'Origem não existe: {}'.format(data_fs_path) + if not exists(documentos_fs_path): documentos_fs_path = data_fs_path nome_banco_legado = 'sapl_cm_{}'.format(sigla) @@ -427,12 +439,17 @@ def dump_sapl(sigla): salvar = build_salvar(repo) try: finalizado = False - _dump_sapl(data_fs_path, documentos_fs_path, destino, salvar) + arq_mtimes = Path(repo.working_dir, 'mtimes.yaml') + mtimes = yaml.load( + arq_mtimes.read_file()) if arq_mtimes.exists() else {} + _dump_sapl(data_fs_path, documentos_fs_path, destino, salvar, mtimes) finalizado = True finally: # grava mundaças repo_execute(repo, 'git annex add sapl_documentos') repo.git.add(A=True) + arq_mtimes.write_file(yaml.safe_dump(mtimes, allow_unicode=True)) + # atualiza repo if 'master' not in repo.heads or repo.index.diff('HEAD'): # se de fato existe mudança status = 'completa' if finalizado else 'parcial' From a1b2d3bc7efe09da444388fc32eb805a8e7179c1 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Sat, 16 Jun 2018 19:33:06 -0300 Subject: [PATCH 030/107] =?UTF-8?q?Retira=20verifica=C3=A7=C3=A3o=20de=20h?= =?UTF-8?q?ashes=20do=20annex=20ao=20exportar=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Já estamos usando verificando o mtime --- .../scripts/exporta_zope/exporta_zope.py | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 33a007230..5639a7665 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -379,12 +379,6 @@ def repo_execute(repo, cmd, *args): return repo.git.execute(cmd.split() + list(args)) -def get_annex_hashes(repo): - hashes = repo_execute( - repo, 'git annex find', '--format=${keyname}\n', '--include=*') - return {os.path.splitext(h)[0] for h in hashes.splitlines()} - - def ajusta_extensao(fullname, conteudo): base, extensao = os.path.splitext(fullname) if extensao not in ['.xsl', '.xslt', '.yaml', '.css']: @@ -393,23 +387,15 @@ def ajusta_extensao(fullname, conteudo): def build_salvar(repo): - """Constroi função salvar que pula arquivos que já estão no annex - """ - hashes = get_annex_hashes(repo) def salvar(fullname, conteudo): - sha = hashlib.sha256() - sha.update(conteudo) - if sha.hexdigest() in hashes: - print('- hash encontrado - {}'.format(fullname)) - else: - fullname = ajusta_extensao(fullname, conteudo) - if exists(fullname): - # destrava arquivo pré-existente (o conteúdo mudou) - repo_execute(repo, 'git annex unlock', fullname) - with open(fullname, 'w') as arq: - arq.write(conteudo) - print(fullname) + fullname = ajusta_extensao(fullname, conteudo) + if exists(fullname): + # destrava arquivo pré-existente (o conteúdo mudou) + repo_execute(repo, 'git annex unlock', fullname) + with open(fullname, 'w') as arq: + arq.write(conteudo) + print(fullname) return salvar From a62fe294570f49968c4385efa4aff1c4070fe33b Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Sun, 17 Jun 2018 16:18:24 -0300 Subject: [PATCH 031/107] =?UTF-8?q?Ajusta=20compara=C3=A7=C3=A3o=20de=20mt?= =?UTF-8?q?imes=20na=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, 1 insertion(+), 1 deletion(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 5639a7665..8f78b060f 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -217,7 +217,7 @@ def dump_folder(folder, path, salvar, mtimes, enum=enumerate_folder): # se o objeto for mais recente que o da última exportação mtime = obj._p_mtime fullname = os.path.join(path, id) - if mtime > mtimes.get(fullname): + if mtime > mtimes.get(fullname, 0): id_interno = dump(br(obj), path, salvar) assert id == id_interno mtimes[fullname] = mtime From d561025fc793843784188f291a9dbc78d23e55a4 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Mon, 18 Jun 2018 12:10:39 -0300 Subject: [PATCH 032/107] Fix #2022 (#2023) --- sapl/sessao/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 8b695f10d..a0c727ec1 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -2824,7 +2824,8 @@ class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente): ordem_dia.tipo_votacao = tipo_votacao ordem_dia.save() - return self.get(request, self.kwargs) + return HttpResponseRedirect( + reverse('sapl.sessao:ordemdia_list', kwargs=self.kwargs)) @csrf_exempt From 8e92fc55506bee088b9463fcada9a47ce17f4a9d Mon Sep 17 00:00:00 2001 From: Edward Date: Mon, 18 Jun 2018 12:10:54 -0300 Subject: [PATCH 033/107] Fixes: #2024 (#2025) --- sapl/parlamentares/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sapl/parlamentares/views.py b/sapl/parlamentares/views.py index 093bb83bd..ee67f2733 100644 --- a/sapl/parlamentares/views.py +++ b/sapl/parlamentares/views.py @@ -462,12 +462,14 @@ class ParlamentarCrud(Crud): return l.id if legislaturas: return legislaturas[0].id - return 0 + return -1 def get_queryset(self): queryset = super().get_queryset() legislatura_id = self.take_legislatura_id() - if legislatura_id != 0: + # Pelo menos uma casa legislativa criou uma + # legislatura de numero zero, o que é um absurdo + if legislatura_id >= 0: return queryset.filter( mandato__legislatura_id=legislatura_id).annotate( mandato_titular=F('mandato__titular')) From f37a754a458726a7a8836e065c13ede778ebb3ae Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 18 Jun 2018 12:21:44 -0300 Subject: [PATCH 034/107] HOT-FIX: adiciona logs no file system do container --- Dockerfile | 3 ++- docker-compose.yml | 3 ++- gunicorn_start.sh | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 693230025..9f89509d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,7 +50,8 @@ RUN rm -rf /var/interlegis/sapl/sapl/.env && \ RUN chmod +x /var/interlegis/sapl/start.sh && \ ln -sf /dev/stdout /var/log/nginx/access.log && \ - ln -sf /dev/stderr /var/log/nginx/error.log + ln -sf /dev/stderr /var/log/nginx/error.log && \ + mkdir /var/log/sapl/ VOLUME ["/var/interlegis/sapl/data", "/var/interlegis/sapl/media"] diff --git a/docker-compose.yml b/docker-compose.yml index f3ca2cef8..59d13d8a9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,8 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.87 + # image: interlegis/sapl:3.1.87 + build: . restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/gunicorn_start.sh b/gunicorn_start.sh index 6247a0b27..4f58022ce 100755 --- a/gunicorn_start.sh +++ b/gunicorn_start.sh @@ -44,6 +44,6 @@ exec gunicorn ${DJANGO_WSGI_MODULE}:application \ --workers $NUM_WORKERS \ --max-requests $MAX_REQUESTS \ --user $USER \ - --access-logfile - \ - --error-logfile - \ + --access-logfile /var/log/sapl/access.log \ + --error-logfile /var/log/sapl/error.log \ --bind=unix:$SOCKFILE From 543b4a6adb6406795e707af5f3a169338341bf88 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 18 Jun 2018 12:22:10 -0300 Subject: [PATCH 035/107] Release: 3.1.88 --- 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 59d13d8a9..a607b27df 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - # image: interlegis/sapl:3.1.87 + # image: interlegis/sapl:3.1.88 build: . restart: always environment: diff --git a/setup.py b/setup.py index e25cde8b6..61e420d8a 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.87', + version='3.1.88', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From d055b2c86a50ee4af9b6ac19278c1dabaeb35cdd Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 18 Jun 2018 13:27:05 -0300 Subject: [PATCH 036/107] 2014 exclui tramitacao lote (#2020) * Fix #2014 * Adiciona condicao para excluir --- sapl/materia/forms.py | 67 ++++++++++++++++++- sapl/materia/urls.py | 5 +- sapl/materia/views.py | 27 +++++++- .../materia/em_lote/excluir_tramitacao.html | 7 ++ sapl/templates/navbar.yaml | 3 + 5 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 sapl/templates/materia/em_lote/excluir_tramitacao.html diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index d14fad28c..20518cfdd 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -32,7 +32,8 @@ from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, to_row) from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto, MateriaLegislativa, Orgao, RegimeTramitacao, - TipoDocumento, TipoProposicao) + TipoDocumento, TipoProposicao, StatusTramitacao, + UnidadeTramitacao) from sapl.norma.models import (LegislacaoCitada, NormaJuridica, TipoNormaJuridica) from sapl.parlamentares.models import Legislatura @@ -2032,3 +2033,67 @@ class FichaSelecionaForm(forms.Form): form_actions(label='Gerar Impresso') ) ) + + +class ExcluirTramitacaoEmLote(forms.Form): + + data_tramitacao = forms.DateField(required=True, + label=_('Data da Tramitação')) + + unidade_tramitacao_local = forms.ModelChoiceField(label=_('Unidade Local'), + required=True, + queryset=UnidadeTramitacao.objects.all(), + empty_label='------') + + unidade_tramitacao_destino = forms.ModelChoiceField(label=_('Unidade Destino'), + required=True, + queryset=UnidadeTramitacao.objects.all(), + empty_label='------') + + status = forms.ModelChoiceField(label=_('Status'), + required=True, + queryset=StatusTramitacao.objects.all(), + empty_label='------') + + def clean(self): + super(ExcluirTramitacaoEmLote, self).clean() + + cleaned_data = self.cleaned_data + + if not self.is_valid(): + return cleaned_data + + data_tramitacao = cleaned_data['data_tramitacao'] + unidade_tramitacao_local = cleaned_data['unidade_tramitacao_local'] + unidade_tramitacao_destino = cleaned_data['unidade_tramitacao_destino'] + status = cleaned_data['status'] + + tramitacao_set = Tramitacao.objects.filter(data_tramitacao=data_tramitacao, + unidade_tramitacao_local=unidade_tramitacao_local, + unidade_tramitacao_destino=unidade_tramitacao_destino, + status=status) + if not tramitacao_set.exists(): + raise forms.ValidationError( + _("Não existem tramitações com os dados informados.")) + + return cleaned_data + + def __init__(self, *args, **kwargs): + super(ExcluirTramitacaoEmLote, self).__init__(*args, **kwargs) + + row1 = to_row( + [('data_tramitacao', 6), + ('status', 6),]) + row2 = to_row( + [('unidade_tramitacao_local', 6), + ('unidade_tramitacao_destino', 6)]) + + self.helper = FormHelper() + self.helper.layout = Layout( + Fieldset(_('Dados das Tramitações'), + row1, + row2, + HTML(" "), + form_actions(label='Excluir') + ) + ) diff --git a/sapl/materia/urls.py b/sapl/materia/urls.py index 934c4dbac..f2c89c908 100644 --- a/sapl/materia/urls.py +++ b/sapl/materia/urls.py @@ -23,7 +23,8 @@ from sapl.materia.views import (AcompanhamentoConfirmarView, TipoFimRelatoriaCrud, TipoMateriaCrud, TipoProposicaoCrud, TramitacaoCrud, TramitacaoEmLoteView, UnidadeTramitacaoCrud, - proposicao_texto, recuperar_materia) + proposicao_texto, recuperar_materia, + ExcluirTramitacaoEmLoteView) from sapl.norma.views import NormaPesquisaSimplesView from .apps import AppConfig @@ -90,6 +91,8 @@ urlpatterns_materia = [ name='primeira_tramitacao_em_lote'), url(r'^materia/tramitacao-em-lote', TramitacaoEmLoteView.as_view(), name='tramitacao_em_lote'), + url(r'^materia/excluir-tramitacao-em-lote', ExcluirTramitacaoEmLoteView.as_view(), + name='excluir_tramitacao_em_lote'), ] diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 807db3d9c..d5c4884c9 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -57,7 +57,8 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, TramitacaoEmLoteFilterSet, UnidadeTramitacaoForm, filtra_tramitacao_destino, filtra_tramitacao_destino_and_status, - filtra_tramitacao_status) + filtra_tramitacao_status, + ExcluirTramitacaoEmLote) from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, DespachoInicial, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao, @@ -1972,3 +1973,27 @@ class FichaSelecionaView(PermissionRequiredMixin, FormView): return gerar_pdf_impressos(self.request, context, 'materia/impressos/ficha_pdf.html') + + +class ExcluirTramitacaoEmLoteView(PermissionRequiredMixin, FormView): + + template_name = 'materia/em_lote/excluir_tramitacao.html' + permission_required = ('materia.add_tramitacao',) + form_class = ExcluirTramitacaoEmLote + form_valid_message = _('Tramitações excluídas com sucesso!') + + def get_success_url(self): + return reverse('sapl.materia:excluir_tramitacao_em_lote') + + def form_valid(self, form): + + tramitacao_set = Tramitacao.objects.filter(data_tramitacao=form.cleaned_data['data_tramitacao'], + unidade_tramitacao_local=form.cleaned_data['unidade_tramitacao_local'], + unidade_tramitacao_destino=form.cleaned_data['unidade_tramitacao_destino'], + status=form.cleaned_data['status']) + for tramitacao in tramitacao_set: + materia = tramitacao.materia + if tramitacao == materia.tramitacao_set.last(): + tramitacao.delete() + + return redirect(self.get_success_url()) \ No newline at end of file diff --git a/sapl/templates/materia/em_lote/excluir_tramitacao.html b/sapl/templates/materia/em_lote/excluir_tramitacao.html new file mode 100644 index 000000000..b74faa593 --- /dev/null +++ b/sapl/templates/materia/em_lote/excluir_tramitacao.html @@ -0,0 +1,7 @@ +{% extends "crud/detail.html" %} +{% load i18n crispy_forms_tags %} + +{% block actions %}{% endblock %} +{% block detail_content %} + {% crispy form %} +{% endblock detail_content %} \ No newline at end of file diff --git a/sapl/templates/navbar.yaml b/sapl/templates/navbar.yaml index c997e2e41..b80cb7acd 100644 --- a/sapl/templates/navbar.yaml +++ b/sapl/templates/navbar.yaml @@ -54,6 +54,9 @@ - title: {% trans 'Tramitação em Lote' %} url: sapl.materia:primeira_tramitacao_em_lote check_permission: materia.list_tramitacao {% comment %} FIXME transformar para checagens de menu_[funcionalidade]{% endcomment%} + - title: {% trans 'Excluir Tramitação em Lote' %} + url: sapl.materia:excluir_tramitacao_em_lote + check_permission: materia.list_tramitacao {% comment %} FIXME transformar para checagens de menu_[funcionalidade]{% endcomment%} - title: {% trans 'Normas Jurídicas' %} children: From 7f41407039d9416c8791f7a1ad08f4d3b4aced33 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 18 Jun 2018 13:35:49 -0300 Subject: [PATCH 037/107] Release: 3.1.89 --- docker-compose.yml | 5 ++--- setup.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index a607b27df..ead9d3300 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ sapldb: - image: postgres + image: postgres:9.6.8-alpine restart: always environment: POSTGRES_PASSWORD: sapl @@ -11,8 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - # image: interlegis/sapl:3.1.88 - build: . + image: interlegis/sapl:3.1.89 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 61e420d8a..661e71e56 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.88', + version='3.1.89', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 429c87921d8669714bd5453aadf9a72542b0f381 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 18 Jun 2018 15:57:58 -0300 Subject: [PATCH 038/107] Fix #2027 (#2028) --- sapl/materia/views.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index d5c4884c9..8bf4f7600 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -1037,10 +1037,16 @@ class TramitacaoCrud(MasterDetailCrud): '-id').first() if ultima_tramitacao: - context['form'].fields[ - 'unidade_tramitacao_local'].choices = [ - (ultima_tramitacao.unidade_tramitacao_destino.pk, - ultima_tramitacao.unidade_tramitacao_destino)] + if ultima_tramitacao.unidade_tramitacao_destino: + context['form'].fields[ + 'unidade_tramitacao_local'].choices = [ + (ultima_tramitacao.unidade_tramitacao_destino.pk, + ultima_tramitacao.unidade_tramitacao_destino)] + else: + msg = _('Unidade de tramitação destino ' + ' da última tramitação não pode ser vazia!') + messages.add_message(self.request, messages.ERROR, msg) + return context def form_valid(self, form): From 47afb8b73aaa40f93adbecf1ffa20d9349ad0598 Mon Sep 17 00:00:00 2001 From: Edward Date: Mon, 18 Jun 2018 16:01:20 -0300 Subject: [PATCH 039/107] HOT-FIX: revertendo pinagem de PG --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index ead9d3300..313c0a963 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ sapldb: - image: postgres:9.6.8-alpine + image: postgres restart: always environment: POSTGRES_PASSWORD: sapl From 6f18ccb12da3922a2afd96e2b0daf6a9fe98223a Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 18 Jun 2018 16:06:31 -0300 Subject: [PATCH 040/107] Release: 3.1.90 --- 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 313c0a963..6d6221296 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.89 + image: interlegis/sapl:3.1.90 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 661e71e56..dee2f95fd 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.89', + version='3.1.90', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From ad9f0bd846805ac11f4b03d304167c0837ae52fa Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 19 Jun 2018 12:02:34 -0300 Subject: [PATCH 041/107] Inclui arq mtimes.yaml no versionamento ao exportar docs --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 8f78b060f..ca5044db1 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -433,8 +433,8 @@ def dump_sapl(sigla): finally: # grava mundaças repo_execute(repo, 'git annex add sapl_documentos') - repo.git.add(A=True) arq_mtimes.write_file(yaml.safe_dump(mtimes, allow_unicode=True)) + repo.git.add(A=True) # atualiza repo if 'master' not in repo.heads or repo.index.diff('HEAD'): # se de fato existe mudança From f11795b932b940349d1f69202a3d3ad995e6380e Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Wed, 20 Jun 2018 09:43:32 -0300 Subject: [PATCH 042/107] retira link disponivel para superuser --- sapl/templates/compilacao/textoarticulado_menu_config.html | 1 - 1 file changed, 1 deletion(-) diff --git a/sapl/templates/compilacao/textoarticulado_menu_config.html b/sapl/templates/compilacao/textoarticulado_menu_config.html index 0116ba667..f423d21cd 100644 --- a/sapl/templates/compilacao/textoarticulado_menu_config.html +++ b/sapl/templates/compilacao/textoarticulado_menu_config.html @@ -14,7 +14,6 @@ {% if perms.compilacao.list_tipovide %}
  • {%model_verbose_name_plural 'sapl.compilacao.models.TipoVide'%}
  • {% endif %} {% if user.is_superuser %} -
  • {%model_verbose_name_plural 'sapl.compilacao.models.TipoDispositivo'%}
  • Relacionamento entre Dispositivos
  • {% endif %} From f8e973bca41a3c735d2e57c526467660687f3fea Mon Sep 17 00:00:00 2001 From: cristian-longhi Date: Wed, 20 Jun 2018 13:47:34 -0300 Subject: [PATCH 043/107] =?UTF-8?q?Exibi=C3=A7=C3=A3o=20da=20Mesa=20Direto?= =?UTF-8?q?ra=20e=20ajustes=20de=20preenchimento=20em=20mat=C3=A9rias=20e?= =?UTF-8?q?=20protocolo=20(#2029)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Ordenação mesa * Ordenação mesa --- sapl/parlamentares/views.py | 6 ++--- sapl/protocoloadm/forms.py | 3 ++- .../migrations/0022_auto_20180618_1625.py | 25 +++++++++++++++++++ sapl/sessao/models.py | 2 +- sapl/sessao/views.py | 4 +-- 5 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 sapl/sessao/migrations/0022_auto_20180618_1625.py diff --git a/sapl/parlamentares/views.py b/sapl/parlamentares/views.py index ee67f2733..78678c3fc 100644 --- a/sapl/parlamentares/views.py +++ b/sapl/parlamentares/views.py @@ -652,7 +652,7 @@ class MesaDiretoraView(FormView): sessao_atual = sessoes.filter(data_inicio__year__lte=year).exclude( data_inicio__gt=timezone.now()).order_by('-data_inicio').first() - mesa = sessao_atual.composicaomesa_set.all() if sessao_atual else [] + mesa = sessao_atual.composicaomesa_set.all().order_by('cargo_id') if sessao_atual else [] cargos_ocupados = [m.cargo for m in mesa] cargos = CargoMesa.objects.all() @@ -712,7 +712,7 @@ def altera_field_mesa(request): # Atualiza os componentes da view após a mudança composicao_mesa = ComposicaoMesa.objects.filter( - sessao_legislativa=sessao_selecionada) + sessao_legislativa=sessao_selecionada).order_by('cargo_id') cargos_ocupados = [m.cargo for m in composicao_mesa] cargos = CargoMesa.objects.all() @@ -881,7 +881,7 @@ def altera_field_mesa_public_view(request): lista_sessoes = [(s.id, s.__str__()) for s in sessoes] composicao_mesa = ComposicaoMesa.objects.filter( - sessao_legislativa=sessao_selecionada) + sessao_legislativa=sessao_selecionada).order_by('cargo_id') cargos_ocupados = [(m.cargo.id, m.cargo.__str__()) for m in composicao_mesa] diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 7d68ad9c3..8502bf334 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -291,7 +291,8 @@ class ProtocoloDocumentForm(ModelForm): tipo_protocolo = forms.ChoiceField(required=True, label=_('Tipo de Protocolo'), - choices=TIPOS_PROTOCOLO_CREATE,) + choices=TIPOS_PROTOCOLO_CREATE, + initial=0,) tipo_documento = forms.ModelChoiceField( label=_('Tipo de Documento'), diff --git a/sapl/sessao/migrations/0022_auto_20180618_1625.py b/sapl/sessao/migrations/0022_auto_20180618_1625.py new file mode 100644 index 000000000..4e8fd4323 --- /dev/null +++ b/sapl/sessao/migrations/0022_auto_20180618_1625.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-06-18 19:25 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sessao', '0021_auto_20180417_1209'), + ] + + operations = [ + migrations.AlterField( + model_name='expedientemateria', + name='tipo_votacao', + field=models.PositiveIntegerField(choices=[(1, 'Simbólica'), (2, 'Nominal'), (3, 'Secreta')], default=1, verbose_name='Tipo de votação'), + ), + migrations.AlterField( + model_name='ordemdia', + name='tipo_votacao', + field=models.PositiveIntegerField(choices=[(1, 'Simbólica'), (2, 'Nominal'), (3, 'Secreta')], default=1, verbose_name='Tipo de votação'), + ), + ] diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py index 4c5e9e187..6af5f490f 100644 --- a/sapl/sessao/models.py +++ b/sapl/sessao/models.py @@ -241,7 +241,7 @@ class AbstractOrdemDia(models.Model): numero_ordem = models.PositiveIntegerField(verbose_name=_('Nº Ordem')) resultado = models.TextField(blank=True, verbose_name=_('Resultado')) tipo_votacao = models.PositiveIntegerField( - verbose_name=_('Tipo de votação'), choices=TIPO_VOTACAO_CHOICES) + verbose_name=_('Tipo de votação'), choices=TIPO_VOTACAO_CHOICES, default=1) votacao_aberta = models.NullBooleanField( blank=True, choices=YES_NO_CHOICES, diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index a0c727ec1..c9e1e0e00 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -992,7 +992,7 @@ class MesaView(FormMixin, DetailView): return self.render_to_response(context) - mesa = sessao.integrantemesa_set.all() if sessao else [] + mesa = sessao.integrantemesa_set.all().order_by('cargo_id') if sessao else [] cargos_ocupados = [m.cargo for m in mesa] cargos = CargoMesa.objects.all() cargos_vagos = list(set(cargos) - set(cargos_ocupados)) @@ -1043,7 +1043,7 @@ def atualizar_mesa(request): # Atualiza os componentes da view após a mudança composicao_mesa = IntegranteMesa.objects.filter( - sessao_plenaria=sessao.id) + sessao_plenaria=sessao.id).order_by('cargo_id') cargos_ocupados = [m.cargo for m in composicao_mesa] cargos = CargoMesa.objects.all() From 3c9f389c722eda9e133246f9b97f5e8494b22b11 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Wed, 20 Jun 2018 17:46:17 -0300 Subject: [PATCH 044/107] Fix #2035 (#2036) --- sapl/materia/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 8bf4f7600..02484b162 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -96,7 +96,9 @@ def proposicao_texto(request, pk): if proposicao.texto_original: if (not proposicao.data_recebimento and proposicao.autor.user_id != request.user.id): - raise Http404 + messages.error(request, _('Você não tem permissão para acessar o texto original.')) + return redirect(reverse('sapl.materia:proposicao_detail', + kwargs={'pk':pk})) arquivo = proposicao.texto_original From 84aa257b7087a0ded12a2dfa97e32212c85be978 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 20 Jun 2018 19:07:59 -0300 Subject: [PATCH 045/107] =?UTF-8?q?Limita=20buffer=20para=20magic=20na=20e?= =?UTF-8?q?xporta=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, 1 insertion(+), 1 deletion(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index ca5044db1..568535d7f 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -79,7 +79,7 @@ def br(obj): def guess_extension(fullname, buffer): - mime = magic.from_buffer(buffer, mime=True) + mime = magic.from_buffer(buffer[:1024], mime=True) extensao = EXTENSOES.get(mime) if extensao is not None: return extensao From 2a39cbb2b54748f4587a96ee685022df9288f44c Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Thu, 21 Jun 2018 12:53:38 -0300 Subject: [PATCH 046/107] HOT FIX (#2037) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Arrumada variável no template crud/list.html --- sapl/templates/crud/list.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/templates/crud/list.html b/sapl/templates/crud/list.html index b1743516d..8e911913c 100644 --- a/sapl/templates/crud/list.html +++ b/sapl/templates/crud/list.html @@ -74,7 +74,7 @@
    {% if href %} {{ value|safe|default:"" }} - {% elif valu != 'core.Cep.None' %} + {% elif value != 'core.Cep.None' %} {% if value|url %} {{ value|safe|default:"" }} {% else %} From 3b3b4acf72ade7640060d5a511e94ce04db8df2f Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Thu, 21 Jun 2018 12:55:26 -0300 Subject: [PATCH 047/107] 1934 ordenar protocolo (#2033) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #1934 ordenaçao na tela de proposiçoes pendentes * Fix #1934 ordenaçao na tela de proposiçoes pendentes * --amend * Update more pythonic * Update prop_pendentes_list.html --- sapl/base/templatetags/common_tags.py | 31 ++++++++++++++++++- .../materia/prop_pendentes_list.html | 31 +++++++++++++++---- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py index 9e095f072..73d71faa8 100644 --- a/sapl/base/templatetags/common_tags.py +++ b/sapl/base/templatetags/common_tags.py @@ -3,7 +3,7 @@ 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.materia.models import DocumentoAcessorio, MateriaLegislativa, Proposicao from sapl.norma.models import NormaJuridica from sapl.parlamentares.models import Filiacao from sapl.utils import filiacao_data @@ -11,6 +11,11 @@ from sapl.utils import filiacao_data register = template.Library() +@register.simple_tag +def define(arg): + return arg + + @register.simple_tag def field_verbose_name(instance, field_name): return instance._meta.get_field(field_name).verbose_name @@ -34,6 +39,30 @@ def model_verbose_name_plural(class_name): return model._meta.verbose_name_plural +@register.filter +def split(value, arg): + return value.split(arg) + + +@register.filter +def sort_by_keys(value, key): + transformed = [] + id_props = [x.id for x in value] + qs = Proposicao.objects.filter(pk__in=id_props) + key_descricao = {'1': 'data_envio', + '-1': '-data_envio', + '2': 'tipo', + '-2': '-tipo', + '3': 'descricao', + '-3': '-descricao', + '4': 'autor', + '-4': '-autor' + } + + transformed = qs.order_by(key_descricao[key]) + return transformed + + @register.filter def lookup(d, key): return d[key] if key in d else [] diff --git a/sapl/templates/materia/prop_pendentes_list.html b/sapl/templates/materia/prop_pendentes_list.html index 092d19a26..518ba7601 100644 --- a/sapl/templates/materia/prop_pendentes_list.html +++ b/sapl/templates/materia/prop_pendentes_list.html @@ -11,24 +11,42 @@ - - - - + {% with 'Data Envio,Tipo,Descrição,Autor' as list %} + {% for name in list|split:"," %} + + {% endfor %} {% if not AppConfig.receber_recibo_proposicao %} {% endif %} + {% endwith %} - {% for prop in object_list %} + {% if 'o' in request.GET %} + {% define object_list|sort_by_keys:request.GET.o as list %} + {% else %} + {% define object_list as list %} + {% endif %} + + {% for prop in list %} - +
    Data de EnvioTipoDescriçãoAutor + + {{ name }} + {% if 'o' in request.GET %} + {% if 'o' not in request.GET and forloop.counter == 1 or 'o' in request.GET and forloop.counter|safe == request.GET.o %} + + {% elif 'o' in request.GET and forloop.counter == request.GET.o|str2intabs %} + + {%endif%} + {%endif%} + + Código do Documento
    {{ prop.data_envio|localtime|date:"d/m/Y H:i:s" }} {{ prop.tipo.descricao }} {{ prop.descricao }}{{prop.autor}}{{ prop.autor }} {% if not AppConfig.receber_recibo_proposicao %} {%if prop.hash_code %} @@ -44,5 +62,6 @@
    {% endif %} + {% include 'paginacao.html'%} {% endblock %} From 97bf1347d317b409c331668dbf0be58d1f501fc8 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 21 Jun 2018 14:14:08 -0300 Subject: [PATCH 048/107] =?UTF-8?q?Corrige=20ordem=20de=20propaga=C3=A7?= =?UTF-8?q?=C3=A3o=20de=20exclus=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 895380493..5a75afb26 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -567,8 +567,8 @@ def propaga_exclusoes(): def uniformiza_banco(): exec_legado('SET SESSION sql_mode = "";') # desliga checagens do mysql - checa_registros_votacao_ambiguos_e_remove_nao_usados() propaga_exclusoes() + checa_registros_votacao_ambiguos_e_remove_nao_usados() garante_coluna_no_legado('proposicao', 'num_proposicao int(11) NULL') From 7de5654166a25f2374343784e2d32947bcbafd4f Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 21 Jun 2018 14:14:40 -0300 Subject: [PATCH 049/107] Unifica autores por username --- sapl/legacy/migracao_dados.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 5a75afb26..8d3489439 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -649,6 +649,7 @@ sessao_plenaria_presenca | dat_sessao = NULL | dat_sessao = 0 unifica_autores_repetidos_no_legado('cod_parlamentar') unifica_autores_repetidos_no_legado('cod_comissao') + unifica_autores_repetidos_no_legado('col_username') # é 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 From 5c0f4a05544f159146e14dabeca20742cac978e6 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 21 Jun 2018 14:14:58 -0300 Subject: [PATCH 050/107] =?UTF-8?q?Corrige=20verifica=C3=A7=C3=A3o=20de=20?= =?UTF-8?q?reuni=C3=B5es=20no=20legado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 7 ++++++- sapl/legacy/migracao_documentos.py | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 8d3489439..2df65c51b 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -855,12 +855,17 @@ def move_para_depois_de(lista, movido, referencias): return lista +TABELAS_LEGADO = [t for (t,) in exec_legado('show tables')] +EXISTE_REUNIAO_NO_LEGADO = 'reuniao_comissao' in TABELAS_LEGADO + + def get_models_a_migrar(): models = [model for app in appconfs for model in app.models.values() if model in field_renames] # retira reuniões quando não existe na base legada # (só existe no sapl 3.0) - if 'reuniao_comissao' not in list(exec_legado('show tables')): + tabelas_legado = [t for (t,) in exec_legado('show tables')] + if not EXISTE_REUNIAO_NO_LEGADO: models.remove(Reuniao) # Devido à referência TipoProposicao.tipo_conteudo_related # a migração de TipoProposicao precisa ser feita diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index fd692aa47..d7fbd89c2 100644 --- a/sapl/legacy/migracao_documentos.py +++ b/sapl/legacy/migracao_documentos.py @@ -9,7 +9,7 @@ from image_cropping.fields import ImageCropField from sapl.base.models import CasaLegislativa from sapl.comissoes.models import Reuniao -from sapl.legacy.migracao_dados import exec_legado +from sapl.legacy.migracao_dados import EXISTE_REUNIAO_NO_LEGADO, exec_legado from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa, Proposicao) from sapl.norma.models import NormaJuridica @@ -36,9 +36,9 @@ DOCS = { } # acrescenta reuniões (que só existem no sapl 3.0) -if 'reuniao_comissao' in set(exec_legado('show tables')): +if EXISTE_REUNIAO_NO_LEGADO: DOCS[Reuniao] = [('upload_pauta', 'reuniao_comissao/{}_pauta'), - ('upload_ata', 'reuniao_comissao/{}_ata')], + ('upload_ata', 'reuniao_comissao/{}_ata')] DOCS = {model: [(campo, join('sapl_documentos', origem)) From f2985f9af9432cf0e54b6db0d2e8efb3c47589f3 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 22 Jun 2018 10:53:20 -0300 Subject: [PATCH 051/107] =?UTF-8?q?Otimiza=20migra=C3=A7=C3=A3o=20de=20doc?= =?UTF-8?q?umentos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_documentos.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index d7fbd89c2..44e52ffef 100644 --- a/sapl/legacy/migracao_documentos.py +++ b/sapl/legacy/migracao_documentos.py @@ -53,7 +53,7 @@ def mover_documento(repo, origem, destino, ignora_origem_ausente=False): print('Origem ignorada ao mover documento: {}'.format(origem)) return os.makedirs(os.path.dirname(destino), exist_ok=True) - repo.git.mv(origem, destino) + os.rename(origem, destino) def migrar_logotipo(repo, casa, propriedades): @@ -167,6 +167,10 @@ def migrar_documentos(repo): for model in DOCS: migrar_docs_por_ids(repo, model) + # versiona modificações + repo.git.add('-A', '.') + repo.index.commit('Migração dos documentos completa') + sobrando = [join(dir, file) for (dir, _, files) in os.walk(join(repo.working_dir, 'sapl_documentos')) From cc440afd256721ca7cb31717039b5b1122eabf98 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 22 Jun 2018 15:25:00 -0300 Subject: [PATCH 052/107] Release: 3.1.91 --- 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 6d6221296..b67c9c472 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.90 + image: interlegis/sapl:3.1.91 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index dee2f95fd..1ce8830db 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.90', + version='3.1.91', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From b3aa5d77902f7430ea1c3d43c1c56e85eee12bbb Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Sat, 23 Jun 2018 10:52:09 -0300 Subject: [PATCH 053/107] Resiste a POSKeyError ao enumerar btree --- .../scripts/exporta_zope/exporta_zope.py | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 568535d7f..c2b8e7973 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -144,17 +144,21 @@ def get_conteudo_dtml_method(doc): return doc['raw'] +def print_msg_poskeyerror(id): + print('#' * 80) + print('#' * 80) + print('ATENÇÃO: DIRETÓRIO corrompido: {}'.format(id)) + print('#' * 80) + print('#' * 80) + + def enumerate_by_key_list(folder, key_list, type_key): for entry in folder.get(key_list, []): id, meta_type = entry['id'], entry[type_key] try: obj = folder.get(id, None) except POSKeyError: - print('#' * 80) - print('#' * 80) - print('ATENÇÃO: DIRETÓRIO corrompido: {}'.format(id)) - print('#' * 80) - print('#' * 80) + print_msg_poskeyerror(id) else: yield id, obj, meta_type @@ -170,9 +174,12 @@ def enumerate_btree(folder): contagem_esperada = folder['_count'].value tree = folder['_tree'] contagem_real = 0 # para o caso em que não haja itens - for contagem_real, (id, obj) in enumerate(tree.iteritems(), start=1): - meta_type = type(obj).__name__ - yield id, obj, meta_type + try: + for contagem_real, (id, obj) in enumerate(tree.iteritems(), start=1): + meta_type = type(obj).__name__ + yield id, obj, meta_type + except POSKeyError: + print_msg_poskeyerror(folder['id']) # verificação de consistência if contagem_esperada != contagem_real: print('ATENÇÃO: contagens diferentes na btree: ' From 82c18f5c95b97d56fcc5a786ad5a68519bf288bd Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Sat, 23 Jun 2018 11:16:56 -0300 Subject: [PATCH 054/107] Preserva ordem ao ler yaml no python 3.5 --- sapl/legacy/migracao_dados.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 2df65c51b..99d656504 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -53,6 +53,22 @@ from sapl.utils import normalize from .scripts.normaliza_dump_mysql import normaliza_dump_mysql from .timezonesbrasil import get_timezone + + +# YAML SETUP ############################################################### +def dict_representer(dumper, data): + return dumper.represent_dict(data.items()) + +yaml.add_representer(OrderedDict, dict_representer) + + +# importante para preservar a ordem ao ler yaml no python 3.5 +def dict_constructor(loader, node): + return OrderedDict(loader.construct_pairs(node)) + +yaml.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, + dict_constructor) + # BASE ###################################################################### # apps to be migrated, in app dependency order (very important) appconfs = [apps.get_app_config(n) for n in [ @@ -740,13 +756,6 @@ def reinicia_sequence(model, id): REPO = git.Repo.init(DIR_REPO) -def dict_representer(dumper, data): - return dumper.represent_dict(data.items()) - - -yaml.add_representer(OrderedDict, dict_representer) - - # configura timezone de migração match = re.match('sapl_cm_(.*)', NOME_BANCO_LEGADO) sigla_casa = match.group(1) From 8fbc5aee5cb676e3c664509ff8484e9135a871ea Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Sat, 23 Jun 2018 12:35:07 -0300 Subject: [PATCH 055/107] =?UTF-8?q?Corrige=20git=20annex=20fix=20na=20migr?= =?UTF-8?q?a=C3=A7=C3=A3o=20de=20imagens?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_documentos.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index 44e52ffef..b246cd467 100644 --- a/sapl/legacy/migracao_documentos.py +++ b/sapl/legacy/migracao_documentos.py @@ -140,6 +140,7 @@ def migrar_docs_por_ids(repo, model): if tem_cropping: # conserta link do git annex (antes do commit) # pois o conteúdo das imagens é acessado pelo cropping + repo.git.add(destino) repo.git.execute('git annex fix'.split() + [destino]) obj.save() else: From 943ce8046993c8b7841ebc68a8590f8111944921 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Sat, 23 Jun 2018 12:44:37 -0300 Subject: [PATCH 056/107] Verifica se dir parlamentar existe antes de git annex get --- sapl/legacy/migracao_documentos.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sapl/legacy/migracao_documentos.py b/sapl/legacy/migracao_documentos.py index b246cd467..66ada19fc 100644 --- a/sapl/legacy/migracao_documentos.py +++ b/sapl/legacy/migracao_documentos.py @@ -163,7 +163,9 @@ def migrar_documentos(repo): # garante que o conteúdo das fotos dos parlamentares esteja presente # (necessário para o cropping de imagem) - repo.git.execute('git annex get sapl_documentos/parlamentar'.split()) + if os.path.exists( + os.path.join(repo.working_dir, 'sapl_documentos/parlamentar')): + repo.git.execute('git annex get sapl_documentos/parlamentar'.split()) for model in DOCS: migrar_docs_por_ids(repo, model) From 0e54d17c777f160c93fe7ebf67e1dc111c133e7d Mon Sep 17 00:00:00 2001 From: Edward Date: Mon, 25 Jun 2018 09:44:43 -0300 Subject: [PATCH 057/107] Fixes #2038 (#2039) --- sapl/materia/forms.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 20518cfdd..838b8616d 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1818,7 +1818,19 @@ class ConfirmarProposicaoForm(ProposicaoForm): if numeracao == 'A': nm = Protocolo.objects.filter( ano=timezone.now().year).aggregate(Max('numero')) - elif numeracao == 'U': + elif numeracao == 'L': + 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 + nm = MateriaLegislativa.objects.filter( + data_apresentacao__gte=data_inicio, + data_apresentacao__lte=data_fim, + tipo=tipo).aggregate(Max('numero')) + + else: + # numeracao == 'U' ou não informada nm = Protocolo.objects.all().aggregate(Max('numero')) protocolo = Protocolo() From 71c63b26bf89a8b2f83423890e9132957f688eee Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 25 Jun 2018 09:45:56 -0300 Subject: [PATCH 058/107] Release: 3.1.92 --- 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 b67c9c472..c33273b3f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.91 + image: interlegis/sapl:3.1.92 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 1ce8830db..b76d46c98 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.91', + version='3.1.92', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 78bf262f41c6ea574a39cc8d506c8c264bfb6203 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Mon, 25 Jun 2018 10:35:06 -0300 Subject: [PATCH 059/107] Resiste a POSKeyError em mais um ponto --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index c2b8e7973..51be333af 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -219,7 +219,11 @@ def dump_folder(folder, path, salvar, mtimes, enum=enumerate_folder): nao_identificados[meta_type].append(path + '/' + id) elif dump: if isinstance(dump, partial) and dump.func == dump_folder: - dump(br(obj), path, salvar, mtimes) + try: + dump(br(obj), path, salvar, mtimes) + except POSKeyError as e: + print_msg_poskeyerror(id) + continue else: # se o objeto for mais recente que o da última exportação mtime = obj._p_mtime From 98a22156909ede4597a79019e28672c6fe79b921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Fr=C3=A1?= Date: Mon, 25 Jun 2018 14:20:50 -0300 Subject: [PATCH 060/107] Aumenta retorno da pesquisa de capa de Processo (#2040) --- sapl/materia/views.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 02484b162..6f0b35ef8 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -1948,16 +1948,16 @@ class FichaSelecionaView(PermissionRequiredMixin, FormView): tipo=tipo, data_apresentacao__range=(data_inicial, data_final)) context['quantidade'] = len(materia_list) - materia_list = materia_list[:20] + materia_list = materia_list[:100] context['form'].fields['materia'].choices = [ (m.id, str(m)) for m in materia_list] - if context['quantidade'] > 20: + if context['quantidade'] > 100: messages.info(self.request, _('Sua pesquisa retornou mais do que ' - '20 impressos. Por questões de ' + '100 impressos. Por questões de ' 'performance, foram retornados ' - 'apenas os 20 primeiros. Caso ' + 'apenas os 100 primeiros. Caso ' 'queira outros, tente fazer uma ' 'pesquisa mais específica')) @@ -2004,4 +2004,4 @@ class ExcluirTramitacaoEmLoteView(PermissionRequiredMixin, FormView): if tramitacao == materia.tramitacao_set.last(): tramitacao.delete() - return redirect(self.get_success_url()) \ No newline at end of file + return redirect(self.get_success_url()) From 5f9c2d9f8c21218207242207e2bdc12b29aecc84 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Tue, 26 Jun 2018 12:54:47 -0300 Subject: [PATCH 061/107] Fix #2042 (#2045) --- sapl/norma/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sapl/norma/views.py b/sapl/norma/views.py index 650442676..9c98e783e 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -204,9 +204,9 @@ def recuperar_numero_norma(request): param = {'tipo': tipo} param['ano'] = ano if ano else timezone.now().year - - norma = NormaJuridica.objects.filter(**param).order_by( - 'tipo', 'ano', 'numero').values_list('numero', 'ano').last() + norma = NormaJuridica.objects.filter(**param).extra( + {'numero_id': "CAST(numero as INTEGER)"}).order_by( + 'tipo', 'ano','numero_id').values_list('numero', 'ano').last() if norma: response = JsonResponse({'numero': int(norma[0]) + 1, 'ano': norma[1]}) From 4d55e3ae49a134ecad7acdd384e6eb2ddc883511 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Tue, 26 Jun 2018 13:04:09 -0300 Subject: [PATCH 062/107] Fix #2043 (#2044) * Fix #2043 * Update forms.py --- sapl/norma/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index 5e0eb99ff..610895e09 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -125,7 +125,7 @@ class NormaJuridicaForm(ModelForm): if not self.is_valid(): return cleaned_data - if not self.instance: + if self.instance.numero != cleaned_data['numero']: norma = NormaJuridica.objects.filter(ano=cleaned_data['ano'], numero=cleaned_data['numero'], tipo=cleaned_data['tipo']).exists() From c0266626ef5f65f53054396e58c5285394540a4a Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Tue, 26 Jun 2018 15:56:52 -0300 Subject: [PATCH 063/107] =?UTF-8?q?#1784=20-=20Campo=20observa=C3=A7=C3=A3?= =?UTF-8?q?o=20na=20cria=C3=A7=C3=A3o=20de=20partidos=20(#1834)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #1784 * Fix #1784 migrate --- .../migrations/0007_adiciona_partidos.py | 30 ++------------ .../migrations/0022_partido_observacao.py | 20 ++++++++++ .../migrations/0023_auto_20180626_1524.py | 39 +++++++++++++++++++ sapl/parlamentares/models.py | 2 + sapl/templates/parlamentares/layouts.yaml | 1 + 5 files changed, 65 insertions(+), 27 deletions(-) create mode 100644 sapl/parlamentares/migrations/0022_partido_observacao.py create mode 100644 sapl/parlamentares/migrations/0023_auto_20180626_1524.py diff --git a/sapl/parlamentares/migrations/0007_adiciona_partidos.py b/sapl/parlamentares/migrations/0007_adiciona_partidos.py index 336e15d09..bcdb92a29 100644 --- a/sapl/parlamentares/migrations/0007_adiciona_partidos.py +++ b/sapl/parlamentares/migrations/0007_adiciona_partidos.py @@ -1,40 +1,16 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations -import json -import os - - -from django.core.management import call_command +from django.db import migrations - -def gera_partidos_tse(apps, schema_editor): - Partido = apps.get_model("parlamentares", "Partido") - db_alias = schema_editor.connection.alias - partidos = Partido.objects.all().exists() - - if partidos: - # Caso haja algum partido cadastrado na base de dados, - # a migração não deve ser carregada para evitar duplicações de dados. - print("Carga de Partido não efetuada. Já Existem partidos cadastrados...") - else: - fixture_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../fixtures')) - # pega partidos listados em fixtures/pre_popula_partidos.json - fixture_filename = 'pre_popula_partidos.json' - fixture_file = os.path.join(fixture_dir, fixture_filename) - call_command('loaddata', fixture_file) +# Conteúdo removido para bug fix da issue #1784 (https://github.com/interlegis/sapl/issues/1784) +# Conteúdo agora se encontra na migration 0023_auto_20180626_1524.py class Migration(migrations.Migration): dependencies = [ - # A dependencia real desse script é o arquivo 0001_initial.py, mas - # isso gera um erro (Conflicting migrations detected; multiple leaf - # nodes in the migration graph). para não ocasionar problemas de migração, - # vamos manter a ordem padrão do django. ('parlamentares', '0006_auto_20170831_1400'), ] operations = [ - migrations.RunPython(gera_partidos_tse), ] diff --git a/sapl/parlamentares/migrations/0022_partido_observacao.py b/sapl/parlamentares/migrations/0022_partido_observacao.py new file mode 100644 index 000000000..567acf4c7 --- /dev/null +++ b/sapl/parlamentares/migrations/0022_partido_observacao.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-04-06 13:00 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('parlamentares', '0021_clear_thumbnails_cache'), + ] + + operations = [ + migrations.AddField( + model_name='partido', + name='observacao', + field=models.TextField(blank=True, verbose_name='Observação'), + ), + ] diff --git a/sapl/parlamentares/migrations/0023_auto_20180626_1524.py b/sapl/parlamentares/migrations/0023_auto_20180626_1524.py new file mode 100644 index 000000000..828fbe88b --- /dev/null +++ b/sapl/parlamentares/migrations/0023_auto_20180626_1524.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals +from django.db import migrations +import json +import os + + +from django.core.management import call_command + + +def gera_partidos_tse(apps, schema_editor): + Partido = apps.get_model("parlamentares", "Partido") + db_alias = schema_editor.connection.alias + partidos = Partido.objects.all().exists() + + if partidos: + # Caso haja algum partido cadastrado na base de dados, + # a migração não deve ser carregada para evitar duplicações de dados. + print("Carga de Partido não efetuada. Já Existem partidos cadastrados...") + else: + fixture_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../fixtures')) + # pega partidos listados em fixtures/pre_popula_partidos.json + fixture_filename = 'pre_popula_partidos.json' + fixture_file = os.path.join(fixture_dir, fixture_filename) + call_command('loaddata', fixture_file, ignorenonexistent=True) + +class Migration(migrations.Migration): + + dependencies = [ + # A dependencia real desse script é o arquivo 0001_initial.py, mas + # isso gera um erro (Conflicting migrations detected; multiple leaf + # nodes in the migration graph). para não ocasionar problemas de migração, + # vamos manter a ordem padrão do django. + ('parlamentares', '0022_partido_observacao'), + ] + + operations = [ + migrations.RunPython(gera_partidos_tse), + ] diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py index 769093046..19d4fa57c 100644 --- a/sapl/parlamentares/models.py +++ b/sapl/parlamentares/models.py @@ -112,6 +112,8 @@ class Partido(models.Model): upload_to=logo_upload_path, verbose_name=_('Logo Partido'), validators=[restringe_tipos_de_arquivo_img]) + observacao = models.TextField( + blank=True, verbose_name=_('Observação')) class Meta: verbose_name = _('Partido') diff --git a/sapl/templates/parlamentares/layouts.yaml b/sapl/templates/parlamentares/layouts.yaml index 2c21ade8d..ded7ca647 100644 --- a/sapl/templates/parlamentares/layouts.yaml +++ b/sapl/templates/parlamentares/layouts.yaml @@ -14,6 +14,7 @@ Coligacao: Partido: {% trans 'Partido Político' %}: - sigla:2 nome:4 data_criacao data_extincao + - observacao - logo_partido Dependente: From 31ac86e39089f6e0d89d249e884cecf04e596916 Mon Sep 17 00:00:00 2001 From: Edward Date: Wed, 27 Jun 2018 12:14:06 -0300 Subject: [PATCH 064/107] Configura um timeout maior para gunicorn's workers --- gunicorn_start.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gunicorn_start.sh b/gunicorn_start.sh index 4f58022ce..2021aa83e 100755 --- a/gunicorn_start.sh +++ b/gunicorn_start.sh @@ -16,8 +16,9 @@ DJANGODIR=/var/interlegis/sapl/ # Django project directory (* SOCKFILE=/var/interlegis/sapl/run/gunicorn.sock # we will communicate using this unix socket (*) USER=`whoami` # the user to run as (*) GROUP=`whoami` # the group to run as (*) -NUM_WORKERS=4 # how many worker processes should Gunicorn spawn (*) +NUM_WORKERS=9 # how many worker processes should Gunicorn spawn (*) # NUM_WORKERS = 2 * CPUS + 1 +TIMEOUT=60 MAX_REQUESTS=100 # number of requests before restarting worker DJANGO_SETTINGS_MODULE=sapl.settings # which settings file should Django use (*) DJANGO_WSGI_MODULE=sapl.wsgi # WSGI module name (*) @@ -41,6 +42,7 @@ test -d $RUNDIR || mkdir -p $RUNDIR # Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon) exec gunicorn ${DJANGO_WSGI_MODULE}:application \ --name $NAME \ + --timeout $TIMEOUT \ --workers $NUM_WORKERS \ --max-requests $MAX_REQUESTS \ --user $USER \ From c457d18baa3487b12bbc503d1c6bef009fb695be Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Wed, 27 Jun 2018 12:15:39 -0300 Subject: [PATCH 065/107] Release: 3.1.93 --- 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 c33273b3f..0d6b4e9bd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.92 + image: interlegis/sapl:3.1.93 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index b76d46c98..5f475f273 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.92', + version='3.1.93', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 1cc3d1a19ab1069242b67c7a4227d4ced44b1f74 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Wed, 27 Jun 2018 13:52:00 -0300 Subject: [PATCH 066/107] =?UTF-8?q?Corrige=20detec=C3=A7=C3=A3o=20.docx=20?= =?UTF-8?q?na=20exporta=C3=A7=C3=A3o=20do=20zope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 51be333af..bf71d051c 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -79,7 +79,8 @@ def br(obj): def guess_extension(fullname, buffer): - mime = magic.from_buffer(buffer[:1024], mime=True) + # um corte de apenas 1024 impediu a detecção correta de .docx + mime = magic.from_buffer(buffer[:4096], mime=True) extensao = EXTENSOES.get(mime) if extensao is not None: return extensao From c599db3e9edb9c2b3e8e578533fe4cba10ad55ee Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Fri, 29 Jun 2018 14:27:17 -0300 Subject: [PATCH 067/107] Apaga banco antes de migrar flush direto --- sapl/legacy/migracao_dados.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 99d656504..786824880 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -22,6 +22,7 @@ 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.core.management.commands.flush import Command as FlushCommand from django.db import connections, transaction from django.db.models import Max, Q from pyaml import UnsafePrettyYAMLDumper @@ -54,7 +55,6 @@ from .scripts.normaliza_dump_mysql import normaliza_dump_mysql from .timezonesbrasil import get_timezone - # YAML SETUP ############################################################### def dict_representer(dumper, data): return dumper.represent_dict(data.items()) @@ -64,7 +64,7 @@ yaml.add_representer(OrderedDict, dict_representer) # importante para preservar a ordem ao ler yaml no python 3.5 def dict_constructor(loader, node): - return OrderedDict(loader.construct_pairs(node)) + return OrderedDict(loader.construct_pairs(node)) yaml.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, dict_constructor) @@ -830,8 +830,8 @@ def migrar_dados(): # excluindo database antigo. info('Excluindo entradas antigas do banco destino.') - call([PROJECT_DIR.child('manage.py'), 'flush', - '--database=default', '--no-input'], stdout=PIPE) + flush = FlushCommand() + flush.handle(database='default', interactive=False, verbosity=0) # apaga tipos de autor padrão (criados no flush acima) TipoAutor.objects.all().delete() From fd21134dd66d3e0f4bea02d10ee3afcfb7b3b6bc Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 29 Jun 2018 15:59:02 -0300 Subject: [PATCH 068/107] Fix #2046 (#2047) * Fix #2046 * Add requirements --- requirements/requirements.txt | 1 + sapl/settings.py | 1 + sapl/utils.py | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 4b80ad130..6d9d79d66 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -36,3 +36,4 @@ django-reversion==2.0.8 WeasyPrint==0.42 whoosh==2.7.4 django-speedinfo==1.3.5 +django-reversion-compare==0.8.4 diff --git a/sapl/settings.py b/sapl/settings.py index ca24b9f02..72cf086cc 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -87,6 +87,7 @@ INSTALLED_APPS = ( 'sass_processor', 'rest_framework', 'reversion', + 'reversion_compare', 'whoosh', 'speedinfo', diff --git a/sapl/utils.py b/sapl/utils.py index b674481c3..89cf80f94 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -25,6 +25,7 @@ from django_filters.filterset import STRICTNESS from easy_thumbnails import source_generators from floppyforms import ClearableFileInput from reversion.admin import VersionAdmin +from reversion_compare.admin import CompareVersionAdmin from unipath.path import Path from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row @@ -228,7 +229,7 @@ def register_all_models_in_admin(module_name): appname = appname[1] if appname[0] == 'sapl' else appname[0] app = apps.get_app_config(appname) for model in app.get_models(): - class CustomModelAdmin(VersionAdmin): + class CustomModelAdmin(CompareVersionAdmin): list_display = [f.name for f in model._meta.fields if f.name != 'id'] From 8f27a1cee3cfcd95f13a83d9424059a734a9e68c Mon Sep 17 00:00:00 2001 From: Edward Date: Fri, 29 Jun 2018 16:11:35 -0300 Subject: [PATCH 069/107] Fixes #2048 (#2049) --- sapl/materia/forms.py | 6 +++--- sapl/templates/materia/layouts.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 838b8616d..116ecc6b9 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -666,7 +666,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): autoria__primeiro_autor = django_filters.BooleanFilter( required=False, label='Primeiro Autor', - widget=forms.HiddenInput()) + ) ementa = django_filters.CharFilter(lookup_expr='icontains') @@ -724,7 +724,6 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): ('data_publicacao', 6)]) row4 = to_row( [('autoria__autor', 0), - ('autoria__primeiro_autor', 0), (Button('pesquisar', 'Pesquisar Autor', css_class='btn btn-primary btn-sm'), 2), @@ -732,7 +731,8 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): 'limpar Autor', css_class='btn btn-primary btn-sm'), 10)]) row5 = to_row( - [('autoria__autor__tipo', 12), + [('autoria__autor__tipo', 6), + ('autoria__primeiro_autor', 6), # ('autoria__autor__partido', 6) ]) row6 = to_row( diff --git a/sapl/templates/materia/layouts.yaml b/sapl/templates/materia/layouts.yaml index d31817b94..4495b4347 100644 --- a/sapl/templates/materia/layouts.yaml +++ b/sapl/templates/materia/layouts.yaml @@ -23,7 +23,7 @@ MateriaLegislativa: {% trans 'Identificação Básica' %}: - tipo ano numero - data_apresentacao numero_protocolo tipo_apresentacao - - tipo_autor autor + - tipo_autor autoria__primeiro_autor autor - texto_original {% trans 'Outras Informações' %}: - apelido dias_prazo polemica From 6e493ba60b0fd2366a52d9c2a65f0f9d95b50131 Mon Sep 17 00:00:00 2001 From: Talitha Date: Tue, 3 Jul 2018 10:53:17 -0300 Subject: [PATCH 070/107] Revert "Fixes #2048 (#2049)" This reverts commit 8f27a1cee3cfcd95f13a83d9424059a734a9e68c. --- sapl/materia/forms.py | 6 +++--- sapl/templates/materia/layouts.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 116ecc6b9..838b8616d 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -666,7 +666,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): autoria__primeiro_autor = django_filters.BooleanFilter( required=False, label='Primeiro Autor', - ) + widget=forms.HiddenInput()) ementa = django_filters.CharFilter(lookup_expr='icontains') @@ -724,6 +724,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): ('data_publicacao', 6)]) row4 = to_row( [('autoria__autor', 0), + ('autoria__primeiro_autor', 0), (Button('pesquisar', 'Pesquisar Autor', css_class='btn btn-primary btn-sm'), 2), @@ -731,8 +732,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): 'limpar Autor', css_class='btn btn-primary btn-sm'), 10)]) row5 = to_row( - [('autoria__autor__tipo', 6), - ('autoria__primeiro_autor', 6), + [('autoria__autor__tipo', 12), # ('autoria__autor__partido', 6) ]) row6 = to_row( diff --git a/sapl/templates/materia/layouts.yaml b/sapl/templates/materia/layouts.yaml index 4495b4347..d31817b94 100644 --- a/sapl/templates/materia/layouts.yaml +++ b/sapl/templates/materia/layouts.yaml @@ -23,7 +23,7 @@ MateriaLegislativa: {% trans 'Identificação Básica' %}: - tipo ano numero - data_apresentacao numero_protocolo tipo_apresentacao - - tipo_autor autoria__primeiro_autor autor + - tipo_autor autor - texto_original {% trans 'Outras Informações' %}: - apelido dias_prazo polemica From 6000ac3b20efd41dd58e7b5d590451e67ce297de Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 3 Jul 2018 12:56:21 -0300 Subject: [PATCH 071/107] =?UTF-8?q?Corrige=20decodifica=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20assuntos=20de=20norma?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 786824880..ed05b2e90 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -1195,8 +1195,8 @@ def adjust_normajuridica_depois_salvar(): for model in [AssuntoNorma, NormaJuridica]] def filtra_assuntos_migrados(cod_assunto): - return [a for a in map(int, cod_assunto.split(',')) - if a in assuntos_migrados] + cods = {int(a) for a in cod_assunto.split(',') if a} + return cods.intersection(assuntos_migrados) norma_para_assuntos = [ (norma, filtra_assuntos_migrados(cod_assunto)) @@ -1206,7 +1206,7 @@ def adjust_normajuridica_depois_salvar(): ligacao.objects.bulk_create( ligacao(normajuridica_id=norma, assuntonorma_id=assunto) for norma, assuntos in norma_para_assuntos - for assunto in assuntos) + for assunto in sorted(assuntos)) def adjust_autor(new, old): From 7456656535513a5b77997abf1c37f0d5034c0fa2 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 3 Jul 2018 13:16:08 -0300 Subject: [PATCH 072/107] =?UTF-8?q?Corrige=20decodifica=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20assunto=20de=20norma=20nulo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index ed05b2e90..eab699084 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -1195,8 +1195,10 @@ def adjust_normajuridica_depois_salvar(): for model in [AssuntoNorma, NormaJuridica]] def filtra_assuntos_migrados(cod_assunto): + if not cod_assunto: + return [] cods = {int(a) for a in cod_assunto.split(',') if a} - return cods.intersection(assuntos_migrados) + return sorted(cods.intersection(assuntos_migrados)) norma_para_assuntos = [ (norma, filtra_assuntos_migrados(cod_assunto)) @@ -1206,7 +1208,7 @@ def adjust_normajuridica_depois_salvar(): ligacao.objects.bulk_create( ligacao(normajuridica_id=norma, assuntonorma_id=assunto) for norma, assuntos in norma_para_assuntos - for assunto in sorted(assuntos)) + for assunto in assuntos) def adjust_autor(new, old): From 0794e6d0de4e9eef3da079f58aff735157e75f54 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Tue, 3 Jul 2018 15:41:03 -0300 Subject: [PATCH 073/107] =?UTF-8?q?Corrige=20caminhos=20XSLT=20p=20conte?= =?UTF-8?q?=C3=BAdos=20do=20SDE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/scripts/exporta_zope/exporta_zope.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index bf71d051c..f24bdfea5 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -395,13 +395,18 @@ def ajusta_extensao(fullname, conteudo): base, extensao = os.path.splitext(fullname) if extensao not in ['.xsl', '.xslt', '.yaml', '.css']: extensao = guess_extension(fullname, conteudo) - return base + extensao + return base + extensao, extensao def build_salvar(repo): def salvar(fullname, conteudo): - fullname = ajusta_extensao(fullname, conteudo) + fullname, extensao = ajusta_extensao(fullname, conteudo) + + # ajusta caminhos XSLT p conteúdos relacionados ao SDE + if extensao in ['.xsl', '.xslt', '.xml']: + conteudo = conteudo.replace('"XSLT/HTML', '"/XSLT/HTML') + if exists(fullname): # destrava arquivo pré-existente (o conteúdo mudou) repo_execute(repo, 'git annex unlock', fullname) From 74dbdf388193bef6cb98c16a139ad686f1fa69d3 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 4 Jul 2018 19:31:21 -0300 Subject: [PATCH 074/107] Remove rebuild_index e reduz workers gunicorn --- gunicorn_start.sh | 3 ++- start.sh | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gunicorn_start.sh b/gunicorn_start.sh index 2021aa83e..862221a29 100755 --- a/gunicorn_start.sh +++ b/gunicorn_start.sh @@ -16,7 +16,7 @@ DJANGODIR=/var/interlegis/sapl/ # Django project directory (* SOCKFILE=/var/interlegis/sapl/run/gunicorn.sock # we will communicate using this unix socket (*) USER=`whoami` # the user to run as (*) GROUP=`whoami` # the group to run as (*) -NUM_WORKERS=9 # how many worker processes should Gunicorn spawn (*) +NUM_WORKERS=3 # how many worker processes should Gunicorn spawn (*) # NUM_WORKERS = 2 * CPUS + 1 TIMEOUT=60 MAX_REQUESTS=100 # number of requests before restarting worker @@ -42,6 +42,7 @@ test -d $RUNDIR || mkdir -p $RUNDIR # Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon) exec gunicorn ${DJANGO_WSGI_MODULE}:application \ --name $NAME \ + --log-level debug \ --timeout $TIMEOUT \ --workers $NUM_WORKERS \ --max-requests $MAX_REQUESTS \ diff --git a/start.sh b/start.sh index 4790d2df4..9695572ef 100755 --- a/start.sh +++ b/start.sh @@ -49,7 +49,7 @@ create_env # manage.py migrate --noinput nao funcionava yes yes | python3 manage.py migrate #python3 manage.py collectstatic --no-input -python3 manage.py rebuild_index --noinput & +# python3 manage.py rebuild_index --noinput & echo "Criando usuário admin..." From 0e3ba35586565d42959c2244bea285a3c155a10c Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 4 Jul 2018 19:31:39 -0300 Subject: [PATCH 075/107] Release: 3.1.94 --- 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 0d6b4e9bd..f4132d75e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.93 + image: interlegis/sapl:3.1.94 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 5f475f273..20fa9b172 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.93', + version='3.1.94', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 60f27469a99dfb016852fe4f04af77ab079c4e40 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Thu, 5 Jul 2018 12:07:24 -0300 Subject: [PATCH 076/107] Fix #2062 (#2063) --- sapl/base/views.py | 7 +++-- ...latorioMateriasPorAnoAutorTipo_filter.html | 28 +++++++++++++++++-- .../RelatorioMateriasPorAutor_filter.html | 12 +++++++- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/sapl/base/views.py b/sapl/base/views.py index 238252245..b41492f4e 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -420,9 +420,9 @@ class RelatorioMateriasPorAnoAutorTipoView(FilterView): filterset_class = RelatorioMateriasPorAnoAutorTipoFilterSet template_name = 'base/RelatorioMateriasPorAnoAutorTipo_filter.html' - def get_materias_autor_ano(self, ano): + def get_materias_autor_ano(self, ano, primeiro_autor): - autorias = Autoria.objects.filter(materia__ano=ano).values( + autorias = Autoria.objects.filter(materia__ano=ano, primeiro_autor=primeiro_autor).values( 'autor', 'materia__tipo__sigla', 'materia__tipo__descricao').annotate( @@ -488,7 +488,8 @@ class RelatorioMateriasPorAnoAutorTipoView(FilterView): if 'ano' in self.request.GET and self.request.GET['ano']: ano = int(self.request.GET['ano']) - context['relatorio'] = self.get_materias_autor_ano(ano) + context['relatorio'] = self.get_materias_autor_ano(ano, True) + context['corelatorio'] = self.get_materias_autor_ano(ano, False) else: context['relatorio'] = [] diff --git a/sapl/templates/base/RelatorioMateriasPorAnoAutorTipo_filter.html b/sapl/templates/base/RelatorioMateriasPorAnoAutorTipo_filter.html index 43deac36b..890733053 100644 --- a/sapl/templates/base/RelatorioMateriasPorAnoAutorTipo_filter.html +++ b/sapl/templates/base/RelatorioMateriasPorAnoAutorTipo_filter.html @@ -12,7 +12,8 @@ {% trans 'Fazer nova pesquisa' %}



    - +

    Autorias

    +

    {% for r in relatorio %}

    {{r.autor}}


    @@ -35,7 +36,30 @@
    {% endfor %}

    - +

    Coautorias

    +

    + {% for r in corelatorio %} +

    {{r.autor}}


    +
    + + + + + + + + {% for i in r.materia %} + + + + {% endfor %} + +
    Natureza da ProposituraQuantidade
    {{i.0}}{{i.1}}
    +

    Total: {{r.total}}


    +
    +
    + {% endfor %} +

    diff --git a/sapl/templates/base/RelatorioMateriasPorAutor_filter.html b/sapl/templates/base/RelatorioMateriasPorAutor_filter.html index c75aad42b..ec26ecd63 100644 --- a/sapl/templates/base/RelatorioMateriasPorAutor_filter.html +++ b/sapl/templates/base/RelatorioMateriasPorAutor_filter.html @@ -36,7 +36,8 @@ - + + @@ -48,7 +49,16 @@ + From bf0fd4706f071e052b64c0bfeb3578319e09fea7 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Thu, 5 Jul 2018 12:08:18 -0300 Subject: [PATCH 077/107] Release: 3.1.95 --- 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 f4132d75e..893e7c62e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.94 + image: interlegis/sapl:3.1.95 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 20fa9b172..afd1579e3 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.94', + version='3.1.95', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 86ac760c4fe9805dfe24c2d582f18b2fb1594a78 Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 5 Jul 2018 15:39:32 -0300 Subject: [PATCH 078/107] =?UTF-8?q?Resolve=20registros=20de=20vota=C3=A7?= =?UTF-8?q?=C3=A3o=20amb=C3=ADguos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/legacy/migracao_dados.py | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index eab699084..4c953d5f5 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -513,9 +513,10 @@ def checa_registros_votacao_ambiguos_e_remove_nao_usados(): # 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) + if ambiguos: + warn('registro_votacao_ambiguos', + 'Existe(m) RegistroVotacao ambíguo(s): {cod_votacao}', + {'cod_votacao': ambiguos}) # exclui registros não usados (zumbis) todos = set(primeira_coluna(exec_legado( @@ -1109,6 +1110,18 @@ def adjust_protocolo_antes_salvar(new, old): {'cod_protocolo': old.cod_protocolo}) +ARQUIVO_COMO_RESOLVER_REGISTRO_VOTACAO_AMBIGUO = \ + 'como_resolver_registro_votacao_ambiguo.yaml' + + +def get_como_resolver_registro_votacao_ambiguo(): + path = DIR_REPO.child(ARQUIVO_COMO_RESOLVER_REGISTRO_VOTACAO_AMBIGUO) + if path.exists(): + return yaml.load(path.read_file()) + else: + return {} + + def adjust_registrovotacao_antes_salvar(new, old): ordem_dia = OrdemDia.objects.filter( pk=old.cod_ordem, materia=old.cod_materia) @@ -1119,6 +1132,19 @@ def adjust_registrovotacao_antes_salvar(new, old): new.ordem = ordem_dia[0] if not ordem_dia and expediente_materia: new.expediente = expediente_materia[0] + # registro de votação ambíguo + if ordem_dia and expediente_materia: + como_resolver = get_como_resolver_registro_votacao_ambiguo() + campo = como_resolver[new.id] + if campo.startswith('ordem'): + new.ordem = ordem_dia[0] + elif campo.startswith('expediente'): + new.expediente = expediente_materia[0] + else: + raise Exception(''' + Registro de Votação ambíguo: {} + Resolva criando o arquivo {}'''.format( + new.id, ARQUIVO_COMO_RESOLVER_REGISTRO_VOTACAO_AMBIGUO)) def adjust_tipoafastamento(new, old): From e2b31691728e3b163208ab9d8317e94b27e9ae27 Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Fri, 6 Jul 2018 10:10:44 -0300 Subject: [PATCH 079/107] Adiciona teste de audiencia (#2064) --- sapl/audiencia/tests/test_audiencia.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/sapl/audiencia/tests/test_audiencia.py b/sapl/audiencia/tests/test_audiencia.py index 7ce503c2d..710d70dff 100644 --- a/sapl/audiencia/tests/test_audiencia.py +++ b/sapl/audiencia/tests/test_audiencia.py @@ -1,3 +1,25 @@ -from django.test import TestCase +import pytest +from django.utils.translation import ugettext as _ +from model_mommy import mommy -# Create your tests here. +from sapl.audiencia import forms + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_audiencia_form(): + form = forms.AudienciaForm(data={}) + + assert not form.is_valid() + + errors = form.errors + + assert errors['nome'] == [_('Este campo é obrigatório.')] + assert errors['tema'] == [_('Este campo é obrigatório.')] + assert errors['tipo'] == [_('Este campo é obrigatório.')] + assert errors['tipo_materia'] == [_('Este campo é obrigatório.')] + assert errors['numero_materia'] == [_('Este campo é obrigatório.')] + assert errors['ano_materia'] == [_('Este campo é obrigatório.')] + assert errors['data'] == [_('Este campo é obrigatório.')] + assert errors['hora_inicio'] == [_('Este campo é obrigatório.')] + assert errors['hora_fim'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 9 From 40eecaa07cdcb1bb83cca605e5bd076120fc8705 Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Fri, 6 Jul 2018 10:11:00 -0300 Subject: [PATCH 080/107] =?UTF-8?q?HOT-FIX=20-=20Adiciona=20o=20teste=20de?= =?UTF-8?q?=20comiss=C3=A3o=20(#2061)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adiciona teste em test_comissões e corrige mensagem no forms * Corrige erro de admin_client * Adiciona testes referente a reunião de comissão * Adiciona mais testes --- sapl/comissoes/forms.py | 3 +- sapl/comissoes/tests/test_comissoes.py | 48 +++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index 05a0a97b9..75b45c976 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -61,7 +61,8 @@ class PeriodoForm(forms.ModelForm): data_fim = cleaned_data['data_fim'] if data_fim and data_fim < data_inicio: - raise ValidationError('Data início não pode ser superior a data de fim') + raise ValidationError('A Data Final não pode ser menor que ' + 'a Data Inicial') return cleaned_data diff --git a/sapl/comissoes/tests/test_comissoes.py b/sapl/comissoes/tests/test_comissoes.py index fee303192..4d12ba810 100644 --- a/sapl/comissoes/tests/test_comissoes.py +++ b/sapl/comissoes/tests/test_comissoes.py @@ -1,9 +1,11 @@ import pytest from django.core.urlresolvers import reverse +from django.utils.translation import ugettext as _ from model_mommy import mommy -from sapl.comissoes.models import Comissao, Composicao, Periodo, TipoComissao +from sapl.comissoes.models import Comissao, Composicao, Periodo, TipoComissao, Reuniao from sapl.parlamentares.models import Filiacao, Parlamentar, Partido +from sapl.comissoes import forms def make_composicao(comissao): @@ -96,3 +98,47 @@ def test_incluir_comissao_errors(admin_client): ['Este campo é obrigatório.']) assert (response.context_data['form'].errors['data_criacao'] == ['Este campo é obrigatório.']) + + +@pytest.mark.django_db(transaction=False) +def test_periodo_invalidas(): + + form = forms.PeriodoForm(data={'data_inicio': '10/11/2017', + 'data_fim': '09/11/2017' + }) + assert not form.is_valid() + assert form.errors['__all__'] == [_('A Data Final não pode ser menor que ' + 'a Data Inicial')] + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_periodo_form(): + form = forms.PeriodoForm(data={}) + + assert not form.is_valid() + + errors = form.errors + + assert errors['data_inicio'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 1 + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_reuniao_form(): + form = forms.ReuniaoForm(data={}) + + assert not form.is_valid() + + errors = form.errors + + assert errors['comissao'] == [_('Este campo é obrigatório.')] + assert errors['periodo'] == [_('Este campo é obrigatório.')] + assert errors['numero'] == [_('Este campo é obrigatório.')] + assert errors['nome'] == [_('Este campo é obrigatório.')] + assert errors['data'] == [_('Este campo é obrigatório.')] + assert errors['hora_inicio'] == [_('Este campo é obrigatório.')] + assert errors['hora_fim'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 7 + From 79efc588a41a0c7f148f374bede7536118ccd19c Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 6 Jul 2018 10:12:01 -0300 Subject: [PATCH 081/107] Fix #2054 (#2056) --- sapl/relatorios/views.py | 3 ++- sapl/templates/protocoloadm/comprovante.html | 18 +++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py index 0bad27889..28d6010e4 100644 --- a/sapl/relatorios/views.py +++ b/sapl/relatorios/views.py @@ -963,7 +963,8 @@ def get_etiqueta_protocolos(prots): dic['num_documento'] = '' for documento in DocumentoAdministrativo.objects.filter( protocolo=p): - dic['num_documento'] = str(documento) + dic['num_documento'] = documento.tipo.sigla + ' ' + \ + str(documento.numero) + '/' + str(documento.ano) dic['ident_processo'] = dic['num_materia'] or dic['num_documento'] diff --git a/sapl/templates/protocoloadm/comprovante.html b/sapl/templates/protocoloadm/comprovante.html index e4258c263..f4ec4cc62 100644 --- a/sapl/templates/protocoloadm/comprovante.html +++ b/sapl/templates/protocoloadm/comprovante.html @@ -70,15 +70,15 @@ - {% else %} - - - - - - - - + {% else %} + + + + + + + + {% endif %} From 6e42b08fdf01657e0acc71c3ec327ecbd6fea69d Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Fri, 6 Jul 2018 12:12:17 -0100 Subject: [PATCH 082/107] Hot-Fix : Add Testes para MateriaLegislativa (#2053) * Add Testes para MateriaLegislativa * more tests --- sapl/materia/forms.py | 2 +- sapl/materia/tests/test_materia_form.py | 195 ++++++++++++++++++++++++ 2 files changed, 196 insertions(+), 1 deletion(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 838b8616d..fc31c1464 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -270,7 +270,7 @@ class UnidadeTramitacaoForm(ModelForm): del cleaned_data[key] if len(cleaned_data) != 1: - msg = _('Somente um campo deve preenchido!') + msg = _('Somente um campo deve ser preenchido!') raise ValidationError(msg) return cleaned_data diff --git a/sapl/materia/tests/test_materia_form.py b/sapl/materia/tests/test_materia_form.py index 41ad04837..944cabf00 100644 --- a/sapl/materia/tests/test_materia_form.py +++ b/sapl/materia/tests/test_materia_form.py @@ -66,3 +66,198 @@ def test_ficha_seleciona_form_valido(): form = forms.FichaSelecionaForm(data={'materia': str(materia.pk)}) assert form.is_valid() + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_materialegislativa_form(): + form = forms.MateriaLegislativaForm(data={}) + + assert not form.is_valid() + + errors = form.errors + assert errors['tipo'] == [_('Este campo é obrigatório.')] + assert errors['ano'] == [_('Este campo é obrigatório.')] + assert errors['data_apresentacao'] == [_('Este campo é obrigatório.')] + assert errors['numero'] == [_('Este campo é obrigatório.')] + assert errors['ementa'] == [_('Este campo é obrigatório.')] + assert errors['regime_tramitacao'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 6 + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_unidade_tramitacao_form(): + form = forms.UnidadeTramitacaoForm(data={}) + + assert not form.is_valid() + errors = form.errors + + assert errors['__all__'] == [_('Somente um campo deve ser preenchido!')] + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_orgao_form(): + form = forms.OrgaoForm(data={}) + + assert not form.is_valid() + errors = form.errors + + assert errors['nome'] == [_('Este campo é obrigatório.')] + assert errors['sigla'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 2 + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_materia_assunto_form(): + form = forms.MateriaAssuntoForm(data={}) + + assert not form.is_valid() + + errors = form.errors + + assert errors['assunto'] == [_('Este campo é obrigatório.')] + assert errors['materia'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 2 + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_autoria_form(): + form = forms.AutoriaForm(data={},instance=None) + + assert not form.is_valid() + + errors = form.errors + + assert errors['autor'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 1 + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_autoria_multicreate_form(): + form = forms.AutoriaMultiCreateForm(data={}) + + assert not form.is_valid() + + errors = form.errors + + assert errors['__all__'] == [_('Ao menos um autor deve ser selecionado para inclusão')] + + assert len(errors) == 1 + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_tipo_proposicao_form(): + form = forms.TipoProposicaoForm(data={}) + + assert not form.is_valid() + + errors = form.errors + assert errors['tipo_conteudo_related'] == [_('Este campo é obrigatório.')] + assert errors['descricao'] == [_('Este campo é obrigatório.')] + assert errors['content_type'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 3 + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_devolver_proposicao_form(): + form = forms.DevolverProposicaoForm(data={}) + + assert not form.is_valid() + + errors = form.errors + assert errors['__all__'] == [_('Adicione uma Justificativa para devolução.')] + + assert len(errors) == 1 + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_relatoria_form(): + form = forms.RelatoriaForm(data={}) + + assert not form.is_valid() + + errors = form.errors + assert errors['parlamentar'] == [_('Este campo é obrigatório.')] + assert errors['data_designacao_relator'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 2 + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_tramitacao_form(): + form = forms.TramitacaoForm(data={}) + + assert not form.is_valid() + + errors = form.errors + + assert errors['unidade_tramitacao_local'] == [_('Este campo é obrigatório.')] + assert errors['texto'] == [_('Este campo é obrigatório.')] + assert errors['status'] == [_('Este campo é obrigatório.')] + assert errors['data_tramitacao'] == [_('Este campo é obrigatório.')] + assert errors['unidade_tramitacao_destino'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 5 + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_tramitacao_update_form(): + form = forms.TramitacaoUpdateForm(data={}) + + assert not form.is_valid() + + errors = form.errors + + assert errors['unidade_tramitacao_local'] == [_('Este campo é obrigatório.')] + assert errors['texto'] == [_('Este campo é obrigatório.')] + assert errors['status'] == [_('Este campo é obrigatório.')] + assert errors['data_tramitacao'] == [_('Este campo é obrigatório.')] + assert errors['unidade_tramitacao_destino'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 5 + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_legislacao_citada_form(): + form = forms.LegislacaoCitadaForm(data={}) + + assert not form.is_valid() + + errors = form.errors + assert errors['tipo'] == [_('Este campo é obrigatório.')] + assert errors['ano'] == [_('Este campo é obrigatório.')] + assert errors['numero'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 3 + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_numeracao_form(): + form = forms.NumeracaoForm(data={}) + + assert not form.is_valid() + + errors = form.errors + + assert errors['tipo_materia'] == [_('Este campo é obrigatório.')] + assert errors['ano_materia'] == [_('Este campo é obrigatório.')] + assert errors['numero_materia'] == [_('Este campo é obrigatório.')] + assert errors['data_materia'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 4 + + +@pytest.mark.django_db(transaction=False) +def test_valida_campos_obrigatorios_anexada_form(): + form = forms.AnexadaForm(data={}) + + assert not form.is_valid() + + errors = form.errors + + assert errors['tipo'] == [_('Este campo é obrigatório.')] + assert errors['ano'] == [_('Este campo é obrigatório.')] + assert errors['numero'] == [_('Este campo é obrigatório.')] + assert errors['data_anexacao'] == [_('Este campo é obrigatório.')] + + assert len(errors) == 4 From c510b3bd7899fedd2e5371c5b7c3a64b258af605 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 6 Jul 2018 10:12:36 -0300 Subject: [PATCH 083/107] Fix #2058 (#2059) --- sapl/materia/views.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 6f0b35ef8..14f77b7d0 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -700,12 +700,15 @@ 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 - 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))) + try: + Numero = MateriaLegislativa.objects.filter(tipo=p.tipo.tipo_conteudo_related, + ano=p.ano).last().numero + 1 + messages.success(request, _( + '%s : nº %s de %s
    Atenção! Este número é apenas um provável ' + 'número que pode não corresponder com a realidade' + % (p.tipo, Numero, p.ano))) + except ValueError: + pass elif action == 'return': if not p.data_envio: From 98e5faab2d387bb2ac914411a4a4f516da6716ab Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Fri, 6 Jul 2018 10:14:32 -0300 Subject: [PATCH 084/107] fix #2057 (#2060) --- sapl/templates/norma/layouts.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/templates/norma/layouts.yaml b/sapl/templates/norma/layouts.yaml index e1ca61084..a06b80b2b 100644 --- a/sapl/templates/norma/layouts.yaml +++ b/sapl/templates/norma/layouts.yaml @@ -45,7 +45,7 @@ LegislacaoCitada: LegislacaoCitadaDetail: {% trans 'Legislação Citada' %}: - - norma + - norma|fk_urlize_for_detail - disposicoes parte livro titulo - capitulo secao subsecao artigo - paragrafo inciso alinea item From 4f1b7a36badc2fae1287c6e603a853385241ab2b Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 10 Jul 2018 13:23:25 -0300 Subject: [PATCH 085/107] Fixes #2065 (#2066) --- sapl/protocoloadm/forms.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 8502bf334..e7b418253 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -708,10 +708,10 @@ class DocumentoAdministrativoForm(ModelForm): ano=ano_protocolo).exists() exist_doc = DocumentoAdministrativo.objects.filter( - protocolo_id=numero_protocolo, - ano=ano_protocolo).exists() + protocolo__numero=numero_protocolo, + protocolo__ano=ano_protocolo).exists() if exist_materia or exist_doc: - raise ValidationError(_('Protocolo %s/%s ja possui' + raise ValidationError(_('Protocolo %s/%s já possui' ' documento vinculado' % (numero_protocolo, ano_protocolo))) From a8206bc7f35b3dcb324a9205335a7e7cb7f58031 Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Tue, 10 Jul 2018 14:09:00 -0300 Subject: [PATCH 086/107] Hot Fix: error_message usuario parlamentar votante (#2067) * Fix error_message usuario votante nao cadastrado * update painel/view.py --- sapl/painel/views.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sapl/painel/views.py b/sapl/painel/views.py index a185fed3b..847518898 100644 --- a/sapl/painel/views.py +++ b/sapl/painel/views.py @@ -85,10 +85,16 @@ def votacao_aberta(request): def votante_view(request): # Pega o votante relacionado ao usuário template_name = 'painel/voto_nominal.html' + context = {} try: votante = Votante.objects.get(user=request.user) except ObjectDoesNotExist: - raise Http404() + msg = _("Usuário não cadastrado como votante na tela de parlamentares. Contate a administração de sua Casa Legislativa!") + context.update({ + 'error_message':msg + }) + + return render(request, template_name, context) context = {'head_title': str(_('Votação Individual'))} From 41d8ff45c38851b3634c3eefcd1ffb87a1e5c871 Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 10 Jul 2018 14:09:15 -0300 Subject: [PATCH 087/107] Fixes #2069 (#2070) --- sapl/relatorios/templates/pdf_etiqueta_protocolo_gerar.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sapl/relatorios/templates/pdf_etiqueta_protocolo_gerar.py b/sapl/relatorios/templates/pdf_etiqueta_protocolo_gerar.py index 38057791f..8b9c3b2cc 100755 --- a/sapl/relatorios/templates/pdf_etiqueta_protocolo_gerar.py +++ b/sapl/relatorios/templates/pdf_etiqueta_protocolo_gerar.py @@ -98,7 +98,11 @@ def protocolos(lst_protocolos, dic_cabecalho): tmp_data += '\t\t' + \ dic['natureza'] if dic['ident_processo']: - tmp_data += ' - ' + dic['ident_processo'] + '\n' + # Limita o tamanho do texto para não "explodir" as etiquetas + descricao = dic['ident_processo'][:60] + if len(dic['ident_processo']) > 60: + descricao += '...' + tmp_data += ' - ' + descricao + '\n' else: tmp_data += '\n' From 5bb573e81b81cb42bf530db485b4e9872c6d888d Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 10 Jul 2018 14:13:42 -0300 Subject: [PATCH 088/107] Release: 3.1.96 --- 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 893e7c62e..ccf3ed7ab 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.95 + image: interlegis/sapl:3.1.96 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index afd1579e3..0fbba0cce 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.95', + version='3.1.96', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 4dd3a55ae3274099559057172c6d40f0728451ee Mon Sep 17 00:00:00 2001 From: Talitha Pumar Date: Tue, 10 Jul 2018 14:29:44 -0300 Subject: [PATCH 089/107] Update forms.py (#2071) --- sapl/base/forms.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index e60ffe072..ea0f628a3 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -44,7 +44,9 @@ STATUS_USER_CHOICE = [ def get_roles(): - return [(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') + if g.name != 'Votante' and g.name != 'Autor'] + return roles class UsuarioCreateForm(ModelForm): From ed0e1f2bb125bd109ff7ae4aa2e998c7d5a90446 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 11 Jul 2018 13:52:10 -0300 Subject: [PATCH 090/107] =?UTF-8?q?HOT-FIX:=20usu=C3=A1rio=20estourando=20?= =?UTF-8?q?limite=20de=20campo=20em=20User?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/base/forms.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index ea0f628a3..de6b50403 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -51,11 +51,14 @@ def get_roles(): 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') + username = forms.CharField(required=True, label="Nome de usuário", + max_length=30) + firstname = forms.CharField(required=True, label="Nome", max_length=30) + lastname = forms.CharField(required=True, label="Sobrenome", max_length=30) + password1 = forms.CharField(required=True, widget=forms.PasswordInput, + label='Senha', max_length=128) + password2 = forms.CharField(required=True, widget=forms.PasswordInput, + label='Confirmar senha', max_length=128) user_active = forms.ChoiceField(required=False, choices=YES_NO_CHOICES, label="Usuário ativo?", initial='True') From 2cbf50c1be4723b9bed71f1c1c3d972c4f10fa2a Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 11 Jul 2018 13:53:04 -0300 Subject: [PATCH 091/107] Release: 3.1.97 --- 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 ccf3ed7ab..8282fd240 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.96 + image: interlegis/sapl:3.1.97 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 0fbba0cce..078f5f3e5 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.96', + version='3.1.97', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 56ed200efb03790140483123fd5af8bf791e8b5b Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 12 Jul 2018 12:24:32 -0300 Subject: [PATCH 092/107] Release: 3.1.98 --- 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 8282fd240..9f3c96563 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.97 + image: interlegis/sapl:3.1.98 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 078f5f3e5..285c277a6 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.97', + version='3.1.98', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 06e5f72c5dabbe558aa531973ca7c06217544f13 Mon Sep 17 00:00:00 2001 From: Edward Date: Thu, 12 Jul 2018 15:29:33 -0300 Subject: [PATCH 093/107] Fixes #2072 (#2075) --- sapl/comissoes/forms.py | 2 +- sapl/templates/norma/normajuridica_filter.html | 12 ++++++++++++ sapl/templates/norma/normajuridica_form.html | 9 +++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index 75b45c976..db1822e4a 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -100,7 +100,7 @@ class ParticipacaoCreateForm(forms.ModelForm): exclude(id__in=id_part) eligible = self.verifica() result = list(set(qs) & set(eligible)) - if not cmp(result, eligible): # se igual a 0 significa que o qs e o eli são iguais! + if result == eligible: self.fields['parlamentar'].queryset = qs else: ids = [e.id for e in eligible] diff --git a/sapl/templates/norma/normajuridica_filter.html b/sapl/templates/norma/normajuridica_filter.html index 511f20a01..fcc176eda 100644 --- a/sapl/templates/norma/normajuridica_filter.html +++ b/sapl/templates/norma/normajuridica_filter.html @@ -84,6 +84,18 @@

    Nenhuma norma encontrada com essas especificações

    {% endif %} {% endif %} + + {% endblock detail_content %} {% block table_content %} diff --git a/sapl/templates/norma/normajuridica_form.html b/sapl/templates/norma/normajuridica_form.html index 9c4772a80..58a48046a 100644 --- a/sapl/templates/norma/normajuridica_form.html +++ b/sapl/templates/norma/normajuridica_form.html @@ -41,6 +41,15 @@ for (i = 0; i < fields.length; i++) { $(fields[i]).change(recuperar_norma); } + + var numeroField = $("#id_numero"); + + numeroField.keyup(function() { + var numero = numeroField.val(); + if (numero.startsWith("0")) { + numeroField.val(numero.replace(/^0+/, '')); + } + }); {% endblock %} From 4eb5ee8a1cdbaff8f21b921339348b62268b8237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Sconetto?= Date: Thu, 12 Jul 2018 15:35:29 -0300 Subject: [PATCH 094/107] Fix #2073 (#2074) --- sapl/templates/materia/layouts.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/templates/materia/layouts.yaml b/sapl/templates/materia/layouts.yaml index d31817b94..7c0c17e4e 100644 --- a/sapl/templates/materia/layouts.yaml +++ b/sapl/templates/materia/layouts.yaml @@ -100,7 +100,7 @@ Proposicao: StatusTramitacao: {% trans 'Status Tramitação' %}: - - indicador:3 sigla:2 descricao + - sigla:2 descricao:6 indicador:4 UnidadeTramitacao: {% trans 'Unidade Tramitação' %}: From 1a3b2a6fcd7877946fb6bdf2427fc8681a68f394 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 12 Jul 2018 16:06:05 -0300 Subject: [PATCH 095/107] Issue #2055 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A reindexação causa um estouro de memória nos containers Docker. Enquanto não solucionamos esse problema é melhor desabilitar a busca textual e retirar os botões referentes a ela da tela. Assim que resolvermos o problema voltamos com eles. --- sapl/templates/materia/materialegislativa_filter.html | 3 ++- sapl/templates/norma/normajuridica_filter.html | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sapl/templates/materia/materialegislativa_filter.html b/sapl/templates/materia/materialegislativa_filter.html index f44d8788b..1f96b1ab6 100644 --- a/sapl/templates/materia/materialegislativa_filter.html +++ b/sapl/templates/materia/materialegislativa_filter.html @@ -4,9 +4,10 @@ {% block actions %}
    + {% if perms.materia.add_materialegislativa %} diff --git a/sapl/templates/norma/normajuridica_filter.html b/sapl/templates/norma/normajuridica_filter.html index fcc176eda..8119ce4d1 100644 --- a/sapl/templates/norma/normajuridica_filter.html +++ b/sapl/templates/norma/normajuridica_filter.html @@ -4,9 +4,11 @@ {% block actions %}
    + {% if perms.norma.add_normajuridica %} From 6008bfc193616b17acbc855100fe6ad47006cc13 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 12 Jul 2018 16:08:03 -0300 Subject: [PATCH 096/107] Release: 3.1.99 --- 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 9f3c96563..7235079c9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.98 + image: interlegis/sapl:3.1.99 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 285c277a6..1a21b5d5e 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.98', + version='3.1.99', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From bd5714311eed4bd5afbfd275109b8a92c540c471 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Mon, 16 Jul 2018 17:57:40 -0300 Subject: [PATCH 097/107] Release: 3.1.100 --- 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 7235079c9..4008155c8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.99 + image: interlegis/sapl:3.1.100 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 1a21b5d5e..930daf046 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.99', + version='3.1.100', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 7a93cb417d687951f669cfe995c7e47377f84817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Sconetto?= Date: Tue, 17 Jul 2018 15:08:58 -0300 Subject: [PATCH 098/107] =?UTF-8?q?Corrige=20apresenta=C3=A7=C3=A3o=20da?= =?UTF-8?q?=20data=20de=20vota=C3=A7=C3=A3o=20das=20mat=C3=A9rias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/templates/materia/materialegislativa_filter.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/templates/materia/materialegislativa_filter.html b/sapl/templates/materia/materialegislativa_filter.html index 1f96b1ab6..b10c20346 100644 --- a/sapl/templates/materia/materialegislativa_filter.html +++ b/sapl/templates/materia/materialegislativa_filter.html @@ -83,11 +83,11 @@ {% for rv in m.registrovotacao_set.all %} {% if rv.ordem %} - {{ rv.ordem.data_ordem }} + {{ rv.ordem.sessao_plenaria.data_inicio }} {% elif rv.expediente %} - {{ rv.expediente.data_ordem }} + {{ rv.expediente.sessao_plenaria.data_inicio }} {% endif %}
    From feb09069a51e2168d55924997caf43838997452b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Sconetto?= Date: Tue, 17 Jul 2018 15:11:08 -0300 Subject: [PATCH 099/107] Release: 3.1.101 --- 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 4008155c8..913399536 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.100 + image: interlegis/sapl:3.1.101 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 930daf046..493513458 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.100', + version='3.1.101', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 5bd0f53d0d3d744fd0d4cac0b4d142de199bda65 Mon Sep 17 00:00:00 2001 From: Mariana Mendes Date: Tue, 17 Jul 2018 15:18:29 -0300 Subject: [PATCH 100/107] fix #2078 (#2079) * Fix #2078 * fix #2078 --- .../migrations/0017_auto_20180717_0827.py | 20 +++++++++++++++++++ sapl/comissoes/models.py | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 sapl/comissoes/migrations/0017_auto_20180717_0827.py diff --git a/sapl/comissoes/migrations/0017_auto_20180717_0827.py b/sapl/comissoes/migrations/0017_auto_20180717_0827.py new file mode 100644 index 000000000..496a76b97 --- /dev/null +++ b/sapl/comissoes/migrations/0017_auto_20180717_0827.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-07-17 11:27 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0016_auto_20180613_2121'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='observacao', + field=models.TextField(blank=True, verbose_name='Observação'), + ), + ] diff --git a/sapl/comissoes/models.py b/sapl/comissoes/models.py index a2477ef1d..4c8c09393 100644 --- a/sapl/comissoes/models.py +++ b/sapl/comissoes/models.py @@ -223,7 +223,7 @@ class Reuniao(models.Model): 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')) + 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)')) From b127eea4ef80dc33bf3d1021fd95f3b4206d309f Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 17 Jul 2018 17:04:05 -0300 Subject: [PATCH 101/107] Refactorings e code fixes --- sapl/materia/views.py | 2 +- sapl/relatorios/templates/pdf_capa_processo_preparar_pysc.py | 2 +- sapl/relatorios/templates/pdf_detalhe_materia_preparar_pysc.py | 2 +- .../templates/pdf_documento_administrativo_preparar_pysc.py | 2 +- sapl/relatorios/templates/pdf_espelho_preparar_pysc.py | 2 +- .../templates/pdf_etiqueta_protocolo_preparar_pysc.py | 2 +- sapl/relatorios/templates/pdf_materia_preparar_pysc.py | 2 +- sapl/relatorios/templates/pdf_norma_preparar_pysc.py | 2 +- sapl/relatorios/templates/pdf_ordem_dia_preparar_pysc.py | 2 +- sapl/relatorios/templates/pdf_pauta_sessao_preparar_pysc.py | 2 +- sapl/relatorios/templates/pdf_protocolo_preparar_pysc.py | 2 +- sapl/relatorios/templates/pdf_sessao_plenaria_preparar_pysc.py | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 14f77b7d0..e81aa4953 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -860,7 +860,7 @@ class ProposicaoCrud(Crud): else: obj.data_recebimento = timezone.localtime( obj.data_recebimento) - obj.data_recebimento = obj.data_recebimento = formats.date_format( + obj.data_recebimento = formats.date_format( obj.data_recebimento, "DATETIME_FORMAT") if obj.data_envio is None: obj.data_envio = 'Em elaboração...' diff --git a/sapl/relatorios/templates/pdf_capa_processo_preparar_pysc.py b/sapl/relatorios/templates/pdf_capa_processo_preparar_pysc.py index eacabf86e..4e741e564 100755 --- a/sapl/relatorios/templates/pdf_capa_processo_preparar_pysc.py +++ b/sapl/relatorios/templates/pdf_capa_processo_preparar_pysc.py @@ -144,6 +144,6 @@ sessao = session.id caminho = context.pdf_capa_processo_gerar( sessao, imagem, data, protocolos, cabecalho, rodape, filtro) if caminho == 'aviso': - return response.redirect('mensagem_emitir_proc') + response.redirect('mensagem_emitir_proc') else: response.redirect(caminho) diff --git a/sapl/relatorios/templates/pdf_detalhe_materia_preparar_pysc.py b/sapl/relatorios/templates/pdf_detalhe_materia_preparar_pysc.py index ebe3be006..19d6271bc 100644 --- a/sapl/relatorios/templates/pdf_detalhe_materia_preparar_pysc.py +++ b/sapl/relatorios/templates/pdf_detalhe_materia_preparar_pysc.py @@ -279,6 +279,6 @@ caminho = context.pdf_detalhe_materia_gerar(imagem, rodape, inf_basicas_dic, ori lst_des_iniciais, dic_tramitacoes, lst_relatorias, lst_numeracoes, lst_legis_citadas, lst_acessorios, sessao=session.id) if caminho == 'aviso': - return response.redirect('mensagem_emitir_proc') + response.redirect('mensagem_emitir_proc') else: response.redirect(caminho) diff --git a/sapl/relatorios/templates/pdf_documento_administrativo_preparar_pysc.py b/sapl/relatorios/templates/pdf_documento_administrativo_preparar_pysc.py index cbaf7d0e3..775ad3d68 100755 --- a/sapl/relatorios/templates/pdf_documento_administrativo_preparar_pysc.py +++ b/sapl/relatorios/templates/pdf_documento_administrativo_preparar_pysc.py @@ -130,6 +130,6 @@ sessao = session.id caminho = context.pdf_documento_administrativo_gerar( sessao, imagem, data, documentos, cabecalho, rodape, filtro) if caminho == 'aviso': - return response.redirect('mensagem_emitir_proc') + response.redirect('mensagem_emitir_proc') else: response.redirect(caminho) diff --git a/sapl/relatorios/templates/pdf_espelho_preparar_pysc.py b/sapl/relatorios/templates/pdf_espelho_preparar_pysc.py index e51fcd43c..43fae0f7c 100644 --- a/sapl/relatorios/templates/pdf_espelho_preparar_pysc.py +++ b/sapl/relatorios/templates/pdf_espelho_preparar_pysc.py @@ -205,6 +205,6 @@ sessao = session.id caminho = context.pdf_espelho_gerar( sessao, imagem, data, materias, cabecalho, rodape, filtro) if caminho == 'aviso': - return response.redirect('mensagem_emitir_proc') + response.redirect('mensagem_emitir_proc') else: response.redirect(caminho) diff --git a/sapl/relatorios/templates/pdf_etiqueta_protocolo_preparar_pysc.py b/sapl/relatorios/templates/pdf_etiqueta_protocolo_preparar_pysc.py index ee9b97330..29ce497b3 100755 --- a/sapl/relatorios/templates/pdf_etiqueta_protocolo_preparar_pysc.py +++ b/sapl/relatorios/templates/pdf_etiqueta_protocolo_preparar_pysc.py @@ -132,6 +132,6 @@ sessao = session.id caminho = context.pdf_etiqueta_protocolo_gerar( sessao, imagem, data, protocolos, cabecalho, rodape, filtro) if caminho == 'aviso': - return response.redirect('mensagem_emitir_proc') + response.redirect('mensagem_emitir_proc') else: response.redirect(caminho) diff --git a/sapl/relatorios/templates/pdf_materia_preparar_pysc.py b/sapl/relatorios/templates/pdf_materia_preparar_pysc.py index 30ddaef9b..95a0b6192 100644 --- a/sapl/relatorios/templates/pdf_materia_preparar_pysc.py +++ b/sapl/relatorios/templates/pdf_materia_preparar_pysc.py @@ -164,6 +164,6 @@ sessao = session.id caminho = context.pdf_materia_gerar( sessao, imagem, data, materias, cabecalho, rodape, filtro) if caminho == 'aviso': - return response.redirect('mensagem_emitir_proc') + response.redirect('mensagem_emitir_proc') else: response.redirect(caminho) diff --git a/sapl/relatorios/templates/pdf_norma_preparar_pysc.py b/sapl/relatorios/templates/pdf_norma_preparar_pysc.py index c8b5b056c..047f04e21 100755 --- a/sapl/relatorios/templates/pdf_norma_preparar_pysc.py +++ b/sapl/relatorios/templates/pdf_norma_preparar_pysc.py @@ -100,6 +100,6 @@ sessao = session.id caminho = context.pdf_norma_gerar( sessao, imagem, data, normas, cabecalho, rodape, filtro) if caminho == 'aviso': - return response.redirect('mensagem_emitir_proc') + response.redirect('mensagem_emitir_proc') else: response.redirect(caminho) diff --git a/sapl/relatorios/templates/pdf_ordem_dia_preparar_pysc.py b/sapl/relatorios/templates/pdf_ordem_dia_preparar_pysc.py index 4e765239f..79281beed 100644 --- a/sapl/relatorios/templates/pdf_ordem_dia_preparar_pysc.py +++ b/sapl/relatorios/templates/pdf_ordem_dia_preparar_pysc.py @@ -155,6 +155,6 @@ if context.REQUEST['cod_sessao_plen'] != '': caminho = context.pdf_ordem_dia_gerar( sessao, imagem, dat_ordem, splen, pauta, cabecalho, rodape) if caminho == 'aviso': - return response.redirect('mensagem_emitir_proc') + response.redirect('mensagem_emitir_proc') else: response.redirect(caminho) diff --git a/sapl/relatorios/templates/pdf_pauta_sessao_preparar_pysc.py b/sapl/relatorios/templates/pdf_pauta_sessao_preparar_pysc.py index d76545371..914f77a7b 100755 --- a/sapl/relatorios/templates/pdf_pauta_sessao_preparar_pysc.py +++ b/sapl/relatorios/templates/pdf_pauta_sessao_preparar_pysc.py @@ -184,6 +184,6 @@ if context.REQUEST['data'] != '': caminho = context.pdf_pauta_sessao_gerar( rodape, sessao, imagem, inf_basicas_dic, lst_votacao, lst_expediente_materia) if caminho == 'aviso': - return response.redirect('mensagem_emitir_proc') + response.redirect('mensagem_emitir_proc') else: response.redirect(caminho) diff --git a/sapl/relatorios/templates/pdf_protocolo_preparar_pysc.py b/sapl/relatorios/templates/pdf_protocolo_preparar_pysc.py index 9a3a0d383..4a1593184 100755 --- a/sapl/relatorios/templates/pdf_protocolo_preparar_pysc.py +++ b/sapl/relatorios/templates/pdf_protocolo_preparar_pysc.py @@ -121,6 +121,6 @@ sessao = session.id caminho = context.pdf_protocolo_gerar( sessao, imagem, data, protocolos, cabecalho, rodape, filtro) if caminho == 'aviso': - return response.redirect('mensagem_emitir_proc') + response.redirect('mensagem_emitir_proc') else: response.redirect(caminho) diff --git a/sapl/relatorios/templates/pdf_sessao_plenaria_preparar_pysc.py b/sapl/relatorios/templates/pdf_sessao_plenaria_preparar_pysc.py index b8f7adda2..5eef2d912 100644 --- a/sapl/relatorios/templates/pdf_sessao_plenaria_preparar_pysc.py +++ b/sapl/relatorios/templates/pdf_sessao_plenaria_preparar_pysc.py @@ -279,6 +279,6 @@ if context.REQUEST['data'] != '': caminho = context.pdf_sessao_plenaria_gerar(rodape, sessao, imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao, lst_expedientes, lst_expediente_materia, lst_oradores_expediente, lst_presenca_ordem_dia, lst_votacao, lst_oradores) if caminho == 'aviso': - return response.redirect('mensagem_emitir_proc') + response.redirect('mensagem_emitir_proc') else: response.redirect(caminho) From c0a8a7acf87249b71b312e6736c5d1f6d9ccde61 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 20 Jul 2018 14:05:44 -0300 Subject: [PATCH 102/107] Fix #2081 (#2083) * Fix #2081 * HOT-FIX --- sapl/materia/views.py | 45 ++++++++++++++++++---- sapl/templates/materia/relatoria_form.html | 2 +- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index e81aa4953..f2e3e76db 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -940,8 +940,9 @@ class RelatoriaCrud(MasterDetailCrud): try: comissao = Comissao.objects.get( pk=context['form'].initial['comissao']) - except ObjectDoesNotExist: + except: pass + else: composicao = comissao.composicao_set.order_by( '-periodo__data_inicio').first() @@ -1778,17 +1779,47 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) - if request.POST['data_encaminhamento']: + if request.POST['status'] == '': + msg = _('Campo Status deve ser preenchido.') + messages.add_message(request, messages.ERROR, msg) + return self.get(request, self.kwargs) + + if request.POST['unidade_tramitacao_local'] == '': + msg = _('Campo Unidade Local deve ser preenchido.') + messages.add_message(request, messages.ERROR, msg) + return self.get(request, self.kwargs) + + if request.POST['data_tramitacao'] == '': + msg = _('Campo Data da Tramitação deve ser preenchido.') + messages.add_message(request, messages.ERROR, msg) + return self.get(request, self.kwargs) + + if request.POST['unidade_tramitacao_destino'] == '': + msg = _('Campo Unidade Destino deve ser preenchido.') + messages.add_message(request, messages.ERROR, msg) + return self.get(request, self.kwargs) + + if request.POST['urgente'] == '': + msg = _('Campo Urgente deve ser preenchido.') + messages.add_message(request, messages.ERROR, msg) + return self.get(request, self.kwargs) + + if request.POST['texto'] == '': + msg = _('Campo Texto da Ação deve ser preenchido.') + messages.add_message(request, messages.ERROR, msg) + return self.get(request, self.kwargs) + + if request.POST['data_encaminhamento'] == '': + data_encaminhamento = None + else: data_encaminhamento = tz.localize(datetime.strptime( request.POST['data_encaminhamento'], "%d/%m/%Y")) - else: - data_encaminhamento = None - if request.POST['data_fim_prazo']: + if request.POST['data_fim_prazo'] == '': + data_fim_prazo = None + else: data_fim_prazo = tz.localize(datetime.strptime( request.POST['data_fim_prazo'], "%d/%m/%Y")) - else: - data_fim_prazo = None # issue https://github.com/interlegis/sapl/issues/1123 # TODO: usar Form diff --git a/sapl/templates/materia/relatoria_form.html b/sapl/templates/materia/relatoria_form.html index f8fbdaf5e..34cffd3db 100644 --- a/sapl/templates/materia/relatoria_form.html +++ b/sapl/templates/materia/relatoria_form.html @@ -6,7 +6,7 @@ {% block base_content %} {% if form.comissao.value == 0 %} {% else %} {% crispy form %} From 759a902f344ed535b2a2f10b31ba758dfc8bb7e0 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Fri, 20 Jul 2018 14:12:18 -0300 Subject: [PATCH 103/107] HOT-FIX: corrige erro ao protocolar pela primeira vez --- sapl/protocoloadm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index c1a2b185a..4a4115f69 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -307,7 +307,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, protocolo.anulado = False if not protocolo.numero: protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 - if protocolo.numero < (numero['numero__max'] + 1): + elif protocolo.numero < (numero['numero__max'] + 1) if numero['numero__max'] else 0: msg = _('Número de protocolo deve ser maior que {}').format(numero['numero__max']) messages.add_message(self.request, messages.ERROR, msg) return self.render_to_response(self.get_context_data()) From 35d4afb64db7255769a03fa3d394194a62253b1c Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 20 Jul 2018 15:14:26 -0300 Subject: [PATCH 104/107] Fix #2076 (#2080) * Fix #2076 * HOT-FIX: melhora codigo --- sapl/materia/forms.py | 8 ++--- sapl/protocoloadm/forms.py | 32 +++++++++++++++++++ sapl/protocoloadm/views.py | 26 +++++++++++++-- .../documentoadministrativo_filter.html | 19 +++++++++-- 4 files changed, 75 insertions(+), 10 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index fc31c1464..97d7156b5 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -766,14 +766,10 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): def pega_ultima_tramitacao(): - ultimas_tramitacoes = Tramitacao.objects.values( + return Tramitacao.objects.values( 'materia_id').annotate(data_encaminhamento=Max( 'data_encaminhamento'), - id=Max('id')).values_list('id') - - lista = [item for sublist in ultimas_tramitacoes for item in sublist] - - return lista + id=Max('id')).values_list('id', flat=True) def filtra_tramitacao_status(status): diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index e7b418253..22e649459 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -7,6 +7,7 @@ from django import forms from django.core.exceptions import (MultipleObjectsReturned, ObjectDoesNotExist, ValidationError) from django.db import models +from django.db.models import Max from django.forms import ModelForm from django.utils import timezone from django.utils.translation import ugettext_lazy as _ @@ -873,3 +874,34 @@ class DesvincularMateriaForm(forms.Form): form_actions(label='Desvincular') ) ) + + +def pega_ultima_tramitacao_adm(): + return TramitacaoAdministrativo.objects.values( + 'materia_id').annotate(data_encaminhamento=Max( + 'data_encaminhamento'), + id=Max('id')).values_list('id', flat=True) + + +def filtra_tramitacao_adm_status(status): + lista = pega_ultima_tramitacao_adm() + return TramitacaoAdministrativo.objects.filter( + id__in=lista, + status=status).distinct().values_list('materia_id', flat=True) + + +def filtra_tramitacao_adm_destino(destino): + lista = pega_ultima_tramitacao_adm() + return TramitacaoAdministrativo.objects.filter( + id__in=lista, + unidade_tramitacao_destino=destino).distinct().values_list( + 'materia_id', flat=True) + + +def filtra_tramitacao_adm_destino_and_status(status, destino): + lista = pega_ultima_tramitacao_adm() + return TramitacaoAdministrativo.objects.filter( + id__in=lista, + status=status, + unidade_tramitacao_destino=destino).distinct().values_list( + 'materia_id', flat=True) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 4a4115f69..3350c81cf 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -31,7 +31,8 @@ from .forms import (AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm, DocumentoAdministrativoFilterSet, DocumentoAdministrativoForm, ProtocoloDocumentForm, ProtocoloFilterSet, ProtocoloMateriaForm, - TramitacaoAdmEditForm, TramitacaoAdmForm, DesvincularDocumentoForm, DesvincularMateriaForm) + TramitacaoAdmEditForm, TramitacaoAdmForm, DesvincularDocumentoForm, DesvincularMateriaForm, + filtra_tramitacao_adm_destino_and_status, filtra_tramitacao_adm_destino, filtra_tramitacao_adm_status) from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo, StatusTramitacaoAdministrativo, TipoDocumentoAdministrativo, TramitacaoAdministrativo) @@ -543,13 +544,34 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin, kwargs = {'data': self.request.GET or None} + status_tramitacao = self.request.GET.get('tramitacao__status') + unidade_destino = self.request.GET.get( + 'tramitacao__unidade_tramitacao_destino') + qs = self.get_queryset() - qs = qs.distinct() + if status_tramitacao and unidade_destino: + lista = filtra_tramitacao_adm_destino_and_status(status_tramitacao, + unidade_destino) + qs = qs.filter(id__in=lista).distinct() + + elif status_tramitacao: + lista = filtra_tramitacao_adm_status(status_tramitacao) + qs = qs.filter(id__in=lista).distinct() + + elif unidade_destino: + lista = filtra_tramitacao_adm_destino(unidade_destino) + qs = qs.filter(id__in=lista).distinct() if 'o' in self.request.GET and not self.request.GET['o']: qs = qs.order_by('-ano', '-numero') + qs = qs.prefetch_related("documentoacessorioadministrativo_set", + "tramitacaoadministrativo_set", + "tramitacaoadministrativo_set__status", + "tramitacaoadministrativo_set__unidade_tramitacao_local", + "tramitacaoadministrativo_set__unidade_tramitacao_destino") + kwargs.update({ 'queryset': qs, }) diff --git a/sapl/templates/protocoloadm/documentoadministrativo_filter.html b/sapl/templates/protocoloadm/documentoadministrativo_filter.html index b15726772..83eb1bd40 100644 --- a/sapl/templates/protocoloadm/documentoadministrativo_filter.html +++ b/sapl/templates/protocoloadm/documentoadministrativo_filter.html @@ -37,11 +37,26 @@
    QUADRO GERAL
    Matéria EmentaAutor(es)AutorCoautor(es)
    {{materia.ementa}} {% for autor in materia.autoria_set.all %} + {% if autor.primeiro_autor %} {{autor.autor}}
    + {% endif %} + {% endfor %} +
    + {% for autor in materia.autoria_set.all %} + {% if not autor.primeiro_autor %} + {{autor.autor}}
    + {% endif %} {% endfor %}
    Autor {{ protocolo.autor }}
    Assunto{{ protocolo.assunto_ementa }}
    Interessado{{ protocolo.interessado }}
    Assunto{{ protocolo.assunto_ementa }}
    Interessado{{ protocolo.interessado }}
    Natureza
    {{d.tipo.sigla}} {{d.numero}}/{{d.ano}} - {{d.tipo}}
    - Interessado: {{ d.interessado|default_if_none:"Não informado"}}
    - Assunto: {{ d.assunto|safe }}
    + Interessado: {{ d.interessado|default_if_none:"Não informado"}} +
    + Assunto: {{ d.assunto|safe }} +
    {% if d.protocolo %} Protocolo: {{ d.protocolo}}
    {% endif %} + {% if d.tramitacaoadministrativo_set.last.unidade_tramitacao_destino %} + Localização Atual:  {{d.tramitacaoadministrativo_set.last.unidade_tramitacao_destino}} +
    + Status: {{d.tramitacaoadministrativo_set.last.status}} +
    + {% endif %} + {% if d.documentoacessorioadministrativo_set.all.exists %} + Documentos Acessórios: + + {{ d.documentoacessorioadministrativo_set.all.count }} + +
    + {% endif %} {% if d.texto_integral %} Texto Integral
    {% endif %} From 740991625031a4d5d1611b324e14f5c74ae05f3b Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 20 Jul 2018 17:40:16 -0300 Subject: [PATCH 105/107] Fix #2084 (#2085) --- sapl/materia/forms.py | 6 ++++++ sapl/templates/protocoloadm/protocolo_mostrar.html | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 97d7156b5..04ee8d0e0 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -186,6 +186,7 @@ class MateriaLegislativaForm(ModelForm): widget=forms.HiddenInput()) self.fields['autor'] = forms.CharField(required=False, widget=forms.HiddenInput()) + self.fields['numero_protocolo'].widget.attrs['readonly'] = True def clean(self): super(MateriaLegislativaForm, self).clean() @@ -213,11 +214,16 @@ class MateriaLegislativaForm(ModelForm): exist_doc = DocumentoAdministrativo.objects.filter( protocolo_id=protocolo, ano=ano).exists() + if exist_materia or exist_doc: raise ValidationError(_('Protocolo %s/%s ja possui' ' documento vinculado' % (protocolo, ano))) + p = Protocolo.objects.get(numero=protocolo,ano=ano) + if p.tipo_materia != cleaned_data['tipo']: + raise ValidationError(_('Tipo do Protocolo deve ser o mesmo do Tipo Matéria')) + if data_apresentacao.year != ano: raise ValidationError(_("O ano da matéria não pode ser " "diferente do ano na data de apresentação")) diff --git a/sapl/templates/protocoloadm/protocolo_mostrar.html b/sapl/templates/protocoloadm/protocolo_mostrar.html index 0e434429b..376c730a1 100644 --- a/sapl/templates/protocoloadm/protocolo_mostrar.html +++ b/sapl/templates/protocoloadm/protocolo_mostrar.html @@ -38,11 +38,10 @@ {{materia}} {% endif %}
    - {% if not protocolo.anulado %}Criar Matéria{% endif %} + {% if not protocolo.anulado%}{% if not materia %}Criar Matéria    {% endif %}{% endif %} {% endif %} -      Comprovante {% endblock detail_content %} From 193555602d43f54c37d2852a66c6d5c3617b910c Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 20 Jul 2018 18:14:41 -0300 Subject: [PATCH 106/107] HOT-FIX: adiciona octet-stream para suportar formato docx. --- sapl/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sapl/utils.py b/sapl/utils.py index 89cf80f94..a656fa5a0 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -356,6 +356,7 @@ TIPOS_TEXTO_PERMITIDOS = ( 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/xml', + 'application/octet-stream', 'text/xml', 'text/html', ) From 63166f7b5c7831c4cf6e619c6368d4d563abbeb2 Mon Sep 17 00:00:00 2001 From: VictorFabreF Date: Fri, 20 Jul 2018 18:31:19 -0300 Subject: [PATCH 107/107] Release: 3.1.102 --- 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 913399536..fa0abdd5d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.101 + image: interlegis/sapl:3.1.102 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/setup.py b/setup.py index 493513458..758b57fc8 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.101', + version='3.1.102', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007',