mirror of https://github.com/interlegis/sapl.git
Edward
2 years ago
committed by
GitHub
61 changed files with 16 additions and 5341 deletions
@ -1,7 +0,0 @@ |
|||||
TipoAutor: |
|
||||
descricao: des_tipo_autor |
|
||||
|
|
||||
Autor: |
|
||||
nome: nom_autor |
|
||||
cargo: des_cargo |
|
||||
tipo: tip_autor |
|
@ -0,0 +1,15 @@ |
|||||
|
# Generated by Django 2.2.28 on 2022-09-14 14:25 |
||||
|
|
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('base', '0051_auto_20220814_2138'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.RunSQL("DROP TABLE IF EXISTS reversion_version"), |
||||
|
migrations.RunSQL("DROP TABLE IF EXISTS reversion_revision"), |
||||
|
] |
@ -1,51 +0,0 @@ |
|||||
TipoComissao: |
|
||||
dispositivo_regimental: des_dispositivo_regimental |
|
||||
natureza: sgl_natureza_comissao |
|
||||
nome: nom_tipo_comissao |
|
||||
sigla: sgl_tipo_comissao |
|
||||
|
|
||||
Comissao: |
|
||||
agenda_reuniao: des_agenda_reuniao |
|
||||
apelido_temp: nom_apelido_temp |
|
||||
data_criacao: dat_criacao |
|
||||
data_extincao: dat_extincao |
|
||||
data_fim_comissao: dat_fim_comissao |
|
||||
data_final_prevista_temp: dat_final_prevista_temp |
|
||||
data_instalacao_temp: dat_instalacao_temp |
|
||||
data_prorrogada_temp: dat_prorrogada_temp |
|
||||
email: end_email |
|
||||
endereco_secretaria: end_secretaria |
|
||||
fax_secretaria: num_fax_secretaria |
|
||||
finalidade: txt_finalidade |
|
||||
local_reuniao: loc_reuniao |
|
||||
nome: nom_comissao |
|
||||
secretario: nom_secretario |
|
||||
sigla: sgl_comissao |
|
||||
telefone_reuniao: num_tel_reuniao |
|
||||
telefone_secretaria: num_tel_secretaria |
|
||||
tipo: tip_comissao |
|
||||
unidade_deliberativa: ind_unid_deliberativa |
|
||||
|
|
||||
Periodo (PeriodoCompComissao): |
|
||||
data_fim: dat_fim_periodo |
|
||||
data_inicio: dat_inicio_periodo |
|
||||
|
|
||||
CargoComissao: |
|
||||
nome: des_cargo |
|
||||
unico: ind_unico |
|
||||
|
|
||||
Participacao (ComposicaoComissao): |
|
||||
cargo: cod_cargo |
|
||||
data_designacao: dat_designacao |
|
||||
data_desligamento: dat_desligamento |
|
||||
motivo_desligamento: des_motivo_desligamento |
|
||||
observacao: obs_composicao |
|
||||
parlamentar: cod_parlamentar |
|
||||
titular: ind_titular |
|
||||
|
|
||||
Reuniao (ReuniaoComissao): |
|
||||
comissao: cod_comissao |
|
||||
numero: num_reuniao |
|
||||
data: dat_inicio_reuniao |
|
||||
observacao: txt_observacao |
|
||||
|
|
@ -1,68 +0,0 @@ |
|||||
-> /sapl/comissoes/models.py |
|
||||
#1 - class ComposicaoComissao: Verificar comissao e periodo_comp. |
|
||||
|
|
||||
-> /sapl/lexml/models.py |
|
||||
#1 - Na classe 'LexmlRegistroProvedor', 'sigla_provedor' e 'tipo' não tem no html |
|
||||
#2 - Na classe 'LexmlRegistroProvedor' falta o campo 'Endereço do provedor OAI' |
|
||||
#3 - Na classe 'LexmlRegistroPublicador' 'tipo' não tem no html |
|
||||
|
|
||||
-> /sapl/norma/models.py |
|
||||
## html's faltando: |
|
||||
VinculoNormaJuridica |
|
||||
|
|
||||
#1 - Na classe 'LegislacaoCitada' falta 'Tipo Norma', 'Número' e 'Ano' |
|
||||
#2 - Na classe 'NormaJuridica' falta os campos 'Matéria Legislativa', 'Texto original (PDF)' e 'Situação de Vigência' |
|
||||
|
|
||||
-> /sapl/parlamentares/models.py |
|
||||
## html's faltando: |
|
||||
Localidade(Não tem html mesmo) |
|
||||
ComposicaoMesa |
|
||||
ComposicaoColigacao(Talvez seja http://sapl3.interlegis.leg.br/cadastros/auxiliares/coligacao/coligacao_index_html) |
|
||||
|
|
||||
#1 - Classe 'Legislatura' falta 'Nº Legislatura' |
|
||||
#2 - Na classe 'Parlamentar' faltam os campos 'Observação', 'UF' e 'Login' |
|
||||
#3 - Na classe 'Mandato' eu não tenho certeza se os campos 'tipo_afastamento' e 'tipo_causa_fim_mandato' |
|
||||
# correspondem aos campos 'Natureza do Mandato' e 'Expedição do Diploma', então naõ adicionei os verbose_name |
|
||||
|
|
||||
-> /sapl/protocoloadm/models.py |
|
||||
#1 - Na classe 'DocumentoAdministrativo' não possui o campo 'Autor' no html por isso está sem verbose_name e falta o |
|
||||
campo 'Texto Integral' na classe. |
|
||||
#2 - Na classe 'StatusTramitacaoAdministrativo' falta o campo 'Indicador de Tramitação' |
|
||||
#3 - A classe protocolo tá bastante diferente do html |
|
||||
- Ver depois |
|
||||
|
|
||||
-> /sapl/materia/models.py |
|
||||
## html's faltando: |
|
||||
AcompMateria |
|
||||
AssuntoMateria |
|
||||
DespachoInicial |
|
||||
MateriaAssunto |
|
||||
Parecer |
|
||||
|
|
||||
#1 - Na classe 'MateriaLegislativa' falta o campo 'cep' |
|
||||
#2 - Na classe 'Anexada' faltam os campos 'Tipo', 'Número' e 'Ano' |
|
||||
#3 - Na classe 'TipoAutor' falta o campo 'Tipo' |
|
||||
#4 - Classe 'Autor' com campos a mais |
|
||||
#5 - Na classe 'Autoria' faltam os campos 'Tipo de Autor' e 'Nome Autor' |
|
||||
#6 - Na classe 'DocumentoAcessorio' faltam os campos 'Texto digitalizado (PDF)' e 'Obeservação' |
|
||||
#7 - Classe 'Proposicao' muito diferente do html |
|
||||
#8 - Na classe 'StatusTramitacao', 'fim_tramitacao' e 'retorno_tramitacao' não deveriam tá separados |
|
||||
#9 - Na classe 'UnidadeTramitacao' falta o campo 'Correspondente SPDO' |
|
||||
|
|
||||
-> /sapl/sessao/models.py |
|
||||
## html's faltando: |
|
||||
SessaoPlenariaPresenca |
|
||||
RegistroVotacaoParlamentar |
|
||||
OrdemDiaPresenca |
|
||||
MesaSessaoPlenaria |
|
||||
ExpedienteSessaoPlenaria |
|
||||
|
|
||||
#1 - Na classe 'SessaoPlenaria' faltam os campos de arquivos indexados |
|
||||
#2 - Na classe 'ExpedienteMateria' faltam os campos 'Tipo da Sessão', 'Tipo Matéria', 'Núm. Matéria' e 'Ano Matéria' |
|
||||
#3 - Na Classe 'Oradores' faltam os campos 'Parlamentar' e 'Discurso' |
|
||||
#4 - Na Classe 'OradoresExpediente' faltam os campos 'Parlamentar' e 'Discurso' |
|
||||
***** As páginas 'Oradores' e 'OradoresExpediente' são iguas |
|
||||
#5 - Na classe 'OrdemDia' faltam os campos 'Tipo da Sessão', 'Tipo Matéria', 'Núm. Matéria' e 'Ano Matéria' |
|
||||
***** As páginas 'ExpedienteMateria' e 'OrdemDia' são iguas |
|
||||
#6 - Na classe 'RegistroVotacao' faltam os campos 'Não Votou:', 'Anular Votação' e |
|
||||
'A totalização inclui o voto do Presidente?' |
|
@ -1,20 +0,0 @@ |
|||||
from django.core.management.base import BaseCommand |
|
||||
|
|
||||
from sapl.legacy.migracao import migrar |
|
||||
|
|
||||
|
|
||||
class Command(BaseCommand): |
|
||||
|
|
||||
help = 'Migração de dados do SAPL 2.5 para o SAPL 3.1' |
|
||||
|
|
||||
def add_arguments(self, parser): |
|
||||
parser.add_argument( |
|
||||
'-a', |
|
||||
action='store_true', |
|
||||
default=False, |
|
||||
dest='apagar_do_legado', |
|
||||
help='Apagar entradas migradas do legado', |
|
||||
) |
|
||||
|
|
||||
def handle(self, *args, **options): |
|
||||
migrar(apagar_do_legado=options['apagar_do_legado']) |
|
@ -1,11 +0,0 @@ |
|||||
from django.core.management.base import BaseCommand |
|
||||
|
|
||||
from sapl.legacy.migracao_documentos import migrar_documentos |
|
||||
|
|
||||
|
|
||||
class Command(BaseCommand): |
|
||||
|
|
||||
help = 'Migração documentos do SAPL 2.5 para o SAPL 3.1' |
|
||||
|
|
||||
def handle(self, *args, **options): |
|
||||
migrar_documentos() |
|
@ -1,12 +0,0 @@ |
|||||
from django.core.management.base import BaseCommand |
|
||||
|
|
||||
from sapl.legacy.scripts.ressuscita_dependencias import adiciona_ressuscitar |
|
||||
|
|
||||
|
|
||||
class Command(BaseCommand): |
|
||||
|
|
||||
help = 'Ressuscita dependências apagadas ' \ |
|
||||
'que são necessárias para migrar outros registros' |
|
||||
|
|
||||
def handle(self, *args, **options): |
|
||||
adiciona_ressuscitar() |
|
@ -1,82 +0,0 @@ |
|||||
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, |
|
||||
migrar_dados) |
|
||||
from sapl.legacy.migracao_documentos import migrar_documentos |
|
||||
from sapl.legacy.migracao_usuarios import migrar_usuarios |
|
||||
from sapl.legacy.scripts.exporta_zope.variaveis_comuns import TAG_ZOPE |
|
||||
from sapl.legacy_migration_settings import DIR_REPO, NOME_BANCO_LEGADO |
|
||||
from sapl.materia.models import Proposicao |
|
||||
|
|
||||
|
|
||||
def adornar_msg(msg): |
|
||||
return '\n{1}\n{0}\n{1}'.format(msg, '#' * len(msg)) |
|
||||
|
|
||||
|
|
||||
def migrar(apagar_do_legado=False): |
|
||||
if TAG_MARCO in REPO.tags: |
|
||||
info('A migração já está feita.') |
|
||||
return |
|
||||
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(apagar_do_legado) |
|
||||
migrar_usuarios(REPO.working_dir) |
|
||||
migrar_documentos(REPO) |
|
||||
gravar_marco() |
|
||||
# compactar_media() |
|
||||
|
|
||||
|
|
||||
def compactar_media(): |
|
||||
|
|
||||
# tar de media/sapl |
|
||||
print('Criando tar de media... ', end='', flush=True) |
|
||||
arq_tar = DIR_REPO.child('{}.media.tar'.format(NOME_BANCO_LEGADO)) |
|
||||
arq_tar.remove() |
|
||||
subprocess.check_output(['tar', 'cfh', arq_tar, '-C', DIR_REPO, 'sapl']) |
|
||||
print('SUCESSO') |
|
||||
|
|
||||
|
|
||||
PROPOSICAO_UPLOAD_TO = Proposicao._meta.get_field('texto_original').upload_to |
|
||||
|
|
||||
|
|
||||
def salva_conteudo_do_sde(proposicao, conteudo): |
|
||||
caminho_relativo = PROPOSICAO_UPLOAD_TO( |
|
||||
proposicao, 'proposicao_sde_{}.xml'.format(proposicao.pk)) |
|
||||
caminho_absoluto = Path(REPO.working_dir, caminho_relativo) |
|
||||
caminho_absoluto.parent.mkdir(parents=True) |
|
||||
# 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 |
|
||||
proposicao.save() |
|
||||
|
|
||||
|
|
||||
def scrap_sde(url, usuario, senha=None): |
|
||||
if not senha: |
|
||||
senha = getpass() |
|
||||
|
|
||||
# login |
|
||||
session = requests.session() |
|
||||
res = session.post('{}?retry=1'.format(url), |
|
||||
{'__ac_name': usuario, '__ac_password': senha}) |
|
||||
assert res.status_code == 200 |
|
||||
|
|
||||
url_proposicao_tmpl = '{}/sapl_documentos/proposicao/{}/renderXML?xsl=__default__' # noqa |
|
||||
total = Proposicao.objects.count() |
|
||||
for num, proposicao in enumerate(Proposicao.objects.all()): |
|
||||
pk = proposicao.pk |
|
||||
url_proposicao = url_proposicao_tmpl.format(url, pk) |
|
||||
res = session.get(url_proposicao) |
|
||||
print("pk: {} status: {} {} (progresso: {:.2%})".format( |
|
||||
pk, res.status_code, url_proposicao, num / total)) |
|
||||
if res.status_code == 200: |
|
||||
salva_conteudo_do_sde(proposicao, res.content) |
|
File diff suppressed because it is too large
@ -1,215 +0,0 @@ |
|||||
import os |
|
||||
import re |
|
||||
import shutil |
|
||||
from glob import glob |
|
||||
from os.path import join |
|
||||
|
|
||||
import yaml |
|
||||
from django.db import transaction |
|
||||
from image_cropping.fields import ImageCropField |
|
||||
|
|
||||
from sapl.base.models import CasaLegislativa |
|
||||
from sapl.comissoes.models import Reuniao |
|
||||
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 |
|
||||
from sapl.parlamentares.models import Parlamentar |
|
||||
from sapl.protocoloadm.models import (DocumentoAcessorioAdministrativo, |
|
||||
DocumentoAdministrativo) |
|
||||
from sapl.sessao.models import SessaoPlenaria |
|
||||
|
|
||||
# MIGRAÇÃO DE DOCUMENTOS ################################################### |
|
||||
|
|
||||
|
|
||||
DOCS = { |
|
||||
Parlamentar: [('fotografia', 'parlamentar/fotos/{}_foto_parlamentar')], |
|
||||
MateriaLegislativa: [('texto_original', 'materia/{}_texto_integral')], |
|
||||
DocumentoAcessorio: [('arquivo', 'materia/{}')], |
|
||||
NormaJuridica: [('texto_integral', 'norma_juridica/{}_texto_integral')], |
|
||||
SessaoPlenaria: [('upload_pauta', 'pauta_sessao/{}_pauta_sessao'), |
|
||||
('upload_ata', 'ata_sessao/{}_ata_sessao'), |
|
||||
('upload_anexo', 'anexo_sessao/{}_texto_anexado')], |
|
||||
Proposicao: [('texto_original', 'proposicao/{}')], |
|
||||
DocumentoAdministrativo: [('texto_integral', |
|
||||
'administrativo/{}_texto_integral')], |
|
||||
DocumentoAcessorioAdministrativo: [('arquivo', 'administrativo/{}')], |
|
||||
} |
|
||||
|
|
||||
# acrescenta reuniões (que só existem no sapl 3.0) |
|
||||
if EXISTE_REUNIAO_NO_LEGADO: |
|
||||
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 model, campos in DOCS.items()} |
|
||||
|
|
||||
|
|
||||
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 |
|
||||
# apaga destino, se houver, e renomeia origem para destino |
|
||||
if os.path.exists(destino): |
|
||||
if os.path.isdir(destino): |
|
||||
shutil.rmtree(destino) |
|
||||
else: |
|
||||
os.remove(destino) |
|
||||
os.makedirs(os.path.dirname(destino), exist_ok=True) |
|
||||
os.rename(origem, destino) |
|
||||
|
|
||||
|
|
||||
def migrar_logotipo(repo, casa, propriedades): |
|
||||
print('.... Migrando logotipo da casa ....') |
|
||||
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( |
|
||||
join(repo.working_dir, origem.format(nome_nas_propriedades))) |
|
||||
if arquivos: |
|
||||
assert len(arquivos) == 1, 'Há mais de um logotipo para a casa' |
|
||||
[logo] = arquivos |
|
||||
destino = join(CasaLegislativa._meta.get_field(campo).upload_to, |
|
||||
os.path.basename(logo)) |
|
||||
mover_documento(repo, logo, destino) |
|
||||
casa.logotipo = destino |
|
||||
|
|
||||
|
|
||||
def migrar_propriedades_da_casa(repo): |
|
||||
print('#### Migrando propriedades da casa ####') |
|
||||
caminho = join(repo.working_dir, 'sapl_documentos/propriedades.yaml') |
|
||||
repo.git.execute('git annex get'.split() + [caminho]) |
|
||||
with open(caminho, 'r') as arquivo: |
|
||||
propriedades = yaml.safe_load(arquivo) |
|
||||
casa = CasaLegislativa.objects.first() |
|
||||
if not casa: |
|
||||
casa = CasaLegislativa() |
|
||||
campos_para_propriedades = [('codigo', 'cod_casa'), |
|
||||
('nome', 'nom_casa'), |
|
||||
('sigla', 'sgl_casa'), |
|
||||
('endereco', 'end_casa'), |
|
||||
('cep', 'num_cep'), |
|
||||
('telefone', 'num_tel'), |
|
||||
('fax', 'num_fax'), |
|
||||
('endereco_web', 'end_web_casa'), |
|
||||
('email', 'end_email_casa'), |
|
||||
('sigla', 'sgl_casa'), |
|
||||
('informacao_geral', 'txt_informacao_geral')] |
|
||||
for campo, prop in campos_para_propriedades: |
|
||||
setattr(casa, campo, propriedades[prop]) |
|
||||
|
|
||||
# localidade |
|
||||
sql_localidade = ''' |
|
||||
select nom_localidade, sgl_uf from localidade |
|
||||
where cod_localidade = {}'''.format(propriedades['cod_localidade']) |
|
||||
[(casa.municipio, casa.uf)] = exec_legado(sql_localidade) |
|
||||
|
|
||||
# logotipo |
|
||||
migrar_logotipo(repo, casa, propriedades) |
|
||||
|
|
||||
casa.save() |
|
||||
|
|
||||
|
|
||||
def migrar_docs_por_ids(repo, model): |
|
||||
|
|
||||
for campo, base_origem in DOCS[model]: |
|
||||
print('#### Migrando {} de {} ####'.format(campo, model.__name__)) |
|
||||
|
|
||||
dir_origem, nome_origem = os.path.split( |
|
||||
join(repo.working_dir, base_origem)) |
|
||||
nome_origem = nome_origem.format('(\d+)') |
|
||||
pat = re.compile('^{}\.\w+$'.format(nome_origem)) |
|
||||
if not os.path.isdir(dir_origem): |
|
||||
print(' >>> O diretório {} não existe! Abortado.'.format( |
|
||||
dir_origem)) |
|
||||
continue |
|
||||
|
|
||||
matches = [pat.match(arq) for arq in os.listdir(dir_origem)] |
|
||||
ids_origens = [(int(m.group(1)), |
|
||||
join(dir_origem, m.group(0))) |
|
||||
for m in matches if m] |
|
||||
objetos = {obj.id: obj for obj in model.objects.all()} |
|
||||
upload_to = model._meta.get_field(campo).upload_to |
|
||||
tem_cropping = isinstance(model._meta.get_field(campo), ImageCropField) |
|
||||
|
|
||||
with transaction.atomic(): |
|
||||
for id, origem in ids_origens: |
|
||||
# associa documento ao objeto |
|
||||
obj = objetos.get(id) |
|
||||
if obj: |
|
||||
destino = upload_to(obj, os.path.basename(origem)) |
|
||||
mover_documento(repo, origem, destino) |
|
||||
setattr(obj, campo, destino) |
|
||||
if tem_cropping: |
|
||||
# conserta link do git annex (antes do commit) |
|
||||
# pois o conteúdo das imagens é acessado pelo cropping |
|
||||
repo.git.add(destino) |
|
||||
repo.git.execute('git annex fix'.split() + [destino]) |
|
||||
obj.save() |
|
||||
else: |
|
||||
msg = ' {} (pk={}) não encontrado para documento em [{}]' |
|
||||
print(msg.format(model.__name__, id, origem)) |
|
||||
|
|
||||
|
|
||||
def migrar_documentos(repo): |
|
||||
# aqui supomos que as pastas XSLT e sapl_documentos estão em |
|
||||
# <repo.working_dir> com o conteúdo exportado do zope |
|
||||
# Os arquivos das pastas serão (git) MOVIDOS para a nova estrutura! |
|
||||
# |
|
||||
# Isto significa que para rodar novamente esta função é preciso |
|
||||
# restaurar o repo ao estado anterior |
|
||||
|
|
||||
mover_documento(repo, 'XSLT', 'sapl/public/XSLT', |
|
||||
ignora_origem_ausente=True) |
|
||||
|
|
||||
migrar_propriedades_da_casa(repo) |
|
||||
|
|
||||
# garante que o conteúdo das fotos dos parlamentares esteja presente |
|
||||
# (necessário para o cropping de imagem) |
|
||||
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) |
|
||||
|
|
||||
# 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')) |
|
||||
for file in files] |
|
||||
if sobrando: |
|
||||
print('\n#### Encerrado ####\n\n' |
|
||||
'{} documentos sobraram sem ser migrados!!!'.format( |
|
||||
len(sobrando))) |
|
||||
|
|
||||
|
|
||||
def corrigir_documentos_para_existentes(repo): |
|
||||
|
|
||||
for model, campos_bases in DOCS.items(): |
|
||||
if model == Parlamentar: |
|
||||
continue |
|
||||
for campo, base_origem in campos_bases: |
|
||||
print('#### Corrigindo {} de {} ####'.format(campo, |
|
||||
model.__name__)) |
|
||||
upload_to = model._meta.get_field(campo).upload_to |
|
||||
for obj in model.objects.all(): |
|
||||
if getattr(obj, campo): |
|
||||
continue |
|
||||
dir_upload_to = os.path.join( |
|
||||
repo.working_dir, upload_to(obj, '')) |
|
||||
achados = glob(dir_upload_to + '*') |
|
||||
if achados: |
|
||||
assert len(achados) == 1, 'Mais de um doc achado' |
|
||||
[achado] = achados |
|
||||
destino = upload_to(obj, os.path.basename(achado)) |
|
||||
print('-- {}'.format(destino)) |
|
||||
setattr(obj, campo, destino) |
|
||||
obj.save() |
|
@ -1,109 +0,0 @@ |
|||||
import yaml |
|
||||
from django.contrib.auth.models import Group, User |
|
||||
from unipath import Path |
|
||||
|
|
||||
from sapl.hashers import zope_encoded_password_to_django |
|
||||
|
|
||||
PERFIL_LEGADO_PARA_NOVO = {legado: Group.objects.get(name=novo) |
|
||||
for legado, novo in [ |
|
||||
('Autor', 'Autor'), |
|
||||
('Operador', 'Operador Geral'), |
|
||||
('Operador Comissao', 'Operador de Comissões'), |
|
||||
('Operador Materia', 'Operador de Matéria'), |
|
||||
('Operador Modulo Administrativo', 'Operador Administrativo'), |
|
||||
('Operador Norma', 'Operador de Norma Jurídica'), |
|
||||
('Operador Parlamentar', 'Parlamentar'), |
|
||||
('Operador Protocolo', 'Operador de Protocolo Administrativo'), |
|
||||
('Operador Sessao Plenaria', 'Operador de Sessão Plenária'), |
|
||||
('Parlamentar', 'Votante'), |
|
||||
('Operador Painel', 'Operador de Painel Eletrônico'), |
|
||||
] |
|
||||
} |
|
||||
|
|
||||
ADMINISTRADORES = {'Administrador', 'Manager'} |
|
||||
|
|
||||
IGNORADOS = { |
|
||||
# sem significado fora do zope |
|
||||
'Alterar Senha', 'Authenticated', 'Owner', |
|
||||
|
|
||||
# obsoletos (vide docs a seguir) |
|
||||
'Operador Mesa Diretora', |
|
||||
'Operador Ordem Dia', |
|
||||
'Operador Tabela Auxiliar', |
|
||||
'Operador Lexml', |
|
||||
} |
|
||||
|
|
||||
|
|
||||
def decode_nome(nome): |
|
||||
if isinstance(nome, bytes): |
|
||||
try: |
|
||||
return nome.decode('utf-8') |
|
||||
except UnicodeDecodeError: |
|
||||
return nome.decode('iso8859-1') |
|
||||
else: |
|
||||
assert isinstance(nome, str) |
|
||||
return nome |
|
||||
|
|
||||
|
|
||||
def migrar_usuarios(dir_repo): |
|
||||
""" |
|
||||
Lê o arquivo <dir_repo>/usuarios.yaml e importa os usuários nele listados, |
|
||||
com senhas e perfis. |
|
||||
Os usuários são criados se necessário e seus perfis ajustados. |
|
||||
|
|
||||
Os seguintes perfis no legado não correspondem a nenhum no código atual |
|
||||
e estão sendo **ignorados**: |
|
||||
|
|
||||
* Operador Mesa Diretora |
|
||||
Apenas **8 usuários**, em todas as bases, têm esse perfil |
|
||||
e não têm nem "Operador" nem "Operador Sessao Plenaria" |
|
||||
|
|
||||
* Operador Ordem Dia |
|
||||
Apenas **16 usuários**, em todas as bases, têm esse perfil |
|
||||
e não têm nem "Operador" nem "Operador Sessao Plenaria" |
|
||||
|
|
||||
* Operador Tabela Auxiliar |
|
||||
A edição das tabelas auxiliares deve ser feita por um administrador |
|
||||
|
|
||||
* Operador Lexml |
|
||||
Também podemos assumir que essa é uma tarefa de um administrador |
|
||||
""" |
|
||||
|
|
||||
ARQUIVO_USUARIOS = Path(dir_repo).child('usuarios.yaml') |
|
||||
with open(ARQUIVO_USUARIOS, 'r') as f: |
|
||||
usuarios = yaml.load(f, yaml.Loader) |
|
||||
# conferimos de que só há um nome de usuário |
|
||||
assert all(nome == dados['name'] for nome, dados in usuarios.items()) |
|
||||
usuarios = [ |
|
||||
(decode_nome(nome), |
|
||||
# troca senha "inicial" (que existe em alguns zopes) |
|
||||
# por uma inutilizável |
|
||||
dados['__'] if dados['__'] != 'inicial' else None, |
|
||||
# filtra perfis ignorados |
|
||||
set(dados['roles']) - IGNORADOS) |
|
||||
for nome, dados in usuarios.items()] |
|
||||
|
|
||||
admins = [] |
|
||||
for nome, senha, perfis in usuarios: |
|
||||
usuario = User.objects.get_or_create(username=nome)[0] |
|
||||
usuario.password = zope_encoded_password_to_django(senha) |
|
||||
for perfil in perfis: |
|
||||
if perfil in ADMINISTRADORES: |
|
||||
# todos os administradores ganham perfil "Operador Geral" |
|
||||
usuario.groups.add(PERFIL_LEGADO_PARA_NOVO['Operador']) |
|
||||
admins.append(usuario) |
|
||||
else: |
|
||||
usuario.groups.add(PERFIL_LEGADO_PARA_NOVO[perfil]) |
|
||||
usuario.save() |
|
||||
|
|
||||
# configura administradores |
|
||||
for admin in admins: |
|
||||
admin.is_superuser = True |
|
||||
admin.save() |
|
||||
|
|
||||
print('Usuários migrados com sucesso.') |
|
||||
print('#' * 100) |
|
||||
print('Uusários administradores:') |
|
||||
for admin in admins: |
|
||||
print(admin.username) |
|
||||
print('#' * 100) |
|
File diff suppressed because it is too large
@ -1,22 +0,0 @@ |
|||||
class LegacyRouter: |
|
||||
|
|
||||
def db_for_read(self, model, **hints): |
|
||||
if model._meta.app_label == 'legacy': |
|
||||
return 'legacy' |
|
||||
return None |
|
||||
|
|
||||
def db_for_write(self, model, **hints): |
|
||||
if model._meta.app_label == 'legacy': |
|
||||
return 'legacy' |
|
||||
return None |
|
||||
|
|
||||
def allow_relation(self, obj1, obj2, **hints): |
|
||||
if obj1._meta.app_label == 'legacy' \ |
|
||||
and obj2._meta.app_label == 'legacy': |
|
||||
return True |
|
||||
return None |
|
||||
|
|
||||
def allow_migrate(self, db, app_label, model_name=None, **hints): |
|
||||
if app_label == 'legacy': |
|
||||
return False |
|
||||
return None |
|
@ -1,6 +0,0 @@ |
|||||
#!/usr/bin/env bash |
|
||||
|
|
||||
# All tests under this directory are excluded in default pytest.ini |
|
||||
# To run them use this script in this directory |
|
||||
|
|
||||
py.test --ds=sapl.legacy_migration_settings |
|
@ -1,3 +0,0 @@ |
|||||
[flake8] |
|
||||
ignore = E501 |
|
||||
|
|
@ -1,3 +0,0 @@ |
|||||
Data*.fs* |
|
||||
sapl_documentos |
|
||||
XSLT |
|
@ -1,31 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
|
|
||||
from exporta_zope import (br, dump_folder, dump_propriedades, dump_usuarios, |
|
||||
get_app, logando_nao_identificados) |
|
||||
|
|
||||
|
|
||||
def dump_sapl30(): |
|
||||
"""Extrai dados do zope de um sapl 3.0, que, ao que tudo indica: |
|
||||
* não possui a pasta XSLT |
|
||||
* usa um mountpoint separado para os documentos |
|
||||
* usa encoding utf-8 (ao invés de iso-8859-1) |
|
||||
""" |
|
||||
destino = '../../../../media' |
|
||||
data_fs_path = destino + '/Data.fs' |
|
||||
docs_path = destino + '/DocumentosSapl.fs' |
|
||||
|
|
||||
try: |
|
||||
app, close_db = get_app(data_fs_path) |
|
||||
sapl = br(app['sapl']) |
|
||||
dump_usuarios(sapl, destino) |
|
||||
finally: |
|
||||
close_db() |
|
||||
|
|
||||
try: |
|
||||
app, close_db = get_app(docs_path) |
|
||||
docs = br(app['sapl_documentos']) |
|
||||
with logando_nao_identificados(): |
|
||||
dump_folder(docs, destino) |
|
||||
dump_propriedades(docs, destino, 'utf-8') |
|
||||
finally: |
|
||||
close_db() |
|
@ -1,498 +0,0 @@ |
|||||
#!/usr/bin/env python |
|
||||
# -*- coding: utf-8 -*- |
|
||||
|
|
||||
# IMPORTANTE: |
|
||||
# Esse script precisa rodar em python 2 |
|
||||
# e depende apenas do descrito no arquivo requiments.txt |
|
||||
|
|
||||
import cStringIO |
|
||||
import hashlib |
|
||||
import mimetypes |
|
||||
import os |
|
||||
import sys |
|
||||
from collections import defaultdict |
|
||||
from contextlib import contextmanager |
|
||||
from functools import partial |
|
||||
from os.path import exists |
|
||||
|
|
||||
import git |
|
||||
import magic |
|
||||
import yaml |
|
||||
import ZODB.DB |
|
||||
import ZODB.FileStorage |
|
||||
from unipath import Path |
|
||||
from ZODB.broken import Broken |
|
||||
from ZODB.POSException import POSKeyError |
|
||||
|
|
||||
from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE |
|
||||
|
|
||||
EXTENSOES = { |
|
||||
# docs |
|
||||
'application/msword': '.doc', |
|
||||
'application/pdf': '.pdf', |
|
||||
'application/vnd.oasis.opendocument.text': '.odt', |
|
||||
'application/vnd.ms-excel': '.xls', |
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx', # noqa |
|
||||
'application/vnd.oasis.opendocument.text-template': '.ott', |
|
||||
'application/vnd.ms-powerpoint': '.ppt', |
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': '.xlsx', # noqa |
|
||||
'application/vnd.oasis.opendocument.spreadsheet': '.ods', |
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation': '.pptx', # noqa |
|
||||
'application/vnd.oasis.opendocument.graphics': '.odg', |
|
||||
|
|
||||
# incertos... associamos a extensão mais provável |
|
||||
'application/vnd.ms-office': '.doc', |
|
||||
'text/x-c++': '.cpp', |
|
||||
|
|
||||
# outros |
|
||||
'application/xml': '.xml', |
|
||||
'text/xml': '.xml', |
|
||||
'application/zip': '.zip', |
|
||||
'application/x-rar': '.rar', |
|
||||
'application/x-dosexec': '.exe', |
|
||||
'message/rfc822': '.mht', |
|
||||
'text/richtext': '.rtx', |
|
||||
'application/gzip': '.gz', |
|
||||
'image/vnd.dwg': '*.dwg', |
|
||||
|
|
||||
# media |
|
||||
'image/jpeg': '.jpeg', |
|
||||
'image/png': '.png', |
|
||||
'image/gif': '.gif', |
|
||||
'text/html': '.html', |
|
||||
'text/rtf': '.rtf', |
|
||||
'text/x-python': '.py', |
|
||||
'text/plain': '.txt', |
|
||||
'SDE-Document': '.xml', |
|
||||
'image/tiff': '.tiff', |
|
||||
'application/tiff': '.tiff', |
|
||||
'audio/x-wav': '.wav', |
|
||||
'video/mp4': '.mp4', |
|
||||
'image/x-icon': '.ico', |
|
||||
'image/x-ms-bmp': '.bmp', |
|
||||
'video/x-ms-asf': '.asf', |
|
||||
'audio/mpeg': '.mp3', |
|
||||
'video/x-flv': '.flv', |
|
||||
'video/quicktime': '.mov', |
|
||||
|
|
||||
# sem extensao |
|
||||
'application/octet-stream': '', # binário |
|
||||
'inode/x-empty': '', # vazio |
|
||||
'application/x-empty': '', # vazio |
|
||||
'text/x-unknown-content-type': '', # desconhecido |
|
||||
'application/CDFV2-unknown': '', # desconhecido |
|
||||
} |
|
||||
|
|
||||
|
|
||||
def br(obj): |
|
||||
if isinstance(obj, Broken): |
|
||||
return obj.__Broken_state__ |
|
||||
else: |
|
||||
return obj |
|
||||
|
|
||||
|
|
||||
def guess_extension(fullname, buffer): |
|
||||
# um corte de apenas 1024 impediu a detecção correta de .docx |
|
||||
mime = magic.from_buffer(buffer, mime=True) |
|
||||
extensao = EXTENSOES.get(mime) |
|
||||
if extensao is not None: |
|
||||
return extensao |
|
||||
else: |
|
||||
possibilidades = '\n'.join( |
|
||||
[" '{}': '{}',".format(mime, ext) |
|
||||
for ext in mimetypes.guess_all_extensions(mime)]) |
|
||||
print('''Extensão não conhecida para o arquivo: {} |
|
||||
e mimetype: {} |
|
||||
Algumas possibilidades são: |
|
||||
{} |
|
||||
Atualize o código do dicionário EXTENSOES! |
|
||||
'''.format(fullname, mime, possibilidades) |
|
||||
) |
|
||||
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 |
|
||||
# ao percorrer a árvore de objetos |
|
||||
# |
|
||||
# Imaginamos que, internamente, o ZODB está guardando referências |
|
||||
# para os objetos Broken criados e não conseguimos identificar como. |
|
||||
# |
|
||||
# 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 |
|
||||
|
|
||||
output = cStringIO.StringIO() |
|
||||
while pdata: |
|
||||
output.write(pdata.pop('data')) |
|
||||
pdata = br(pdata.pop('next', None)) |
|
||||
|
|
||||
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) |
|
||||
return name |
|
||||
|
|
||||
|
|
||||
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_msg_poskeyerror(id) |
|
||||
else: |
|
||||
yield id, obj, meta_type |
|
||||
|
|
||||
|
|
||||
enumerate_folder = partial(enumerate_by_key_list, |
|
||||
key_list='_objects', type_key='meta_type') |
|
||||
|
|
||||
enumerate_properties = partial(enumerate_by_key_list, |
|
||||
key_list='_properties', type_key='type') |
|
||||
|
|
||||
|
|
||||
def enumerate_btree(folder): |
|
||||
contagem_esperada = folder['_count'].value |
|
||||
tree = folder['_tree'] |
|
||||
contagem_real = 0 # para o caso em que não haja itens |
|
||||
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: ' |
|
||||
'{} esperada: {} real: {}'.format(folder['title'], |
|
||||
contagem_esperada, |
|
||||
contagem_real)) |
|
||||
|
|
||||
|
|
||||
nao_identificados = defaultdict(list) |
|
||||
|
|
||||
|
|
||||
@contextmanager |
|
||||
def logando_nao_identificados(): |
|
||||
nao_identificados.clear() |
|
||||
yield |
|
||||
if nao_identificados: |
|
||||
print('#' * 80) |
|
||||
print('#' * 80) |
|
||||
print('FORAM ENCONTRADOS ARQUIVOS DE FORMATO NÃO IDENTIFICADO!!!') |
|
||||
print('REFAÇA A EXPORTAÇÃO\n') |
|
||||
print(nao_identificados) |
|
||||
print('#' * 80) |
|
||||
print('#' * 80) |
|
||||
|
|
||||
|
|
||||
def dump_folder(folder, path, salvar, mtimes, enum=enumerate_folder): |
|
||||
name = folder['id'] |
|
||||
path = os.path.join(path, name) |
|
||||
if not 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) |
|
||||
elif dump: |
|
||||
if isinstance(dump, partial) and dump.func == dump_folder: |
|
||||
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 |
|
||||
fullname = os.path.join(path, id) |
|
||||
if mtime > mtimes.get(fullname, 0): |
|
||||
id_interno = dump(br(obj), path, salvar) |
|
||||
assert id == id_interno |
|
||||
mtimes[fullname] = mtime |
|
||||
return name |
|
||||
|
|
||||
|
|
||||
def decode_iso8859(obj): |
|
||||
return obj.decode('iso8859-1') if isinstance(obj, str) else obj |
|
||||
|
|
||||
|
|
||||
def read_sde(element): |
|
||||
|
|
||||
def read_properties(): |
|
||||
for id, obj, meta_type in enumerate_properties(element): |
|
||||
yield id, decode_iso8859(br(obj)) |
|
||||
|
|
||||
def read_children(): |
|
||||
for id, obj, meta_type in enumerate_folder(element): |
|
||||
assert meta_type in ['SDE-Document-Element', |
|
||||
'SDE-Template-Element', |
|
||||
'SDE-Template-Link', |
|
||||
'SDE-Template-Attribute', |
|
||||
'Script (Python)', |
|
||||
] |
|
||||
if meta_type != 'Script (Python)': |
|
||||
# ignoramos os scrips python de eventos dos templates |
|
||||
yield {'id': id, |
|
||||
'meta_type': meta_type, |
|
||||
'dados': read_sde(br(obj))} |
|
||||
|
|
||||
data = dict(read_properties()) |
|
||||
children = list(read_children()) |
|
||||
if children: |
|
||||
data['children'] = children |
|
||||
return data |
|
||||
|
|
||||
|
|
||||
def save_as_yaml(path, name, obj, salvar): |
|
||||
fullname = os.path.join(path, name) |
|
||||
conteudo = yaml.safe_dump(obj, allow_unicode=True) |
|
||||
salvar(fullname, conteudo) |
|
||||
|
|
||||
|
|
||||
def dump_sde(strdoc, path, salvar, tipo): |
|
||||
id = strdoc['id'] |
|
||||
sde = read_sde(strdoc) |
|
||||
save_as_yaml(path, '{}.{}.yaml'.format(id, tipo), sde, salvar) |
|
||||
return id |
|
||||
|
|
||||
|
|
||||
DUMP_FUNCTIONS = { |
|
||||
'File': dump_file, |
|
||||
'Image': dump_file, |
|
||||
'DTML Method': partial(dump_file, |
|
||||
get_conteudo=get_conteudo_dtml_method), |
|
||||
'DTMLMethod': partial(dump_file, |
|
||||
get_conteudo=get_conteudo_dtml_method), |
|
||||
'Folder': partial(dump_folder, enum=enumerate_folder), |
|
||||
'BTreeFolder2': partial(dump_folder, enum=enumerate_btree), |
|
||||
'SDE-Document': partial(dump_sde, tipo='sde.document'), |
|
||||
'StrDoc': partial(dump_sde, tipo='sde.document'), |
|
||||
'SDE-Template': partial(dump_sde, tipo='sde.template'), |
|
||||
|
|
||||
# explicitamente ignorados |
|
||||
'ZCatalog': None, |
|
||||
'Dumper': None, |
|
||||
'CachingPolicyManager': None, |
|
||||
} |
|
||||
|
|
||||
|
|
||||
def get_app(data_fs_path): |
|
||||
storage = ZODB.FileStorage.FileStorage(data_fs_path, read_only=True) |
|
||||
db = ZODB.DB(storage) |
|
||||
connection = db.open() |
|
||||
root = connection.root() |
|
||||
app = br(root['Application']) |
|
||||
|
|
||||
def close_db(): |
|
||||
db.close() |
|
||||
|
|
||||
return app, close_db |
|
||||
|
|
||||
|
|
||||
def find_sapl(app): |
|
||||
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) |
|
||||
elif id == 'sapl' and meta_type in ['SAPL', 'Folder']: |
|
||||
sapl = br(app['sapl']) |
|
||||
return sapl |
|
||||
|
|
||||
|
|
||||
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: 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 = {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) |
|
||||
|
|
||||
|
|
||||
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: |
|
||||
sapl = find_sapl(app) |
|
||||
# extrai usuários com suas senhas e perfis |
|
||||
dump_usuarios(sapl, destino, salvar) |
|
||||
|
|
||||
# extrai folhas XSLT (primeira tentativa) |
|
||||
if 'XSLT' in sapl: |
|
||||
dump_folder(br(sapl['XSLT']), destino, salvar, mtimes) |
|
||||
|
|
||||
finally: |
|
||||
close_db() |
|
||||
|
|
||||
app, close_db = get_app(documentos_fs_path) |
|
||||
|
|
||||
try: |
|
||||
sapl = find_sapl(app) |
|
||||
if sapl == {'id': 'sapl'}: |
|
||||
# em algumas instalações sapl_documentos está direto na raiz |
|
||||
docs = br(app['sapl_documentos']) |
|
||||
else: |
|
||||
# caso mais comum |
|
||||
docs = br(sapl['sapl_documentos']) |
|
||||
|
|
||||
# extrai folhas XSLT (segunda tentativa) |
|
||||
if 'XSLT' in sapl: |
|
||||
dump_folder(br(sapl['XSLT']), destino, salvar, mtimes) |
|
||||
|
|
||||
# extrai documentos |
|
||||
with logando_nao_identificados(): |
|
||||
dump_folder(docs, destino, salvar, mtimes) |
|
||||
dump_propriedades(docs, destino, salvar) |
|
||||
finally: |
|
||||
close_db() |
|
||||
|
|
||||
|
|
||||
def repo_execute(repo, cmd, *args): |
|
||||
return repo.git.execute(cmd.split() + list(args)) |
|
||||
|
|
||||
|
|
||||
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, extensao |
|
||||
|
|
||||
|
|
||||
def build_salvar(repo): |
|
||||
|
|
||||
def salvar(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) |
|
||||
with open(fullname, 'w') as arq: |
|
||||
arq.write(conteudo) |
|
||||
print(fullname) |
|
||||
|
|
||||
return salvar |
|
||||
|
|
||||
|
|
||||
def dump_sapl(sigla): |
|
||||
sigla = sigla[-3:] # ignora prefixo (por ex. 'sapl_cm_') |
|
||||
data_fs_path, documentos_fs_path = [ |
|
||||
DIR_DADOS_MIGRACAO.child( |
|
||||
'datafs', '{}_cm_{}.fs'.format(prefixo, sigla)) |
|
||||
for prefixo in ('Data', 'DocumentosSapl')] |
|
||||
|
|
||||
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) |
|
||||
destino = DIR_DADOS_MIGRACAO.child('repos', nome_banco_legado) |
|
||||
destino.mkdir(parents=True) |
|
||||
repo = git.Repo.init(destino) |
|
||||
if TAG_ZOPE in repo.tags: |
|
||||
print('{}: A exportação de documentos já está feita -- abortando'.format(sigla)) |
|
||||
return |
|
||||
|
|
||||
repo_execute(repo, 'git annex init') |
|
||||
repo_execute(repo, 'git config annex.thin true') |
|
||||
|
|
||||
salvar = build_salvar(repo) |
|
||||
try: |
|
||||
finalizado = False |
|
||||
arq_mtimes = Path(repo.working_dir, 'mtimes.yaml') |
|
||||
mtimes = yaml.load( |
|
||||
arq_mtimes.read_file(), |
|
||||
yaml.Loader |
|
||||
) 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') |
|
||||
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 |
|
||||
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 __name__ == "__main__": |
|
||||
if len(sys.argv) == 2: |
|
||||
sigla = sys.argv[1] |
|
||||
dump_sapl(sigla) |
|
||||
else: |
|
||||
print('Uso: python exporta_zope <sigla>') |
|
@ -1,8 +0,0 @@ |
|||||
# ZODB version 3.7.4 |
|
||||
ZODB==5.3.0 |
|
||||
PyYAML |
|
||||
Unipath |
|
||||
GitPython |
|
||||
pyaml |
|
||||
python-magic |
|
||||
ipython |
|
@ -1,4 +0,0 @@ |
|||||
from unipath import Path |
|
||||
|
|
||||
DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() |
|
||||
TAG_ZOPE = 'zope' |
|
@ -1,15 +0,0 @@ |
|||||
#!/usr/bin/env bash |
|
||||
|
|
||||
# rodar esse script na raiz do projeto |
|
||||
|
|
||||
|
|
||||
if [ $# -ge 1 ]; then |
|
||||
# mysql com senha |
|
||||
parallel -eta --verbose -j+0 ./sapl/legacy/scripts/migra_um_db.sh :::: <(mysql -u $1 -p$2 -e 'show databases;' | grep '^sapl_') ::: $1 ::: $2 |
|
||||
elif [ $# -ge 0 ]; then |
|
||||
# mysql sem senha |
|
||||
parallel -eta --verbose -j+0 ./sapl/legacy/scripts/migra_um_db.sh :::: <(mysql -u $1 -e 'show databases;' | grep '^sapl_') ::: $1 |
|
||||
else |
|
||||
echo "USO:" |
|
||||
echo " $0 <usuário mysql> [senha mysql]" |
|
||||
fi; |
|
@ -1,27 +0,0 @@ |
|||||
#!/usr/bin/env bash |
|
||||
|
|
||||
# rodar esse script na raiz do projeto |
|
||||
if [ $# -eq 1 ]; then |
|
||||
|
|
||||
DIR_MIGRACAO=~/migracao_sapl |
|
||||
|
|
||||
DATE=$(date +%Y-%m-%d) |
|
||||
DIR_LOGS=$DIR_MIGRACAO/logs/$DATE |
|
||||
mkdir -p $DIR_LOGS |
|
||||
|
|
||||
LOG="$DIR_LOGS/$1.migracao.log" |
|
||||
rm -f $LOG |
|
||||
|
|
||||
echo "########################################" | tee -a $LOG |
|
||||
echo "MIGRANDO BANCO $1" | tee -a $LOG |
|
||||
echo "########################################" | tee -a $LOG |
|
||||
echo >> $LOG |
|
||||
|
|
||||
echo "--- MIGRACAO ---" | tee -a $LOG |
|
||||
echo >> $LOG |
|
||||
DATABASE_NAME=$1 ./manage.py migracao_25_31 --settings sapl.legacy_migration_settings 2>&1 | tee -a $LOG |
|
||||
echo >> $LOG |
|
||||
else |
|
||||
echo "USO:" |
|
||||
echo " $0 <nome_database>" |
|
||||
fi; |
|
@ -1,40 +0,0 @@ |
|||||
#!/usr/bin/env python |
|
||||
import re |
|
||||
import sys |
|
||||
|
|
||||
from unipath import Path |
|
||||
|
|
||||
cabecalho = ''' |
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; |
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; |
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; |
|
||||
/*!40101 SET NAMES utf8 */; |
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; |
|
||||
/*!40103 SET TIME_ZONE='+00:00' */; |
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; |
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; |
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; |
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; |
|
||||
|
|
||||
/*!40000 DROP DATABASE IF EXISTS `{banco}`*/; |
|
||||
|
|
||||
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{banco}` /*!40100 DEFAULT CHARACTER SET latin1 */; |
|
||||
|
|
||||
USE `{banco}`; |
|
||||
|
|
||||
''' |
|
||||
|
|
||||
|
|
||||
def normaliza_dump_mysql(nome_arquivo): |
|
||||
arquivo = Path(nome_arquivo).expand() |
|
||||
banco = arquivo.stem |
|
||||
conteudo = arquivo.read_file() |
|
||||
inicio = re.finditer('--\n-- Table structure for table .*\n--\n', conteudo) |
|
||||
inicio = next(inicio).start() |
|
||||
conteudo = cabecalho.format(banco=banco) + conteudo[inicio:] |
|
||||
arquivo.write_file(conteudo) |
|
||||
|
|
||||
|
|
||||
if __name__ == "__main__": |
|
||||
nome_aquivo = sys.argv[1] |
|
||||
normaliza_dump_mysql(nome_aquivo) |
|
@ -1,11 +0,0 @@ |
|||||
#!/usr/bin/env bash |
|
||||
|
|
||||
# (Re)cria todos os bancos postgres para migração |
|
||||
# cria um banco postgres (de mesmo nome) para cada banco mysql cujo nome começa com "sapl_" |
|
||||
|
|
||||
if [ $# -eq 2 ]; then |
|
||||
parallel --verbose -j+0 ./recria_um_db_postgres.sh :::: <(mysql -u $1 -p$2 -e 'show databases;' | grep '^sapl_' | grep -v '_copy$') |
|
||||
else |
|
||||
echo "USO:" |
|
||||
echo " $0 [usuário mysql] [senha mysql]" |
|
||||
fi; |
|
@ -1,15 +0,0 @@ |
|||||
#!/usr/bin/env bash |
|
||||
|
|
||||
# (Re)cria um db postgres |
|
||||
# uso: recria_um_db_postgres <NOME DO BANCO> |
|
||||
|
|
||||
set -e # Exit immediately if a command exits with a non-zero status |
|
||||
|
|
||||
echo "Database $1" |
|
||||
sudo -u postgres psql -c "drop DATABASE if exists $1" |
|
||||
sudo -u postgres psql -c "CREATE DATABASE $1 WITH OWNER = sapl ENCODING = 'UTF8' TABLESPACE = pg_default LC_COLLATE = 'pt_BR.UTF-8' LC_CTYPE = 'pt_BR.UTF-8' CONNECTION LIMIT = -1 TEMPLATE template0;" |
|
||||
|
|
||||
|
|
||||
echo "--- DJANGO MIGRATE ---" | tee -a $LOG |
|
||||
DATABASE_NAME=$1 ./manage.py migrate --settings sapl.legacy_migration_settings |
|
||||
|
|
@ -1,427 +0,0 @@ |
|||||
from collections import OrderedDict |
|
||||
from textwrap import dedent |
|
||||
|
|
||||
import texttable |
|
||||
import yaml |
|
||||
from unipath import Path |
|
||||
|
|
||||
from sapl.legacy.migracao_dados import (PROPAGACOES_DE_EXCLUSAO, |
|
||||
campos_novos_para_antigos, exec_legado, |
|
||||
get_arquivo_ajustes_pre_migracao, |
|
||||
models_novos_para_antigos) |
|
||||
from sapl.legacy_migration_settings import (DIR_DADOS_MIGRACAO, DIR_REPO, |
|
||||
NOME_BANCO_LEGADO) |
|
||||
|
|
||||
|
|
||||
def stripsplit(ll): |
|
||||
return [l.split() for l in ll.strip().splitlines()] |
|
||||
|
|
||||
|
|
||||
def _tab_legado(model): |
|
||||
return models_novos_para_antigos[model]._meta.db_table |
|
||||
|
|
||||
|
|
||||
fks_legado = { |
|
||||
(_tab_legado(m), campos_novos_para_antigos[f]): _tab_legado(f.related_model) # noqa |
|
||||
for m in models_novos_para_antigos |
|
||||
for f in m._meta.fields |
|
||||
if f in campos_novos_para_antigos and f.related_model} |
|
||||
|
|
||||
# acrescenta mapeamentos que não existem em campos_novos_para_antigos |
|
||||
for tabela_origem, campo, tabela_destino in [ |
|
||||
['autor', 'cod_parlamentar', 'parlamentar'], |
|
||||
['autor', 'cod_comissao', 'comissao'], |
|
||||
['autor', 'cod_partido', 'partido']]: |
|
||||
fks_legado[(tabela_origem, campo)] = tabela_destino |
|
||||
|
|
||||
|
|
||||
urls = ''' |
|
||||
autor /sistema/autor |
|
||||
cargo_comissao /sistema/comissao/cargo |
|
||||
legislatura /sistema/parlamentar/legislatura |
|
||||
materia_legislativa /materia |
|
||||
norma_juridica /norma |
|
||||
parlamentar /parlamentar |
|
||||
sessao_legislativa /sistema/mesa-diretora/sessao-legislativa |
|
||||
sessao_plenaria /sessao |
|
||||
status_tramitacao /sistema/materia/status-tramitacao |
|
||||
tipo_autor /sistema/autor/tipo |
|
||||
tipo_expediente /sistema/sessao-plenaria/tipo-expediente |
|
||||
tipo_proposicao /sistema/proposicao/tipo |
|
||||
tipo_resultado_votacao /sistema/sessao-plenaria/tipo-resultado-votacao |
|
||||
unidade_tramitacao /sistema/materia/unidade-tramitacao |
|
||||
tipo_documento /sistema/materia/tipo-documento |
|
||||
orgao /sistema/materia/orgao |
|
||||
tipo_sessao_plenaria /sistema/sessao-plenaria/tipo |
|
||||
cargo_mesa /sistema/mesa-diretora/cargo-mesa |
|
||||
documento_administrativo /docadm |
|
||||
tipo_materia_legislativa /sistema/materia/tipo |
|
||||
tipo_norma_juridica /sistema/norma/tipo |
|
||||
comissao /comissao |
|
||||
assunto_materia /sistema/assunto-materia |
|
||||
coligacao /sistema/coligacao |
|
||||
nivel_instrucao /sistema/parlamentar/nivel-instrucao |
|
||||
partido /sistema/parlamentar/partido |
|
||||
regime_tramitacao /sistema/materia/regime-tramitacao |
|
||||
tipo_comissao /sistema/comissao/tipo |
|
||||
tipo_documento_administrativo /sistema/tipo-documento-adm |
|
||||
registro_votacao /admin/sessao/registrovotacao |
|
||||
tipo_dependente /sistema/parlamentar/tipo-dependente |
|
||||
origem /sistema/materia/origem |
|
||||
documento_acessorio /materia/documentoacessorio |
|
||||
tipo_fim_relatoria /sistema/materia/tipo-fim-relatoria |
|
||||
tipo_situacao_militar /sistema/parlamentar/tipo-militar |
|
||||
''' |
|
||||
urls = dict(stripsplit(urls)) |
|
||||
|
|
||||
|
|
||||
def get_tabela_campo_tipo_proposicao(tip_proposicao): |
|
||||
[(ind_mat_ou_doc,)] = exec_legado(''' |
|
||||
select ind_mat_ou_doc from tipo_proposicao where tip_proposicao = {}; |
|
||||
'''.format(tip_proposicao)) |
|
||||
if ind_mat_ou_doc == 'M': |
|
||||
return 'tipo_materia_legislativa', 'tip_materia' |
|
||||
elif ind_mat_ou_doc == 'D': |
|
||||
return 'tipo_documento', 'tip_documento' |
|
||||
else: |
|
||||
raise(Exception('ind_mat_ou_doc inválido')) |
|
||||
|
|
||||
|
|
||||
CAMPOS_ORIGEM_PARA_ALVO = { |
|
||||
'cod_unid_tram_dest': 'cod_unid_tramitacao', |
|
||||
'cod_unid_tram_local': 'cod_unid_tramitacao', |
|
||||
'tip_id_basica': 'tip_materia', |
|
||||
'cod_local_origem_externa': 'cod_origem', |
|
||||
} |
|
||||
|
|
||||
|
|
||||
def get_excluido(fk): |
|
||||
tabela_origem, campo, valor = [fk[k] for k in ('tabela', 'campo', 'valor')] |
|
||||
|
|
||||
if tabela_origem == 'tipo_proposicao': |
|
||||
tip_proposicao = fk['pk']['tip_proposicao'] |
|
||||
tabela_alvo, campo = get_tabela_campo_tipo_proposicao(tip_proposicao) |
|
||||
elif tabela_origem == 'proposicao' and campo == 'cod_mat_ou_doc': |
|
||||
[(ind_mat_ou_doc,)] = exec_legado(''' |
|
||||
select ind_mat_ou_doc from |
|
||||
proposicao p inner join tipo_proposicao t |
|
||||
on p.tip_proposicao = t.tip_proposicao |
|
||||
where cod_proposicao = {}; |
|
||||
'''.format(fk['pk']['cod_proposicao'])) |
|
||||
if ind_mat_ou_doc == 'M': |
|
||||
tabela_alvo, campo = 'materia_legislativa', 'cod_materia' |
|
||||
elif ind_mat_ou_doc == 'D': |
|
||||
tabela_alvo, campo = 'documento_acessorio', 'cod_documento' |
|
||||
else: |
|
||||
raise(Exception('ind_mat_ou_doc inválido')) |
|
||||
else: |
|
||||
tabela_alvo = fks_legado[(tabela_origem, campo)] |
|
||||
|
|
||||
# troca nome de campo pelo correspondente na tabela alvo |
|
||||
campo = CAMPOS_ORIGEM_PARA_ALVO.get(campo, campo) |
|
||||
|
|
||||
sql = 'select ind_excluido, t.* from {} t where {} = {}'.format( |
|
||||
tabela_alvo, campo, valor) |
|
||||
res = list(exec_legado(sql)) |
|
||||
return tabela_origem, campo, valor, tabela_alvo, res |
|
||||
|
|
||||
|
|
||||
def get_desc_materia(cod_materia): |
|
||||
sql = ''' |
|
||||
select t.sgl_tipo_materia, t.des_tipo_materia, |
|
||||
m.num_ident_basica, m.ano_ident_basica |
|
||||
from materia_legislativa m inner join tipo_materia_legislativa t |
|
||||
on m.tip_id_basica = t.tip_materia |
|
||||
where cod_materia = {}; |
|
||||
'''.format(cod_materia) |
|
||||
return list(exec_legado(sql))[0] |
|
||||
|
|
||||
|
|
||||
def get_link_proposicao(cod_proposicao, slug): |
|
||||
url_base = get_url(slug) |
|
||||
return 'http://{}/cadastros/proposicao/proposicao_mostrar_proc?cod_proposicao={}'.format( # noqa |
|
||||
url_base, cod_proposicao) |
|
||||
|
|
||||
|
|
||||
def get_apaga_materias_de_proposicoes(fks, slug): |
|
||||
refs_materias = [['id proposicao', 'sigla tipo matéria', |
|
||||
'tipo matéria', 'número matéria', 'ano matéria']] |
|
||||
sqls = [] |
|
||||
cods_proposicoes = [] |
|
||||
|
|
||||
for fk in fks: |
|
||||
cod_proposicao = fk['pk']['cod_proposicao'] |
|
||||
cods_proposicoes.append(cod_proposicao) |
|
||||
assert fk['campo'] == 'cod_materia' |
|
||||
up = 'update proposicao set cod_materia = NULL where cod_proposicao = {};' # noqa |
|
||||
refs_materias.append( |
|
||||
[cod_proposicao, *get_desc_materia(fk['valor'])]) |
|
||||
sqls.append(up.format(cod_proposicao)) |
|
||||
|
|
||||
table = texttable.Texttable() |
|
||||
table.set_cols_width([10, 10, 50, 10, 10]) |
|
||||
table.set_deco(table.VLINES | table.HEADER) |
|
||||
table.add_rows(refs_materias) |
|
||||
|
|
||||
links = '\n'.join([get_link_proposicao(p, slug) |
|
||||
for p in cods_proposicoes]) |
|
||||
sqls = '\n'.join(sqls) |
|
||||
if not sqls: |
|
||||
return '' |
|
||||
else: |
|
||||
return ''' |
|
||||
/* REFERÊNCIAS A MATÉRIAS APAGADAS DE PROPOSIÇÕES |
|
||||
|
|
||||
ATENÇÃO |
|
||||
|
|
||||
As seguintes proposições apontaram no passado para matérias |
|
||||
e esses apontamentos foram em algum momento retirados. |
|
||||
|
|
||||
Elas foram migradas da forma com estão agora: sem apontar para nenhuma matéria. |
|
||||
Entretanto, talvez você deseje rever esses apontamentos. |
|
||||
|
|
||||
Segue então uma lista dos apontamentos anteriores que detectamos. |
|
||||
|
|
||||
{} |
|
||||
|
|
||||
Para facilitar sua conferência, seguem os links para as proposições envolvidas: |
|
||||
|
|
||||
{} |
|
||||
|
|
||||
*/ |
|
||||
|
|
||||
{} |
|
||||
|
|
||||
'''.format(table.draw(), links, sqls) |
|
||||
|
|
||||
|
|
||||
def get_dependencias_a_ressuscitar(slug): |
|
||||
ocorrencias = yaml.load( |
|
||||
Path(DIR_REPO.child('ocorrencias.yaml').read_file()), |
|
||||
yaml.Loader |
|
||||
) |
|
||||
fks_faltando = ocorrencias.get('fk') |
|
||||
if not fks_faltando: |
|
||||
return [], [], [] |
|
||||
|
|
||||
proposicoes_para_materia = [ |
|
||||
fk for fk in fks_faltando |
|
||||
if fk['tabela'] == 'proposicao' and fk['campo'] == 'cod_materia'] |
|
||||
|
|
||||
preambulo = get_apaga_materias_de_proposicoes( |
|
||||
proposicoes_para_materia, slug) |
|
||||
|
|
||||
propagacoes = {(o, c) for t, o, c in PROPAGACOES_DE_EXCLUSAO} |
|
||||
|
|
||||
fks_faltando = [fk for fk in fks_faltando |
|
||||
if fk not in proposicoes_para_materia |
|
||||
and (fk['tabela'], fk['campo']) not in propagacoes] |
|
||||
|
|
||||
excluidos = [get_excluido(fk) for fk in fks_faltando] |
|
||||
desexcluir, criar = [ |
|
||||
set([(tabela_alvo, campo, valor) |
|
||||
for tabela_origem, campo, valor, tabela_alvo, res in excluidos |
|
||||
if condicao(res)]) |
|
||||
for condicao in ( |
|
||||
# o registro existe e ind_excluido == 1 |
|
||||
lambda res: res and res[0][0] == 1, |
|
||||
# o registro não existe |
|
||||
lambda res: not res |
|
||||
)] |
|
||||
return preambulo, desexcluir, criar |
|
||||
|
|
||||
|
|
||||
# deve ser idempotente pois é usada na criação de autor |
|
||||
# por isso o ON DUPLICATE KEY UPDATE |
|
||||
SQL_INSERT_TIPO_AUTOR = ''' |
|
||||
insert into tipo_autor (tip_autor, des_tipo_autor, ind_excluido) |
|
||||
values ({}, "DESCONHECIDO", 0) ON DUPLICATE KEY UPDATE ind_excluido = 0; |
|
||||
''' |
|
||||
|
|
||||
# deve ser idempotente pois é usada na criação de comissao |
|
||||
# por isso o ON DUPLICATE KEY UPDATE |
|
||||
SQL_INSERT_TIPO_COMISSAO = ''' |
|
||||
insert into tipo_comissao (tip_comissao, nom_tipo_comissao, sgl_natureza_comissao, sgl_tipo_comissao, des_dispositivo_regimental, ind_excluido) |
|
||||
values ({}, "DESCONHECIDO", "P", "DESC", NULL, 0) |
|
||||
ON DUPLICATE KEY UPDATE ind_excluido = 0; |
|
||||
''' |
|
||||
|
|
||||
SQLS_CRIACAO = [ |
|
||||
('tipo_proposicao', ''' |
|
||||
insert into tipo_materia_legislativa ( |
|
||||
tip_materia, sgl_tipo_materia, des_tipo_materia, ind_num_automatica, |
|
||||
quorum_minimo_votacao, ind_excluido) |
|
||||
values (0, "DESC", "DESCONHECIDO", 0, 0, 0); |
|
||||
|
|
||||
insert into tipo_proposicao ( |
|
||||
tip_proposicao, des_tipo_proposicao, ind_mat_ou_doc, tip_mat_ou_doc, |
|
||||
nom_modelo, ind_excluido) |
|
||||
values ({}, "DESCONHECIDO", "M", 0, "DESCONHECIDO", 0); |
|
||||
''', ['tipo_materia_legislativa', 0] |
|
||||
), |
|
||||
('tipo_resultado_votacao', ''' |
|
||||
insert into tipo_resultado_votacao ( |
|
||||
tip_resultado_votacao, nom_resultado, ind_excluido) |
|
||||
values ({}, "DESCONHECIDO", 0); |
|
||||
'''), |
|
||||
('tipo_autor', SQL_INSERT_TIPO_AUTOR), |
|
||||
('unidade_tramitacao', ''' |
|
||||
insert into unidade_tramitacao ( |
|
||||
cod_unid_tramitacao, cod_comissao, cod_orgao, cod_parlamentar, ind_excluido) |
|
||||
values ({}, NULL, NULL, 0, 0); |
|
||||
'''), |
|
||||
('autor', SQL_INSERT_TIPO_AUTOR.format(0) + ''' |
|
||||
insert into autor ( |
|
||||
cod_autor, cod_partido, cod_comissao, cod_parlamentar, tip_autor, |
|
||||
nom_autor, des_cargo, col_username, ind_excluido) |
|
||||
values ({}, 0, 0, 0, 0, "DESCONHECIDO", "DESCONHECIDO", NULL, 0); |
|
||||
'''), |
|
||||
('tipo_documento', ''' |
|
||||
insert into tipo_documento (tip_documento, des_tipo_documento, ind_excluido) |
|
||||
values ({}, "DESCONHECIDO", 0); |
|
||||
'''), |
|
||||
('partido', ''' |
|
||||
insert into partido (cod_partido, sgl_partido, nom_partido, dat_criacao, dat_extincao, ind_excluido) |
|
||||
values ({}, "DESC", "DESCONHECIDO", NULL, NULL, 0); |
|
||||
'''), |
|
||||
('legislatura', ''' |
|
||||
insert into legislatura (num_legislatura, dat_inicio, dat_fim, dat_eleicao, ind_excluido) |
|
||||
values ({}, "1/1/1", "1/1/1", "1/1/1", 0); |
|
||||
'''), |
|
||||
('cargo_mesa', ''' |
|
||||
insert into cargo_mesa (cod_cargo, des_cargo, ind_unico, ind_excluido) |
|
||||
values ({}, "DESCONHECIDO", 0, 0); |
|
||||
'''), |
|
||||
('orgao', ''' |
|
||||
insert into orgao (cod_orgao, nom_orgao, sgl_orgao, ind_unid_deliberativa, end_orgao, num_tel_orgao, ind_excluido) |
|
||||
values ({}, "DESCONHECIDO", "DESC", 0, NULL, NULL, 0); |
|
||||
'''), |
|
||||
('origem', ''' |
|
||||
insert into origem (cod_origem, sgl_origem, nom_origem, ind_excluido) |
|
||||
values ({}, "DESC", "DESCONHECIDO", 0); |
|
||||
'''), |
|
||||
('tipo_comissao', SQL_INSERT_TIPO_COMISSAO), |
|
||||
('comissao', SQL_INSERT_TIPO_COMISSAO.format(0) + ''' |
|
||||
insert into comissao (cod_comissao, tip_comissao, nom_comissao, sgl_comissao, dat_criacao, |
|
||||
ind_unid_deliberativa, ind_excluido) |
|
||||
values ({}, 0, "DESCONHECIDO", "DESC", "1-1-1", 0, 0); |
|
||||
'''), |
|
||||
('parlamentar', ''' |
|
||||
insert into parlamentar (cod_parlamentar, nom_completo, nom_parlamentar, sex_parlamentar, cod_casa, ind_ativo, ind_unid_deliberativa, ind_excluido) |
|
||||
values ({}, "DESCONHECIDO", "DESCONHECIDO", "M", 0, 0, 0, 0); |
|
||||
'''), |
|
||||
('tipo_sessao_plenaria', ''' |
|
||||
insert into tipo_sessao_plenaria (tip_sessao, nom_sessao, ind_excluido, num_minimo) values ({}, "DESCONHECIDO", 0, 0); |
|
||||
'''), |
|
||||
] |
|
||||
SQLS_CRIACAO = {k: (dedent(sql.strip()), extras) |
|
||||
for k, sql, *extras in SQLS_CRIACAO} |
|
||||
|
|
||||
|
|
||||
def criar_sessao_legislativa(campo, valor): |
|
||||
assert campo == 'cod_sessao_leg' |
|
||||
[(num_legislatura,)] = exec_legado( |
|
||||
'select min(num_legislatura) from legislatura where ind_excluido <> 1') |
|
||||
return ''' |
|
||||
insert into sessao_legislativa ( |
|
||||
cod_sessao_leg, num_legislatura, num_sessao_leg, tip_sessao_leg, |
|
||||
dat_inicio, dat_fim, dat_inicio_intervalo, dat_fim_intervalo, |
|
||||
ind_excluido) values ({}, {}, 0, "O", |
|
||||
"1900-01-01", "1900-01-02", "1900-01-01", "1900-01-02", 0); |
|
||||
'''.format(valor, num_legislatura) |
|
||||
|
|
||||
|
|
||||
def get_link(tabela_alvo, valor, slug): |
|
||||
url_base = get_url(slug) |
|
||||
return 'http://{}{}/{}'.format(url_base, urls[tabela_alvo], valor) |
|
||||
|
|
||||
|
|
||||
def get_sql_desexcluir(tabela_alvo, campo, valor, slug): |
|
||||
sql = 'update {} set ind_excluido = 0 where {} = {};'.format( |
|
||||
tabela_alvo, campo, valor) |
|
||||
return sql, [get_link(tabela_alvo, valor, slug)] |
|
||||
|
|
||||
|
|
||||
def get_sql_criar(tabela_alvo, campo, valor, slug): |
|
||||
if tabela_alvo == 'sessao_legislativa': |
|
||||
sql = criar_sessao_legislativa(campo, valor) |
|
||||
extras = [] |
|
||||
else: |
|
||||
sql, extras = SQLS_CRIACAO[tabela_alvo] |
|
||||
sql = sql.format(valor) |
|
||||
links = [get_link(tabela_alvo, valor, slug)] |
|
||||
for tabela_extra, valor_extra in extras: |
|
||||
links.insert(0, get_link(tabela_extra, valor_extra, slug)) |
|
||||
return sql, links |
|
||||
|
|
||||
|
|
||||
TEMPLATE_RESSUSCITADOS = '''{} |
|
||||
/* RESSUSCITADOS |
|
||||
|
|
||||
|
|
||||
SOBRE REGISTROS QUE ESTAVAM APAGADOS E FORAM RESTAURADOS |
|
||||
|
|
||||
Os registros que listamos a seguir estavam excluídos (ou simplesmente não existiam) no sistema antigo e precisaram ser restaurados (ou criados) para completarmos a migração. Foi necessário fazer isso pois outros registros ativos no sistema apontam para eles. |
|
||||
Vocês agora podem decidir mantê-los, ajustá-los ou excluí-los. Segue a lista: |
|
||||
|
|
||||
{} |
|
||||
|
|
||||
Se a opção for por excluir um desses registros novamente, note que só será possível fazer isso quando nada mais no sistema fizer referência a ele. |
|
||||
|
|
||||
Ao tentar excluir um registro usado em outras partes do sistema, você verá uma lista dos itens que apontam para ele de alguma forma. Para conseguir excluir você deve editar cada dos dos itens dependentes lista mostrada, retirando ou trocando a referência ao que deseja excluir. |
|
||||
|
|
||||
*/ |
|
||||
|
|
||||
{} |
|
||||
''' |
|
||||
|
|
||||
|
|
||||
def get_url(slug): |
|
||||
return 'sapl.{}.leg.br'.format(slug.replace('-', '.')) |
|
||||
|
|
||||
|
|
||||
def sem_repeticoes_mantendo_ordem(sequencia): |
|
||||
return OrderedDict.fromkeys(sequencia).keys() |
|
||||
|
|
||||
|
|
||||
def get_sqls_desexcluir_criar(preambulo, desexcluir, criar, slug): |
|
||||
sqls_links = [get_sql(*(args + (slug,))) |
|
||||
for itens, get_sql in ((desexcluir, get_sql_desexcluir), |
|
||||
(criar, get_sql_criar)) |
|
||||
for args in itens] |
|
||||
if not sqls_links: |
|
||||
return '' |
|
||||
else: |
|
||||
sqls, links = zip(*sqls_links) |
|
||||
|
|
||||
sqls = [dedent(s.strip()) + ';' |
|
||||
for sql in sqls |
|
||||
for s in sql.split(';') if s.strip()] |
|
||||
sqls = sem_repeticoes_mantendo_ordem(sqls) |
|
||||
|
|
||||
links = (l for ll in links for l in ll) # flatten |
|
||||
links = sem_repeticoes_mantendo_ordem(links) |
|
||||
|
|
||||
sqls, links = ['\n'.join(sorted(s)) for s in [sqls, links]] |
|
||||
return TEMPLATE_RESSUSCITADOS.format(preambulo, links, sqls) |
|
||||
|
|
||||
|
|
||||
def get_ressuscitar(slug): |
|
||||
preambulo, desexcluir, criar = get_dependencias_a_ressuscitar(slug) |
|
||||
return get_sqls_desexcluir_criar(preambulo, desexcluir, criar, slug) |
|
||||
|
|
||||
|
|
||||
def get_slug(): |
|
||||
arq = DIR_DADOS_MIGRACAO.child('siglas_para_slugs.yaml') |
|
||||
with open(arq, 'r') as arq: |
|
||||
siglas_para_slugs = yaml.load(arq, yaml.Loader) |
|
||||
sigla = NOME_BANCO_LEGADO[-3:] |
|
||||
return siglas_para_slugs[sigla] |
|
||||
|
|
||||
|
|
||||
def adiciona_ressuscitar(): |
|
||||
sqls = get_ressuscitar(get_slug()) |
|
||||
if sqls.strip(): |
|
||||
arq_ajustes_pre_migracao = get_arquivo_ajustes_pre_migracao() |
|
||||
conteudo = arq_ajustes_pre_migracao.read_file() |
|
||||
arq_ajustes_pre_migracao.write_file('{}\n{}'.format(conteudo, sqls)) |
|
@ -1,8 +0,0 @@ |
|||||
#!/usr/bin/env bash |
|
||||
|
|
||||
# Inicia um shell_plus com as configurações de migração usando um banco específico |
|
||||
# Uso: ./shell_para_migracao.sh <NOME DO BANCO> |
|
||||
|
|
||||
# Rode esse script a partir da raiz do projeto |
|
||||
|
|
||||
DATABASE_NAME=$1 ./manage.py shell_plus --settings sapl.legacy_migration_settings |
|
@ -1,14 +0,0 @@ |
|||||
import inspect |
|
||||
|
|
||||
from sapl.base.models import Autor |
|
||||
from sapl.legacy.migracao_dados import appconfs |
|
||||
|
|
||||
|
|
||||
def get_models_com_referencia_a(apontado): |
|
||||
|
|
||||
def tem_referencia_a_apontado(model): |
|
||||
return any(getattr(field, 'related_model', None) == apontado |
|
||||
for field in model._meta.get_fields()) |
|
||||
|
|
||||
return [model for app in appconfs for model in app.models.values() |
|
||||
if tem_referencia_a_apontado(model)] |
|
@ -1,62 +0,0 @@ |
|||||
from random import shuffle |
|
||||
|
|
||||
from .migracao_dados import (_formatar_lista_para_sql, |
|
||||
get_autorias_sem_repeticoes, |
|
||||
get_reapontamento_de_autores_repetidos) |
|
||||
|
|
||||
|
|
||||
def test_unifica_autores_repetidos_no_legado(): |
|
||||
|
|
||||
# cod_parlamentar, cod_autor |
|
||||
autores = [[0, 0], |
|
||||
[1, 10], |
|
||||
[1, 11], |
|
||||
[1, 12], |
|
||||
[2, 20], |
|
||||
[2, 21], |
|
||||
[2, 22], |
|
||||
[3, 30], |
|
||||
[3, 31], |
|
||||
[4, 40], |
|
||||
[5, 50]] |
|
||||
reapontamento, apagar = get_reapontamento_de_autores_repetidos(autores) |
|
||||
assert reapontamento == {10: 10, 11: 10, 12: 10, |
|
||||
20: 20, 21: 20, 22: 20, |
|
||||
30: 30, 31: 30} |
|
||||
assert sorted(apagar) == [11, 12, 21, 22, 31] |
|
||||
|
|
||||
# cod_autor, cod_materia, ind_primeiro_autor |
|
||||
autoria = [[10, 111, 0], # não é repetida, mas envolve um autor repetido |
|
||||
|
|
||||
[22, 222, 1], # não é repetida, mas envolve um autor repetido |
|
||||
|
|
||||
[10, 777, 1], # repetição c ind_primeiro_autor==1 no INÍCIO |
|
||||
[10, 777, 0], |
|
||||
[11, 777, 0], |
|
||||
[12, 777, 0], |
|
||||
|
|
||||
[30, 888, 0], # repetição c ind_primeiro_autor==1 no MEIO |
|
||||
[31, 888, 1], |
|
||||
[30, 888, 0], |
|
||||
|
|
||||
[11, 999, 0], # repetição SEM ind_primeiro_autor==1 |
|
||||
[12, 999, 0], |
|
||||
|
|
||||
[21, 999, 0], # repetição SEM ind_primeiro_autor==1 |
|
||||
[22, 999, 0], |
|
||||
] |
|
||||
shuffle(autoria) # não devemos supor ordem na autoria |
|
||||
nova_autoria = get_autorias_sem_repeticoes(autoria, reapontamento) |
|
||||
assert nova_autoria == sorted([(10, 111, 0), |
|
||||
(20, 222, 1), |
|
||||
(10, 777, 1), |
|
||||
(30, 888, 1), |
|
||||
(10, 999, 0), |
|
||||
(20, 999, 0), |
|
||||
]) |
|
||||
|
|
||||
|
|
||||
def test_formatar_lista_para_sql(): |
|
||||
assert _formatar_lista_para_sql([1, 2, 3]) == '(1, 2, 3)' |
|
||||
assert _formatar_lista_para_sql([1]) == '(1)' |
|
||||
assert _formatar_lista_para_sql([]) is None |
|
@ -1,113 +0,0 @@ |
|||||
|
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey |
|
||||
|
|
||||
from sapl.base.models import AppConfig, Autor, CasaLegislativa, TipoAutor |
|
||||
from sapl.comissoes.models import \ |
|
||||
DocumentoAcessorio as DocumentoAcessorioComissoes |
|
||||
from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao |
|
||||
from sapl.legacy.migracao_dados import appconfs, get_renames, legacy_app |
|
||||
from sapl.materia.models import (AcompanhamentoMateria, DocumentoAcessorio, |
|
||||
MateriaLegislativa, Proposicao, |
|
||||
TipoMateriaLegislativa, TipoProposicao, |
|
||||
Tramitacao) |
|
||||
from sapl.norma.models import (AnexoNormaJuridica, NormaJuridica, |
|
||||
NormaRelacionada, TipoVinculoNormaJuridica) |
|
||||
from sapl.parlamentares.models import (Frente, Mandato, Parlamentar, Partido, |
|
||||
TipoAfastamento, Votante, Bloco) |
|
||||
from sapl.protocoloadm.models import DocumentoAdministrativo |
|
||||
from sapl.sessao.models import (Bancada, CargoBancada, |
|
||||
ExpedienteMateria, Orador, OradorExpediente, |
|
||||
OrdemDia, RegistroVotacao, ResumoOrdenacao, |
|
||||
SessaoPlenaria, TipoResultadoVotacao, |
|
||||
VotoParlamentar) |
|
||||
|
|
||||
RENAMING_IGNORED_MODELS = [ |
|
||||
Votante, Frente, Bancada, Bloco, Votante, # parlamentares |
|
||||
Composicao, Reuniao, DocumentoAcessorioComissoes, # commissoes |
|
||||
AppConfig, CasaLegislativa, # base |
|
||||
CargoBancada, ResumoOrdenacao, # sessao |
|
||||
AnexoNormaJuridica, TipoVinculoNormaJuridica, # norma |
|
||||
|
|
||||
] |
|
||||
|
|
||||
RENAMING_IGNORED_FIELDS = [ |
|
||||
(TipoAfastamento, {'indicador'}), |
|
||||
(Participacao, {'composicao'}), |
|
||||
(Proposicao, { |
|
||||
'ano', 'content_type', 'object_id', 'conteudo_gerado_related', |
|
||||
'status', 'hash_code', 'texto_original'}), |
|
||||
(TipoProposicao, { |
|
||||
'object_id', 'content_type', 'tipo_conteudo_related', 'perfis', |
|
||||
# não estou entendendo como esses campos são enumerados, |
|
||||
# mas eles não fazem parte da migração |
|
||||
# 'tipomaterialegislativa_set', 'tipodocumento_set', |
|
||||
}), |
|
||||
|
|
||||
(Tramitacao, {'ultima'}), |
|
||||
(SessaoPlenaria, {'finalizada', 'iniciada', 'painel_aberto', 'interativa', |
|
||||
'upload_ata', |
|
||||
'upload_anexo', |
|
||||
'upload_pauta'}), |
|
||||
(ExpedienteMateria, {'votacao_aberta', 'registro_aberto'}), |
|
||||
(OrdemDia, {'votacao_aberta', 'registro_aberto'}), |
|
||||
(NormaJuridica, {'texto_integral', 'data_ultima_atualizacao', 'assuntos'}), |
|
||||
(Parlamentar, { |
|
||||
'uf_residencia', 'municipio_residencia', 'cropping', 'fotografia'}), |
|
||||
(Partido, {'logo_partido', 'observacao'}), |
|
||||
(MateriaLegislativa, { |
|
||||
'autores', 'anexadas', 'data_ultima_atualizacao', 'texto_original'}), |
|
||||
(DocumentoAdministrativo, { |
|
||||
'protocolo', 'numero_externo', 'texto_integral'}), |
|
||||
(Mandato, {'titular', 'data_fim_mandato', 'data_inicio_mandato'}), |
|
||||
(TipoMateriaLegislativa, {'sequencia_numeracao'}), |
|
||||
(TipoAutor, {'content_type'}), |
|
||||
(TipoResultadoVotacao, {'natureza'}), |
|
||||
(RegistroVotacao, {'ordem', 'expediente'}), |
|
||||
(DocumentoAcessorio, {'arquivo', 'data_ultima_atualizacao'}), |
|
||||
(OradorExpediente, {'upload_anexo', 'observacao'}), |
|
||||
(Orador, {'upload_anexo', 'observacao'}), |
|
||||
(VotoParlamentar, {'user', 'ip', 'expediente', 'data_hora', 'ordem'}), |
|
||||
(NormaRelacionada, {'tipo_vinculo'}), |
|
||||
(AcompanhamentoMateria, {'confirmado', 'data_cadastro', 'usuario'}), |
|
||||
(Autor, {'user', 'content_type', 'object_id', 'autor_related'}), |
|
||||
(Comissao, {'ativa'}), |
|
||||
(Reuniao, {'url_audio', 'url_video', 'local_reuniao', 'upload_anexo', |
|
||||
'periodo', 'upload_pauta', 'tema', 'hora_fim', 'upload_ata', |
|
||||
'nome', 'hora_inicio'}) |
|
||||
] |
|
||||
|
|
||||
|
|
||||
def test_get_renames(): |
|
||||
field_renames, model_renames = get_renames() |
|
||||
all_models = {m for ac in appconfs for m in ac.get_models()} |
|
||||
for model in all_models: |
|
||||
field_names = {f.name for f in model._meta.get_fields() |
|
||||
if f.name != 'id' |
|
||||
and (f.concrete or isinstance(f, GenericForeignKey))} |
|
||||
if model not in field_renames: |
|
||||
# check ignored models in renaming |
|
||||
assert model in RENAMING_IGNORED_MODELS |
|
||||
else: |
|
||||
renamed = set(field_renames[model].keys()) |
|
||||
|
|
||||
match_msg_template = 'All %s field names mentioned in renames ' \ |
|
||||
'must match a %s field' |
|
||||
|
|
||||
# all renamed field references correspond to a current field |
|
||||
assert renamed <= field_names, \ |
|
||||
match_msg_template % ('new', 'current') |
|
||||
|
|
||||
# ignored fields are explicitly listed |
|
||||
missing = field_names - renamed |
|
||||
if missing: |
|
||||
assert (model, missing) in RENAMING_IGNORED_FIELDS, \ |
|
||||
'Campos faltando na renomeação,' \ |
|
||||
'mas não listados explicitamente: ({}, {})'.format( |
|
||||
model.__name__, missing) |
|
||||
|
|
||||
# all old names correspond to a legacy field |
|
||||
legacy_model = legacy_app.get_model( |
|
||||
model_renames.get(model, model.__name__)) |
|
||||
legacy_field_names = {f.name for f in legacy_model._meta.fields} |
|
||||
assert set(field_renames[model].values()) <= legacy_field_names, \ |
|
||||
match_msg_template % ('old', 'legacy') |
|
@ -1,206 +0,0 @@ |
|||||
import unicodedata |
|
||||
|
|
||||
from pytz import timezone |
|
||||
|
|
||||
UF_PARA_TIMEZONE = ''' |
|
||||
AC America/Rio_Branco |
|
||||
AL America/Maceio |
|
||||
AP America/Belem |
|
||||
AM America/Manaus |
|
||||
BA America/Bahia |
|
||||
CE America/Fortaleza |
|
||||
DF America/Sao_Paulo |
|
||||
ES America/Sao_Paulo |
|
||||
GO America/Sao_Paulo |
|
||||
MA America/Fortaleza |
|
||||
MT America/Cuiaba |
|
||||
MS America/Campo_Grande |
|
||||
MG America/Sao_Paulo |
|
||||
PR America/Sao_Paulo |
|
||||
PB America/Fortaleza |
|
||||
PA America/Belem |
|
||||
PE America/Recife |
|
||||
PI America/Fortaleza |
|
||||
RJ America/Sao_Paulo |
|
||||
RN America/Fortaleza |
|
||||
RS America/Sao_Paulo |
|
||||
RO America/Porto_Velho |
|
||||
RR America/Boa_Vista |
|
||||
SC America/Sao_Paulo |
|
||||
SE America/Maceio |
|
||||
SP America/Sao_Paulo |
|
||||
TO America/Araguaina |
|
||||
''' |
|
||||
UF_PARA_TIMEZONE = dict(line.split() |
|
||||
for line in UF_PARA_TIMEZONE.strip().splitlines()) |
|
||||
|
|
||||
|
|
||||
def normalizar_texto(texto): |
|
||||
# baseado em https://gist.github.com/j4mie/557354 |
|
||||
norm = unicodedata.normalize('NFKD', texto.lower()) |
|
||||
return norm.encode('ASCII', 'ignore').decode('ascii') |
|
||||
|
|
||||
# Exceções (Anazonas e Pará): |
|
||||
# leste do Amazonas: America/Manaus |
|
||||
# oeste do Amazonas: America/Eirunepe |
|
||||
# leste do Pará: America/Belem |
|
||||
# oeste do Pará: America/Santarem |
|
||||
# fontes: |
|
||||
# https://en.wikipedia.org/wiki/Time_in_Brazil |
|
||||
# https://www.zeitverschiebung.net/en/timezone/america--belem |
|
||||
# https://www.zeitverschiebung.net/en/timezone/america--santarem |
|
||||
# https://www.zeitverschiebung.net/en/timezone/america--manaus |
|
||||
# https://www.zeitverschiebung.net/en/timezone/america--eirunepe |
|
||||
|
|
||||
|
|
||||
TZ_CIDADES_AMAZONAS_E_PARA = [ |
|
||||
('America/Manaus', ''' |
|
||||
Manaus |
|
||||
Itacoatiara |
|
||||
Parintins |
|
||||
Manacapuru |
|
||||
Coari |
|
||||
Tefé |
|
||||
Humaitá |
|
||||
Tabatinga |
|
||||
Rio Preto da Eva |
|
||||
Maués |
|
||||
Carauari |
|
||||
Fonte Boa |
|
||||
São Gabriel da Cachoeira |
|
||||
Boca do Acre |
|
||||
Manicoré |
|
||||
Nova Olinda do Norte |
|
||||
Borba |
|
||||
São Paulo de Olivença |
|
||||
Barreirinha |
|
||||
Codajás |
|
||||
Iranduba |
|
||||
Novo Aripuanã |
|
||||
Urucurituba |
|
||||
Manaquiri |
|
||||
Guajará |
|
||||
Autazes |
|
||||
Santo Antônio do Içá |
|
||||
Urucará |
|
||||
Anori |
|
||||
Pauini |
|
||||
Barcelos |
|
||||
Careiro da Várzea |
|
||||
Canutama |
|
||||
Jutaí |
|
||||
Alvarães |
|
||||
'''), |
|
||||
('America/Eirunepe', ''' |
|
||||
Eirunepé |
|
||||
Benjamin Constant |
|
||||
Envira |
|
||||
'''), |
|
||||
('America/Belem', ''' |
|
||||
Belém |
|
||||
Ananindeua |
|
||||
Macapá |
|
||||
Marabá |
|
||||
Castanhal |
|
||||
Santana |
|
||||
Abaetetuba |
|
||||
Tucuruí |
|
||||
Paragominas |
|
||||
Bragança |
|
||||
Benevides |
|
||||
Capanema |
|
||||
Breves |
|
||||
Cametá |
|
||||
Salinópolis |
|
||||
Tomé Açu |
|
||||
Capitão Poço |
|
||||
Barcarena |
|
||||
Vigia |
|
||||
São Miguel do Guamá |
|
||||
Conceição do Araguaia |
|
||||
Igarapé Miri |
|
||||
Igarapé Açu |
|
||||
Moju |
|
||||
Portel |
|
||||
Itupiranga |
|
||||
Viseu |
|
||||
Soure |
|
||||
Mocajuba |
|
||||
São Félix do Xingu |
|
||||
Augusto Corrêa |
|
||||
Tucumã |
|
||||
Santa Maria do Pará |
|
||||
Acará |
|
||||
Maracanã |
|
||||
Baião |
|
||||
Curuçá |
|
||||
Marapanim |
|
||||
Oeiras do Pará |
|
||||
São João de Pirabas |
|
||||
Santo Antônio do Tauá |
|
||||
São Caetano de Odivelas |
|
||||
Ourém |
|
||||
Muaná |
|
||||
Afuá |
|
||||
Mazagão |
|
||||
Gurupá |
|
||||
Bujaru |
|
||||
Senador José Porfírio |
|
||||
Irituia |
|
||||
parauapebas |
|
||||
brejo grande do araguaia |
|
||||
santana do araguaia |
|
||||
ourilandia do norte |
|
||||
marituba |
|
||||
canaa dos carajas |
|
||||
goianesia do para |
|
||||
'''), |
|
||||
('America/Santarem', ''' |
|
||||
Santarém |
|
||||
Altamira |
|
||||
Itaituba |
|
||||
Oriximiná |
|
||||
Alenquer |
|
||||
Ábidos |
|
||||
Monte Alegre |
|
||||
Almeirim |
|
||||
Terra Santa |
|
||||
Juruti |
|
||||
Porto de Moz |
|
||||
Nhamundá |
|
||||
Prainha |
|
||||
medicilandia |
|
||||
'''), |
|
||||
] |
|
||||
TZ_CIDADES_AMAZONAS_E_PARA = {normalizar_texto(cidade.strip()): tz |
|
||||
for tz, linhas in TZ_CIDADES_AMAZONAS_E_PARA |
|
||||
for cidade in linhas.strip().splitlines()} |
|
||||
|
|
||||
|
|
||||
def get_nome_timezone(cidade, uf): |
|
||||
uf = uf.upper() |
|
||||
tz = UF_PARA_TIMEZONE[uf] |
|
||||
if uf in ['PA', 'AM']: |
|
||||
cidade = normalizar_texto(cidade) |
|
||||
return TZ_CIDADES_AMAZONAS_E_PARA[cidade] |
|
||||
else: |
|
||||
return tz |
|
||||
|
|
||||
|
|
||||
def get_timezone(cidade, uf): |
|
||||
return timezone(get_nome_timezone(cidade, uf)) |
|
||||
|
|
||||
|
|
||||
def test_get_nome_timezone(): |
|
||||
for cidade, uf, tz in [ |
|
||||
('Fortaleza', 'CE', 'America/Fortaleza'), |
|
||||
('Salvador', 'BA', 'America/Bahia'), |
|
||||
('Belem', 'PA', 'America/Belem'), # sem acento |
|
||||
('Belém', 'PA', 'America/Belem'), # com acento |
|
||||
('Santarem', 'PA', 'America/Santarem'), # sem acento |
|
||||
('Santarém', 'PA', 'America/Santarem'), # com acento |
|
||||
('Manaus', 'AM', 'America/Manaus'), |
|
||||
('Eirunepe', 'AM', 'America/Eirunepe'), # sem acento |
|
||||
('Eirunepé', 'AM', 'America/Eirunepe'), # com acento |
|
||||
]: |
|
||||
assert get_nome_timezone(cidade, uf) == tz, (cidade, uf, tz) |
|
@ -1,64 +0,0 @@ |
|||||
import os |
|
||||
import re |
|
||||
|
|
||||
import pytz |
|
||||
import yaml |
|
||||
from decouple import Config, RepositoryEnv |
|
||||
from dj_database_url import parse as db_url |
|
||||
|
|
||||
from sapl.legacy.scripts.exporta_zope.variaveis_comuns import \ |
|
||||
DIR_DADOS_MIGRACAO |
|
||||
from sapl.legacy.timezonesbrasil import get_timezone |
|
||||
|
|
||||
from .settings import * # flake8: noqa |
|
||||
|
|
||||
config = Config(RepositoryEnv(BASE_DIR.child('legacy', '.env'))) |
|
||||
|
|
||||
|
|
||||
INSTALLED_APPS += ( |
|
||||
'sapl.legacy', # legacy reversed model definitions |
|
||||
) |
|
||||
|
|
||||
DATABASES['legacy'] = config('DATABASE_URL_FONTE', cast=db_url,) |
|
||||
DATABASES['default'] = config( |
|
||||
'DATABASE_URL_DESTINO', |
|
||||
cast=lambda v: v if isinstance(v, dict) else db_url(v), |
|
||||
default=DATABASES['default']) |
|
||||
|
|
||||
# Sobrescreve o nome dos bancos caso a variável de ambiente seja definida |
|
||||
# Útil para migração em lote de vários bancos |
|
||||
DATABASE_NAME_OVERRIDE = os.environ.get('DATABASE_NAME') |
|
||||
if DATABASE_NAME_OVERRIDE: |
|
||||
DATABASES['legacy']['NAME'] = DATABASE_NAME_OVERRIDE |
|
||||
# não altera o nome se o destino é um banco em memória |
|
||||
if not DATABASES['default']['NAME'] == ':memory:': |
|
||||
DATABASES['default']['NAME'] = DATABASE_NAME_OVERRIDE |
|
||||
|
|
||||
DATABASE_ROUTERS = ['sapl.legacy.router.LegacyRouter', ] |
|
||||
|
|
||||
DEBUG = True |
|
||||
|
|
||||
# delisga indexação fulltext em tempo real |
|
||||
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.BaseSignalProcessor' |
|
||||
|
|
||||
SHELL_PLUS_DONT_LOAD = ['legacy'] |
|
||||
|
|
||||
NOME_BANCO_LEGADO = DATABASES['legacy']['NAME'] |
|
||||
DIR_REPO = Path(DIR_DADOS_MIGRACAO, 'repos', NOME_BANCO_LEGADO) |
|
||||
|
|
||||
MEDIA_ROOT = DIR_REPO |
|
||||
|
|
||||
|
|
||||
# configura timezone de migração |
|
||||
match = re.match('sapl_cm_(.*)', NOME_BANCO_LEGADO) |
|
||||
SIGLA_CASA = match.group(1) |
|
||||
_PATH_TABELA_TIMEZONES = DIR_DADOS_MIGRACAO.child('tabela_timezones.yaml') |
|
||||
with open(_PATH_TABELA_TIMEZONES, 'r') as arq: |
|
||||
tabela_timezones = yaml.load(arq, yaml.Loader) |
|
||||
municipio, uf, nome_timezone = tabela_timezones[SIGLA_CASA] |
|
||||
if nome_timezone: |
|
||||
PYTZ_TIMEZONE = pytz.timezone(nome_timezone) |
|
||||
else: |
|
||||
PYTZ_TIMEZONE = get_timezone(municipio, uf) |
|
||||
|
|
||||
TIME_ZONE = PYTZ_TIMEZONE.zone |
|
@ -1,18 +0,0 @@ |
|||||
LexmlProvedor (LexmlRegistroProvedor): |
|
||||
email_responsavel: adm_email |
|
||||
id_provedor: id_provedor |
|
||||
id_responsavel: id_responsavel |
|
||||
nome: nom_provedor |
|
||||
nome_responsavel: nom_responsavel |
|
||||
sigla: sgl_provedor |
|
||||
tipo: tipo |
|
||||
xml: xml_provedor |
|
||||
|
|
||||
LexmlPublicador (LexmlRegistroPublicador): |
|
||||
email_responsavel: adm_email |
|
||||
id_publicador: id_publicador |
|
||||
id_responsavel: id_responsavel |
|
||||
nome: nom_publicador |
|
||||
nome_responsavel: nom_responsavel |
|
||||
sigla: sigla |
|
||||
tipo: tipo |
|
@ -1,146 +0,0 @@ |
|||||
TipoMateriaLegislativa: |
|
||||
descricao: des_tipo_materia |
|
||||
num_automatica: ind_num_automatica |
|
||||
quorum_minimo_votacao: quorum_minimo_votacao |
|
||||
sigla: sgl_tipo_materia |
|
||||
|
|
||||
RegimeTramitacao: |
|
||||
descricao: des_regime_tramitacao |
|
||||
|
|
||||
Origem: |
|
||||
nome: nom_origem |
|
||||
sigla: sgl_origem |
|
||||
|
|
||||
MateriaLegislativa: |
|
||||
ano: ano_ident_basica |
|
||||
ano_origem_externa: ano_origem_externa |
|
||||
apelido: nom_apelido |
|
||||
complementar: ind_complementar |
|
||||
data_apresentacao: dat_apresentacao |
|
||||
data_fim_prazo: dat_fim_prazo |
|
||||
data_origem_externa: dat_origem_externa |
|
||||
data_publicacao: dat_publicacao |
|
||||
dias_prazo: num_dias_prazo |
|
||||
em_tramitacao: ind_tramitacao |
|
||||
ementa: txt_ementa |
|
||||
indexacao: txt_indexacao |
|
||||
local_origem_externa: cod_local_origem_externa |
|
||||
numero: num_ident_basica |
|
||||
numero_origem_externa: num_origem_externa |
|
||||
numero_protocolo: num_protocolo |
|
||||
objeto: des_objeto |
|
||||
observacao: txt_observacao |
|
||||
polemica: ind_polemica |
|
||||
regime_tramitacao: cod_regime_tramitacao |
|
||||
resultado: txt_resultado |
|
||||
tipo_apresentacao: tip_apresentacao |
|
||||
tipo: tip_id_basica |
|
||||
tipo_origem_externa: tip_origem_externa |
|
||||
|
|
||||
Autoria: |
|
||||
autor: cod_autor |
|
||||
materia: cod_materia |
|
||||
primeiro_autor: ind_primeiro_autor |
|
||||
|
|
||||
AcompanhamentoMateria (AcompMateria): |
|
||||
email: end_email |
|
||||
hash: txt_hash |
|
||||
materia: cod_materia |
|
||||
|
|
||||
Anexada: |
|
||||
data_anexacao: dat_anexacao |
|
||||
data_desanexacao: dat_desanexacao |
|
||||
materia_anexada: cod_materia_anexada |
|
||||
materia_principal: cod_materia_principal |
|
||||
|
|
||||
AssuntoMateria: |
|
||||
assunto: des_assunto |
|
||||
dispositivo: des_dispositivo |
|
||||
|
|
||||
DespachoInicial: |
|
||||
materia: cod_materia |
|
||||
comissao: cod_comissao |
|
||||
|
|
||||
TipoDocumento: |
|
||||
descricao: des_tipo_documento |
|
||||
|
|
||||
DocumentoAcessorio: |
|
||||
autor: nom_autor_documento |
|
||||
data: dat_documento |
|
||||
ementa: txt_ementa |
|
||||
indexacao: txt_indexacao |
|
||||
materia: cod_materia |
|
||||
nome: nom_documento |
|
||||
tipo: tip_documento |
|
||||
|
|
||||
MateriaAssunto: |
|
||||
assunto: cod_assunto |
|
||||
materia: cod_materia |
|
||||
|
|
||||
Numeracao: |
|
||||
ano_materia: ano_materia |
|
||||
data_materia: dat_materia |
|
||||
materia: cod_materia |
|
||||
numero_materia: num_materia |
|
||||
tipo_materia: tip_materia |
|
||||
|
|
||||
Orgao: |
|
||||
endereco: end_orgao |
|
||||
nome: nom_orgao |
|
||||
sigla: sgl_orgao |
|
||||
telefone: num_tel_orgao |
|
||||
unidade_deliberativa: ind_unid_deliberativa |
|
||||
|
|
||||
TipoFimRelatoria: |
|
||||
descricao: des_fim_relatoria |
|
||||
|
|
||||
Relatoria: |
|
||||
comissao: cod_comissao |
|
||||
data_designacao_relator: dat_desig_relator |
|
||||
data_destituicao_relator: dat_destit_relator |
|
||||
materia: cod_materia |
|
||||
parlamentar: cod_parlamentar |
|
||||
tipo_fim_relatoria: tip_fim_relatoria |
|
||||
|
|
||||
Parecer: |
|
||||
materia: cod_materia |
|
||||
parecer: txt_parecer |
|
||||
relatoria: cod_relatoria |
|
||||
tipo_apresentacao: tip_apresentacao |
|
||||
tipo_conclusao: tip_conclusao |
|
||||
|
|
||||
TipoProposicao: |
|
||||
descricao: des_tipo_proposicao |
|
||||
|
|
||||
Proposicao: |
|
||||
autor: cod_autor |
|
||||
data_devolucao: dat_devolucao |
|
||||
data_envio: dat_envio |
|
||||
data_recebimento: dat_recebimento |
|
||||
descricao: txt_descricao |
|
||||
justificativa_devolucao: txt_justif_devolucao |
|
||||
materia_de_vinculo: cod_materia |
|
||||
numero_proposicao: num_proposicao |
|
||||
tipo: tip_proposicao |
|
||||
|
|
||||
StatusTramitacao: |
|
||||
descricao: des_status |
|
||||
indicador: ind_fim_tramitacao |
|
||||
sigla: sgl_status |
|
||||
|
|
||||
UnidadeTramitacao: |
|
||||
comissao: cod_comissao |
|
||||
orgao: cod_orgao |
|
||||
parlamentar: cod_parlamentar |
|
||||
|
|
||||
Tramitacao: |
|
||||
data_encaminhamento: dat_encaminha |
|
||||
data_fim_prazo: dat_fim_prazo |
|
||||
data_tramitacao: dat_tramitacao |
|
||||
materia: cod_materia |
|
||||
status: cod_status |
|
||||
texto: txt_tramitacao |
|
||||
turno: sgl_turno |
|
||||
unidade_tramitacao_destino: cod_unid_tram_dest |
|
||||
unidade_tramitacao_local: cod_unid_tram_local |
|
||||
urgente: ind_urgencia |
|
@ -1,46 +0,0 @@ |
|||||
AssuntoNorma: |
|
||||
assunto: des_assunto |
|
||||
descricao: des_estendida |
|
||||
|
|
||||
TipoNormaJuridica: |
|
||||
descricao: des_tipo_norma |
|
||||
equivalente_lexml: voc_lexml |
|
||||
sigla: sgl_tipo_norma |
|
||||
|
|
||||
NormaJuridica: |
|
||||
ano: ano_norma |
|
||||
complemento: ind_complemento |
|
||||
data: dat_norma |
|
||||
data_publicacao: dat_publicacao |
|
||||
data_vigencia: dat_vigencia |
|
||||
ementa: txt_ementa |
|
||||
esfera_federacao: tip_esfera_federacao |
|
||||
indexacao: txt_indexacao |
|
||||
materia: cod_materia |
|
||||
numero: num_norma |
|
||||
observacao: txt_observacao |
|
||||
pagina_fim_publicacao: num_pag_fim_publ |
|
||||
pagina_inicio_publicacao: num_pag_inicio_publ |
|
||||
timestamp: timestamp |
|
||||
tipo: tip_norma |
|
||||
veiculo_publicacao: des_veiculo_publicacao |
|
||||
|
|
||||
LegislacaoCitada: |
|
||||
alinea: des_alinea |
|
||||
artigo: des_artigo |
|
||||
capitulo: des_capitulo |
|
||||
disposicoes: des_disposicoes |
|
||||
inciso: des_inciso |
|
||||
item: des_item |
|
||||
livro: des_livro |
|
||||
materia: cod_materia |
|
||||
norma: cod_norma |
|
||||
paragrafo: des_paragrafo |
|
||||
parte: des_parte |
|
||||
secao: des_secao |
|
||||
subsecao: des_subsecao |
|
||||
titulo: des_titulo |
|
||||
|
|
||||
NormaRelacionada (VinculoNormaJuridica): |
|
||||
norma_principal: cod_norma_referente |
|
||||
norma_relacionada: cod_norma_referida |
|
@ -1,101 +0,0 @@ |
|||||
Legislatura: |
|
||||
numero: num_legislatura |
|
||||
data_eleicao: dat_eleicao |
|
||||
data_fim: dat_fim |
|
||||
data_inicio: dat_inicio |
|
||||
|
|
||||
SessaoLegislativa: |
|
||||
data_fim: dat_fim |
|
||||
data_fim_intervalo: dat_fim_intervalo |
|
||||
data_inicio: dat_inicio |
|
||||
data_inicio_intervalo: dat_inicio_intervalo |
|
||||
legislatura: num_legislatura |
|
||||
numero: num_sessao_leg |
|
||||
tipo: tip_sessao_leg |
|
||||
|
|
||||
Coligacao: |
|
||||
legislatura: num_legislatura |
|
||||
nome: nom_coligacao |
|
||||
numero_votos: num_votos_coligacao |
|
||||
|
|
||||
Partido: |
|
||||
data_criacao: dat_criacao |
|
||||
data_extincao: dat_extincao |
|
||||
nome: nom_partido |
|
||||
sigla: sgl_partido |
|
||||
|
|
||||
ComposicaoColigacao: |
|
||||
coligacao: cod_coligacao |
|
||||
partido: cod_partido |
|
||||
|
|
||||
NivelInstrucao: |
|
||||
descricao: des_nivel_instrucao |
|
||||
|
|
||||
SituacaoMilitar: |
|
||||
descricao: des_tipo_situacao |
|
||||
|
|
||||
Parlamentar: |
|
||||
ativo: ind_ativo |
|
||||
biografia: txt_biografia |
|
||||
cep_residencia: num_cep_resid |
|
||||
cpf: num_cpf |
|
||||
data_nascimento: dat_nascimento |
|
||||
email: end_email |
|
||||
endereco_residencia: end_residencial |
|
||||
endereco_web: end_web |
|
||||
fax: num_fax_parlamentar |
|
||||
fax_residencia: num_fax_resid |
|
||||
locais_atuacao: des_local_atuacao |
|
||||
nivel_instrucao: cod_nivel_instrucao |
|
||||
nome_completo: nom_completo |
|
||||
nome_parlamentar: nom_parlamentar |
|
||||
numero_gab_parlamentar: num_gab_parlamentar |
|
||||
profissao: nom_profissao |
|
||||
rg: num_rg |
|
||||
sexo: sex_parlamentar |
|
||||
situacao_militar: tip_situacao_militar |
|
||||
telefone: num_tel_parlamentar |
|
||||
telefone_residencia: num_tel_resid |
|
||||
titulo_eleitor: num_tit_eleitor |
|
||||
|
|
||||
TipoDependente: |
|
||||
descricao: des_tipo_dependente |
|
||||
|
|
||||
Dependente: |
|
||||
cpf: num_cpf |
|
||||
data_nascimento: dat_nascimento |
|
||||
nome: nom_dependente |
|
||||
parlamentar: cod_parlamentar |
|
||||
rg: num_rg |
|
||||
sexo: sex_dependente |
|
||||
tipo: tip_dependente |
|
||||
titulo_eleitor: num_tit_eleitor |
|
||||
|
|
||||
Filiacao: |
|
||||
data: dat_filiacao |
|
||||
data_desfiliacao: dat_desfiliacao |
|
||||
parlamentar: cod_parlamentar |
|
||||
partido: cod_partido |
|
||||
|
|
||||
TipoAfastamento: |
|
||||
descricao: des_afastamento |
|
||||
dispositivo: des_dispositivo |
|
||||
|
|
||||
Mandato: |
|
||||
coligacao: cod_coligacao |
|
||||
data_expedicao_diploma: dat_expedicao_diploma |
|
||||
legislatura: num_legislatura |
|
||||
observacao: txt_observacao |
|
||||
parlamentar: cod_parlamentar |
|
||||
tipo_afastamento: tip_afastamento |
|
||||
tipo_causa_fim_mandato: tip_causa_fim_mandato |
|
||||
votos_recebidos: num_votos_recebidos |
|
||||
|
|
||||
CargoMesa: |
|
||||
descricao: des_cargo |
|
||||
unico: ind_unico |
|
||||
|
|
||||
ComposicaoMesa: |
|
||||
cargo: cod_cargo |
|
||||
parlamentar: cod_parlamentar |
|
||||
sessao_legislativa: cod_sessao_leg |
|
@ -1,62 +0,0 @@ |
|||||
TipoDocumentoAdministrativo: |
|
||||
descricao: des_tipo_documento |
|
||||
sigla: sgl_tipo_documento |
|
||||
|
|
||||
DocumentoAdministrativo: |
|
||||
ano: ano_documento |
|
||||
assunto: txt_assunto |
|
||||
autor: cod_autor |
|
||||
data: dat_documento |
|
||||
data_fim_prazo: dat_fim_prazo |
|
||||
dias_prazo: num_dias_prazo |
|
||||
interessado: txt_interessado |
|
||||
numero: num_documento |
|
||||
observacao: txt_observacao |
|
||||
tipo: tip_documento |
|
||||
tramitacao: ind_tramitacao |
|
||||
|
|
||||
DocumentoAcessorioAdministrativo: |
|
||||
arquivo: nom_arquivo |
|
||||
assunto: txt_assunto |
|
||||
autor: nom_autor_documento |
|
||||
data: dat_documento |
|
||||
documento: cod_documento |
|
||||
indexacao: txt_indexacao |
|
||||
nome: nom_documento |
|
||||
tipo: tip_documento |
|
||||
|
|
||||
Protocolo: |
|
||||
ano: ano_protocolo |
|
||||
anulado: ind_anulado |
|
||||
assunto_ementa: txt_assunto_ementa |
|
||||
autor: cod_autor |
|
||||
data: dat_protocolo |
|
||||
hora: hor_protocolo |
|
||||
interessado: txt_interessado |
|
||||
ip_anulacao: txt_ip_anulacao |
|
||||
justificativa_anulacao: txt_just_anulacao |
|
||||
numero: num_protocolo |
|
||||
numero_paginas: num_paginas |
|
||||
observacao: txt_observacao |
|
||||
timestamp: dat_timestamp |
|
||||
timestamp_anulacao: timestamp_anulacao |
|
||||
tipo_documento: tip_documento |
|
||||
tipo_materia: tip_materia |
|
||||
tipo_processo: tip_processo |
|
||||
tipo_protocolo: tip_protocolo |
|
||||
user_anulacao: txt_user_anulacao |
|
||||
|
|
||||
StatusTramitacaoAdministrativo: |
|
||||
descricao: des_status |
|
||||
indicador: ind_fim_tramitacao |
|
||||
sigla: sgl_status |
|
||||
|
|
||||
TramitacaoAdministrativo: |
|
||||
data_encaminhamento: dat_encaminha |
|
||||
data_fim_prazo: dat_fim_prazo |
|
||||
data_tramitacao: dat_tramitacao |
|
||||
documento: cod_documento |
|
||||
status: cod_status |
|
||||
texto: txt_tramitacao |
|
||||
unidade_tramitacao_destino: cod_unid_tram_dest |
|
||||
unidade_tramitacao_local: cod_unid_tram_local |
|
@ -1,77 +0,0 @@ |
|||||
TipoSessaoPlenaria: |
|
||||
nome: nom_sessao |
|
||||
quorum_minimo: num_minimo |
|
||||
|
|
||||
SessaoPlenaria: |
|
||||
cod_andamento_sessao: cod_andamento_sessao |
|
||||
data_fim: dat_fim_sessao |
|
||||
data_inicio: dat_inicio_sessao |
|
||||
hora_fim: hr_fim_sessao |
|
||||
hora_inicio: hr_inicio_sessao |
|
||||
legislatura: num_legislatura |
|
||||
numero: num_sessao_plen |
|
||||
sessao_legislativa: cod_sessao_leg |
|
||||
tipo: tip_sessao |
|
||||
url_audio: url_audio |
|
||||
url_video: url_video |
|
||||
|
|
||||
<AbstractOrdemDia>: |
|
||||
data_ordem: dat_ordem |
|
||||
materia: cod_materia |
|
||||
numero_ordem: num_ordem |
|
||||
observacao: txt_observacao |
|
||||
resultado: txt_resultado |
|
||||
sessao_plenaria: cod_sessao_plen |
|
||||
tipo_votacao: tip_votacao |
|
||||
|
|
||||
ExpedienteMateria: <AbstractOrdemDia> |
|
||||
|
|
||||
TipoExpediente: |
|
||||
nome: nom_expediente |
|
||||
|
|
||||
ExpedienteSessao (ExpedienteSessaoPlenaria): |
|
||||
conteudo: txt_expediente |
|
||||
sessao_plenaria: cod_sessao_plen |
|
||||
tipo: cod_expediente |
|
||||
|
|
||||
IntegranteMesa (MesaSessaoPlenaria): |
|
||||
cargo: cod_cargo |
|
||||
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): <AbstractOrador> |
|
||||
|
|
||||
OradorExpediente (OradoresExpediente): <AbstractOrador> |
|
||||
|
|
||||
OrdemDia: <AbstractOrdemDia> |
|
||||
|
|
||||
PresencaOrdemDia (OrdemDiaPresenca): |
|
||||
parlamentar: cod_parlamentar |
|
||||
sessao_plenaria: cod_sessao_plen |
|
||||
|
|
||||
TipoResultadoVotacao: |
|
||||
nome: nom_resultado |
|
||||
|
|
||||
RegistroVotacao: |
|
||||
materia: cod_materia |
|
||||
numero_abstencoes: num_abstencao |
|
||||
numero_votos_nao: num_votos_nao |
|
||||
numero_votos_sim: num_votos_sim |
|
||||
observacao: txt_observacao |
|
||||
tipo_resultado_votacao: tip_resultado_votacao |
|
||||
|
|
||||
VotoParlamentar (RegistroVotacaoParlamentar): |
|
||||
parlamentar: cod_parlamentar |
|
||||
votacao: cod_votacao |
|
||||
voto: vot_parlamentar |
|
||||
|
|
||||
SessaoPlenariaPresenca: |
|
||||
data_sessao: dat_sessao |
|
||||
parlamentar: cod_parlamentar |
|
||||
sessao_plenaria: cod_sessao_plen |
|
Loading…
Reference in new issue