Browse Source

Merge branch 'migracao' into 3.1.x

pull/2023/head
Marcio Mazza 7 years ago
parent
commit
ebf571c40a
  1. 7
      sapl/comissoes/legacy.yaml
  2. 25
      sapl/comissoes/migrations/0015_auto_20180613_2023.py
  3. 21
      sapl/comissoes/migrations/0016_auto_20180613_2121.py
  4. 9
      sapl/comissoes/models.py
  5. 26
      sapl/comissoes/views.py
  6. 2
      sapl/legacy/management/commands/migracao_25_31.py
  7. 6
      sapl/legacy/migracao.py
  8. 70
      sapl/legacy/migracao_dados.py
  9. 36
      sapl/legacy/migracao_documentos.py
  10. 11
      sapl/legacy/migracao_usuarios.py
  11. 14
      sapl/legacy/models.py
  12. 85
      sapl/legacy/scripts/exporta_zope/exporta_zope.py
  13. 12
      sapl/sessao/legacy.yaml

7
sapl/comissoes/legacy.yaml

@ -42,3 +42,10 @@ Participacao (ComposicaoComissao):
observacao: obs_composicao
parlamentar: cod_parlamentar
titular: ind_titular
Reuniao (ReuniaoComissao):
comissao: cod_comissao
numero: num_reuniao
data: dat_inicio_reuniao
observacao: txt_observacao

25
sapl/comissoes/migrations/0015_auto_20180613_2023.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-06-13 23:23
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('comissoes', '0014_auto_20180503_1055'),
]
operations = [
migrations.AlterField(
model_name='reuniao',
name='hora_fim',
field=models.TimeField(null=True, verbose_name='Horário de Término (hh:mm)'),
),
migrations.AlterField(
model_name='reuniao',
name='hora_inicio',
field=models.TimeField(null=True, verbose_name='Horário de Início (hh:mm)'),
),
]

21
sapl/comissoes/migrations/0016_auto_20180613_2121.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-06-14 00:21
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('comissoes', '0015_auto_20180613_2023'),
]
operations = [
migrations.AlterField(
model_name='reuniao',
name='periodo',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='comissoes.Periodo', verbose_name='Periodo da Composicão da Comissão'),
),
]

9
sapl/comissoes/models.py

@ -184,13 +184,16 @@ class Participacao(models.Model): # ComposicaoComissao
def get_comissao_media_path(instance, subpath, filename):
return './sapl/comissao/%s/%s/%s' % (instance.numero, subpath, filename)
def pauta_upload_path(instance, filename):
return texto_upload_path(instance, filename, subpath='pauta', pk_first=True)
def ata_upload_path(instance, filename):
return texto_upload_path(instance, filename, subpath='ata', pk_first=True)
def anexo_upload_path(instance, filename):
return texto_upload_path(instance, filename, subpath='anexo', pk_first=True)
@ -198,6 +201,7 @@ def anexo_upload_path(instance, filename):
class Reuniao(models.Model):
periodo = models. ForeignKey(
Periodo,
null=True,
on_delete=models.PROTECT,
verbose_name=_('Periodo da Composicão da Comissão'))
comissao = models.ForeignKey(
@ -211,8 +215,10 @@ class Reuniao(models.Model):
max_length=150, blank=True, verbose_name=_('Tema da Reunião'))
data = models.DateField(verbose_name=_('Data'))
hora_inicio = models.TimeField(
null=True,
verbose_name=_('Horário de Início (hh:mm)'))
hora_fim = models.TimeField(
null=True,
verbose_name=_('Horário de Término (hh:mm)'))
local_reuniao = models.CharField(
max_length=100, blank=True, verbose_name=_('Local da Reunião'))
@ -292,7 +298,8 @@ class DocumentoAcessorio(models.Model):
on_delete=models.PROTECT)
nome = models.CharField(max_length=50, verbose_name=_('Nome'))
data = models.DateField(blank=True, null=True, default=None, verbose_name=_('Data'))
data = models.DateField(blank=True, null=True,
default=None, verbose_name=_('Data'))
autor = models.CharField(
max_length=100, verbose_name=_('Autor'))
ementa = models.TextField(blank=True, verbose_name=_('Ementa'))

26
sapl/comissoes/views.py

@ -8,20 +8,20 @@ from django.views.generic.base import RedirectView
from django.views.generic.detail import DetailView
from django.views.generic.edit import FormMixin
from sapl.base.models import AppConfig as AppsAppConfig
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud,
CrudAux, MasterDetailCrud,
from sapl.comissoes.apps import AppConfig
from sapl.comissoes.forms import (ComissaoForm, ComposicaoForm,
DocumentoAcessorioCreateForm,
DocumentoAcessorioEditForm,
ParticipacaoCreateForm, ParticipacaoEditForm,
PeriodoForm, ReuniaoForm)
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
MasterDetailCrud,
PermissionRequiredForAppCrudMixin)
from sapl.comissoes.forms import (ComissaoForm, ComposicaoForm, DocumentoAcessorioCreateForm,
DocumentoAcessorioEditForm, ParticipacaoCreateForm,
ParticipacaoEditForm, ReuniaoForm, PeriodoForm)
from sapl.materia.models import MateriaLegislativa, Tramitacao
from .models import (CargoComissao, Comissao, Composicao, DocumentoAcessorio,
Participacao, Periodo, TipoComissao, Reuniao)
from sapl.comissoes.apps import AppConfig
Participacao, Periodo, Reuniao, TipoComissao)
def pegar_url_composicao(pk):
@ -30,6 +30,7 @@ def pegar_url_composicao(pk):
url = reverse('sapl.comissoes:composicao_detail', kwargs={'pk': comp_pk})
return url
def pegar_url_reuniao(pk):
documentoacessorio = DocumentoAcessorio.objects.get(id=pk)
r_pk = documentoacessorio.reuniao.pk
@ -42,6 +43,7 @@ TipoComissaoCrud = CrudAux.build(
TipoComissao, 'tipo_comissao', list_field_names=[
'sigla', 'nome', 'natureza', 'dispositivo_regimental'])
class PeriodoComposicaoCrud(CrudAux):
model = Periodo
@ -77,6 +79,7 @@ class ParticipacaoCrud(MasterDetailCrud):
form_class = ParticipacaoEditForm
class DeleteView(MasterDetailCrud.DeleteView):
def get_success_url(self):
composicao_comissao_pk = self.object.composicao.comissao.pk
composicao_pk = self.object.composicao.pk
@ -98,7 +101,6 @@ class ComposicaoCrud(MasterDetailCrud):
comissao = Comissao.objects.get(id=self.kwargs['pk'])
return {'comissao': comissao}
class ListView(MasterDetailCrud.ListView):
template_name = "comissoes/composicao_list.html"
paginate_by = None
@ -180,6 +182,7 @@ class MateriasTramitacaoListView(ListView):
context['object'] = Comissao.objects.get(id=self.kwargs['pk'])
return context
class ReuniaoCrud(MasterDetailCrud):
model = Reuniao
parent_field = 'comissao'
@ -187,7 +190,7 @@ class ReuniaoCrud(MasterDetailCrud):
public = [RP_LIST, RP_DETAIL, ]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = [ 'nome', 'tema', 'data']
list_field_names = ['data', 'nome', 'tema']
class ListView(MasterDetailCrud.ListView):
paginate_by = 10
@ -256,6 +259,7 @@ class DocumentoAcessorioCrud(MasterDetailCrud):
form_class = DocumentoAcessorioEditForm
class DeleteView(MasterDetailCrud.DeleteView):
def delete(self, *args, **kwargs):
obj = self.get_object()
obj.delete()

2
sapl/legacy/management/commands/migracao_25_31.py

@ -1,4 +1,3 @@
from django.core import management
from django.core.management.base import BaseCommand
from sapl.legacy.migracao import migrar
@ -9,5 +8,4 @@ class Command(BaseCommand):
help = 'Migração de dados do SAPL 2.5 para o SAPL 3.1'
def handle(self, *args, **options):
management.call_command('migrate')
migrar(interativo=False)

6
sapl/legacy/migracao.py

@ -2,6 +2,7 @@ import subprocess
from getpass import getpass
import requests
from django.core import management
from unipath import Path
from sapl.legacy.migracao_dados import (REPO, TAG_MARCO, gravar_marco, info,
@ -24,11 +25,12 @@ def migrar(interativo=False):
assert TAG_ZOPE in REPO.tags, adornar_msg(
'Antes de migrar '
'é necessário fazer a exportação de documentos do zope')
migrar_dados(interativo=interativo)
management.call_command('migrate')
migrar_dados()
migrar_usuarios(REPO.working_dir)
migrar_documentos(REPO)
gravar_marco()
compactar_media()
# compactar_media()
def compactar_media():

70
sapl/legacy/migracao_dados.py

@ -29,7 +29,7 @@ from unipath import Path
from sapl.base.models import AppConfig as AppConf
from sapl.base.models import Autor, TipoAutor, cria_models_tipo_autor
from sapl.comissoes.models import Comissao, Composicao, Participacao
from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao
from sapl.legacy import scripts
from sapl.legacy.models import NormaJuridica as OldNormaJuridica
from sapl.legacy.models import TipoNumeracaoProtocolo
@ -58,6 +58,8 @@ from .timezonesbrasil import get_timezone
appconfs = [apps.get_app_config(n) for n in [
'parlamentares',
'comissoes',
# base precisa vir depois dos apps parlamentares e comissoes
# pois Autor os referencia
'base',
'materia',
'norma',
@ -85,38 +87,34 @@ for a1, s1 in name_sets:
# RENAMES ###################################################################
MODEL_RENAME_PATTERN = re.compile('(.+) \((.+)\)')
MODEL_RENAME_INCLUDE_PATTERN = re.compile('<(.+)>')
def get_renames():
field_renames = {}
model_renames = {}
includes = {}
for app in appconfs:
app_rename_data = yaml.load(
pkg_resources.resource_string(app.module.__name__, 'legacy.yaml'))
for model_name, renames in app_rename_data.items():
# armazena ou substitui includes
if MODEL_RENAME_INCLUDE_PATTERN.match(model_name):
includes[model_name] = renames
continue
elif isinstance(renames, str):
renames = includes[renames]
# detecta mudança de nome
match = MODEL_RENAME_PATTERN.match(model_name)
if match:
model_name, old_name = match.groups()
else:
old_name = None
model = getattr(app.models_module, model_name)
model = app.get_model(model_name)
if old_name:
model_renames[model] = old_name
field_renames[model] = renames
# collect renames from parent classes
for model, renames in field_renames.items():
if any(parent in field_renames for parent in model.__mro__[1:]):
renames = {}
for parent in reversed(model.__mro__):
if parent in field_renames:
renames.update(field_renames[parent])
field_renames[model] = renames
# remove abstract classes
field_renames = {m: r for m, r in field_renames.items()
if not m._meta.abstract}
return field_renames, model_renames
@ -212,6 +210,10 @@ class ForeignKeyFaltando(ObjectDoesNotExist):
'Uma FK aponta para um registro inexistente'
def __init__(self, field, valor, old):
if (field.related_model.__name__ == 'Comissao'
and old.__class__.__name__ == 'ReuniaoComissao'
and valor == 1):
__import__('pdb').set_trace()
self.field = field
self.valor = valor
self.old = old
@ -632,6 +634,7 @@ parlamentar | cod_nivel_instrucao = NULL | cod_nivel_instrucao = 0
parlamentar | tip_situacao_militar = NULL | tip_situacao_militar = 0
mandato | tip_afastamento = NULL | tip_afastamento = 0
relatoria | tip_fim_relatoria = NULL | tip_fim_relatoria = 0
sessao_plenaria_presenca | dat_sessao = NULL | dat_sessao = 0
'''.strip().splitlines()
for spec in update_specs:
@ -794,7 +797,10 @@ def roda_comando_shell(cmd):
assert res == 0, 'O comando falhou: {}'.format(cmd)
def migrar_dados(interativo=True):
def migrar_dados():
try:
ocorrencias.clear()
ocorrencias.default_factory = list
# restaura dump
arq_dump = Path(DIR_DADOS_MIGRACAO.child(
@ -813,17 +819,6 @@ def migrar_dados(interativo=True):
uniformiza_banco()
# excluindo database antigo.
if interativo:
info('Todos os dados do banco serão excluidos. '
'Recomendamos que faça backup do banco sapl '
'antes de continuar.')
info('Deseja continuar? [s/n]')
resposta = input()
if resposta.lower() in ['s', 'sim', 'y', 'yes']:
pass
else:
info('Migração cancelada.')
return 0
info('Excluindo entradas antigas do banco destino.')
call([PROJECT_DIR.child('manage.py'), 'flush',
'--database=default', '--no-input'], stdout=PIPE)
@ -834,14 +829,13 @@ def migrar_dados(interativo=True):
fill_vinculo_norma_juridica()
fill_dados_basicos()
info('Começando migração: ...')
try:
ocorrencias.clear()
migrar_todos_os_models()
except Exception as e:
ocorrencias['traceback'] = str(traceback.format_exc())
raise e
finally:
# grava ocorrências
# congela e grava ocorrências
ocorrencias.default_factory = None
arq_ocorrencias = Path(REPO.working_dir, 'ocorrencias.yaml')
with open(arq_ocorrencias, 'w') as arq:
pyaml.dump(ocorrencias, arq, vspacing=1)
@ -863,6 +857,10 @@ def move_para_depois_de(lista, movido, referencias):
def get_models_a_migrar():
models = [model for app in appconfs for model in app.models.values()
if model in field_renames]
# retira reuniões quando não existe na base legada
# (só existe no sapl 3.0)
if 'reuniao_comissao' not in list(exec_legado('show tables')):
models.remove(Reuniao)
# Devido à referência TipoProposicao.tipo_conteudo_related
# a migração de TipoProposicao precisa ser feita
# após TipoMateriaLegislativa e TipoDocumento
@ -1247,6 +1245,17 @@ def adjust_tiporesultadovotacao(new, old):
{'pk': new.pk, 'nome': new.nome})
def str_to_time(fonte):
if not fonte.strip():
return None
tempo = datetime.datetime.strptime(fonte, '%H:%M')
return tempo.time() if tempo else None
def adjust_reuniao_comissao(new, old):
new.hora_inicio = str_to_time(old.hr_inicio_reuniao)
def remove_style(conteudo):
if 'style' not in conteudo:
return conteudo # atalho que acelera muito os casos sem style
@ -1284,6 +1293,7 @@ AJUSTE_ANTES_SALVAR = {
Tramitacao: adjust_tramitacao,
TipoResultadoVotacao: adjust_tiporesultadovotacao,
ExpedienteSessao: adjust_expediente_sessao,
Reuniao: adjust_reuniao_comissao,
}
AJUSTE_DEPOIS_SALVAR = {

36
sapl/legacy/migracao_documentos.py

@ -8,6 +8,7 @@ from django.db import transaction
from image_cropping.fields import ImageCropField
from sapl.base.models import CasaLegislativa
from sapl.comissoes.models import Reuniao
from sapl.legacy.migracao_dados import exec_legado
from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa,
Proposicao)
@ -21,7 +22,6 @@ from sapl.sessao.models import SessaoPlenaria
DOCS = {
CasaLegislativa: [('logotipo', 'props_sapl/{}.*')],
Parlamentar: [('fotografia', 'parlamentar/fotos/{}_foto_parlamentar')],
MateriaLegislativa: [('texto_original', 'materia/{}_texto_integral')],
DocumentoAcessorio: [('arquivo', 'materia/{}')],
@ -35,24 +35,34 @@ DOCS = {
DocumentoAcessorioAdministrativo: [('arquivo', 'administrativo/{}')],
}
# acrescenta reuniões (que só existem no sapl 3.0)
if 'reuniao_comissao' in set(exec_legado('show tables')):
DOCS[Reuniao] = [('upload_pauta', 'reuniao_comissao/{}_pauta'),
('upload_ata', 'reuniao_comissao/{}_ata')],
DOCS = {model: [(campo, join('sapl_documentos', origem))
for campo, origem, in campos]
for campo, origem in campos]
for model, campos in DOCS.items()}
def mover_documento(repo, origem, destino):
def mover_documento(repo, origem, destino, ignora_origem_ausente=False):
origem, destino = [join(repo.working_dir, c) if not os.path.isabs(c) else c
for c in (origem, destino)]
if ignora_origem_ausente and not os.path.exists(origem):
print('Origem ignorada ao mover documento: {}'.format(origem))
return
os.makedirs(os.path.dirname(destino), exist_ok=True)
repo.git.mv(origem, destino)
def migrar_logotipo(repo, casa, propriedades):
print('.... Migrando logotipo da casa ....')
[(campo, origem)] = DOCS[CasaLegislativa]
campo, origem = 'logotipo', 'sapl_documentos/props_sapl/{}.*'
# a extensão do logo pode ter sido ajustada pelo tipo real do arquivo
nome_nas_propriedades = os.path.splitext(propriedades['id_logo'])[0]
arquivos = glob(join(repo.working_dir, origem.format(nome_nas_propriedades)))
arquivos = glob(
join(repo.working_dir, origem.format(nome_nas_propriedades)))
if arquivos:
assert len(arquivos) == 1, 'Há mais de um logotipo para a casa'
[logo] = arquivos
@ -95,10 +105,10 @@ def migrar_propriedades_da_casa(repo):
migrar_logotipo(repo, casa, propriedades)
casa.save()
repo.git.rm(caminho)
def migrar_docs_por_ids(repo, model):
for campo, base_origem in DOCS[model]:
print('#### Migrando {} de {} ####'.format(campo, model.__name__))
@ -145,7 +155,8 @@ def migrar_documentos(repo):
# Isto significa que para rodar novamente esta função é preciso
# restaurar o repo ao estado anterior
mover_documento(repo, 'XSLT', 'sapl/public/XSLT')
mover_documento(repo, 'XSLT', 'sapl/public/XSLT',
ignora_origem_ausente=True)
migrar_propriedades_da_casa(repo)
@ -153,16 +164,7 @@ def migrar_documentos(repo):
# (necessário para o cropping de imagem)
repo.git.execute('git annex get sapl_documentos/parlamentar'.split())
for model in [
Parlamentar,
MateriaLegislativa,
DocumentoAcessorio,
NormaJuridica,
SessaoPlenaria,
Proposicao,
DocumentoAdministrativo,
DocumentoAcessorioAdministrativo,
]:
for model in DOCS:
migrar_docs_por_ids(repo, model)
sobrando = [join(dir, file)

11
sapl/legacy/migracao_usuarios.py

@ -95,16 +95,7 @@ def migrar_usuarios(dir_repo):
usuario.groups.add(PERFIL_LEGADO_PARA_NOVO[perfil])
usuario.save()
# restringe e configura administradores
if len(admins) > 2:
admins = (
# ususários com admin no nome
[u for u in admins if 'admin' in u.username]
# senão, o usuário saploper, apenas
or [u for u in admins if 'saploper' == u.username]
# senão, simplesmente até os dois primeiros da lista
or admins[:2]
)
# configura administradores
for admin in admins:
admin.is_superuser = True
admin.save()

14
sapl/legacy/models.py

@ -779,6 +779,20 @@ class Relatoria(models.Model):
db_table = 'relatoria'
class ReuniaoComissao(models.Model):
cod_reuniao = models.AutoField(primary_key=True)
cod_comissao = models.IntegerField()
num_reuniao = models.IntegerField()
dat_inicio_reuniao = models.DateField()
hr_inicio_reuniao = models.CharField(max_length=5, blank=True, null=True)
txt_observacao = models.TextField(blank=True, null=True)
ind_excluido = models.IntegerField()
class Meta:
managed = False
db_table = 'reuniao_comissao'
class SessaoLegislativa(models.Model):
cod_sessao_leg = models.AutoField(primary_key=True)
num_legislatura = models.IntegerField()

85
sapl/legacy/scripts/exporta_zope/exporta_zope.py

@ -21,6 +21,7 @@ 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
@ -95,6 +96,9 @@ def guess_extension(fullname, buffer):
return '.DESCONHECIDO.{}'.format(mime.replace('/', '__'))
CONTEUDO_ARQUIVO_CORROMPIDO = 'ARQUIVO CORROMPIDO'
def get_conteudo_file(doc):
# A partir daqui usamos dict.pop('...') nos __Broken_state__
# para contornar um "vazamento" de memória que ocorre
@ -105,7 +109,7 @@ def get_conteudo_file(doc):
#
# Essa medida descarta quase todos os dados retornados
# e só funciona na primeira passagem
try:
pdata = br(doc.pop('data'))
if isinstance(pdata, str):
# Retrocedemos se pdata ja eh uma str (necessario em Images)
@ -118,12 +122,17 @@ def get_conteudo_file(doc):
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)
@ -137,7 +146,15 @@ def get_conteudo_dtml_method(doc):
def enumerate_by_key_list(folder, key_list, type_key):
for entry in folder.get(key_list, []):
id, meta_type = entry['id'], entry[type_key]
try:
obj = br(folder.get(id, None))
except POSKeyError:
print('#' * 80)
print('#' * 80)
print('ATENÇÃO: DIRETÓRIO corrompido: {}'.format(id))
print('#' * 80)
print('#' * 80)
else:
yield id, obj, meta_type
@ -186,6 +203,9 @@ def dump_folder(folder, path, salvar, enum=enumerate_folder):
if not os.path.exists(path):
os.makedirs(path)
for id, obj, meta_type in enum(folder):
# pula pastas *_old (presentes em várias bases)
if id.endswith('_old') and meta_type in ['Folder', 'BTreeFolder2']:
continue
dump = DUMP_FUNCTIONS.get(meta_type, '?')
if dump == '?':
nao_identificados[meta_type].append(path + '/' + id)
@ -271,39 +291,68 @@ def get_app(data_fs_path):
def find_sapl(app):
for obj in app['_objects']:
id, meta_type = obj['id'], obj['meta_type']
ids_meta_types = [(obj['id'], obj['meta_type']) for obj in app['_objects']]
# estar ordenado é muito importante para que a busca dê prioridade
# a um id "cm_zzz" antes do id "sapl"
for id, meta_type in sorted(ids_meta_types):
if id.startswith('cm_') and meta_type == 'Folder':
cm_zzz = br(app[id])
sapl = br(cm_zzz.get('sapl', None))
if sapl and 'sapl_documentos' in sapl and 'acl_users' in sapl:
return find_sapl(cm_zzz)
elif id == 'sapl' and meta_type in ['SAPL', 'Folder']:
sapl = br(app['sapl'])
return sapl
def dump_propriedades(docs, path, salvar, encoding='iso-8859-1'):
def detectar_encoding(fonte):
desc = magic.from_buffer(fonte)
for termo, enc in [('ISO-8859', 'latin1'), ('UTF-8', 'utf-8')]:
if termo in desc:
return enc
return None
def autodecode(fonte):
if isinstance(fonte, str):
enc = detectar_encoding(fonte)
return fonte.decode(enc) if enc else fonte
else:
return fonte
def dump_propriedades(docs, path, salvar):
props_sapl = br(docs['props_sapl'])
ids = [p['id'] for p in props_sapl['_properties']]
props = {id: props_sapl[id] for id in ids}
props = {id: p.decode(encoding) if isinstance(p, str) else p
for id, p in props.items()}
props = {id: autodecode(p) for id, p in props.items()}
save_as_yaml(path, 'sapl_documentos/propriedades.yaml', props, salvar)
def dump_usuarios(sapl, path, salvar):
users = br(br(sapl['acl_users'])['data'])
users = {k: br(v) for k, v in users['data'].items()}
users = {autodecode(k): br(v) for k, v in users['data'].items()}
for dados in users.values():
dados['name'] = autodecode(dados['name'])
save_as_yaml(path, 'usuarios.yaml', users, salvar)
def _dump_sapl(data_fs_path, destino, salvar):
def _dump_sapl(data_fs_path, documentos_fs_path, destino, salvar):
assert Path(data_fs_path).exists()
assert Path(documentos_fs_path).exists()
app, close_db = get_app(data_fs_path)
try:
sapl = find_sapl(app)
# extrai folhas XSLT
dump_folder(br(sapl['XSLT']), destino, salvar)
# extrai usuários com suas senhas e perfis
dump_usuarios(sapl, destino, salvar)
finally:
close_db()
app, close_db = get_app(documentos_fs_path)
try:
sapl = find_sapl(app)
# extrai folhas XSLT
if 'XSLT' in sapl:
dump_folder(br(sapl['XSLT']), destino, salvar)
# extrai documentos
docs = br(sapl['sapl_documentos'])
@ -355,9 +404,15 @@ def build_salvar(repo):
def dump_sapl(sigla):
sigla = sigla[-3:] # ignora prefixo (por ex. 'sapl_cm_')
data_fs_path = DIR_DADOS_MIGRACAO.child('datafs',
'Data_cm_{}.fs'.format(sigla))
data_fs_path, documentos_fs_path = [
DIR_DADOS_MIGRACAO.child(
'datafs', '{}_cm_{}.fs'.format(prefixo, sigla))
for prefixo in ('Data', 'DocumentosSapl')]
assert data_fs_path.exists(), 'Origem não existe: {}'.format(data_fs_path)
if not documentos_fs_path.exists():
documentos_fs_path = data_fs_path
nome_banco_legado = 'sapl_cm_{}'.format(sigla)
destino = DIR_DADOS_MIGRACAO.child('repos', nome_banco_legado)
destino.mkdir(parents=True)
@ -372,7 +427,7 @@ def dump_sapl(sigla):
salvar = build_salvar(repo)
try:
finalizado = False
_dump_sapl(data_fs_path, destino, salvar)
_dump_sapl(data_fs_path, documentos_fs_path, destino, salvar)
finalizado = True
finally:
# grava mundaças

12
sapl/sessao/legacy.yaml

@ -15,7 +15,7 @@ SessaoPlenaria:
url_audio: url_audio
url_video: url_video
AbstractOrdemDia:
<AbstractOrdemDia>:
data_ordem: dat_ordem
materia: cod_materia
numero_ordem: num_ordem
@ -24,7 +24,7 @@ AbstractOrdemDia:
sessao_plenaria: cod_sessao_plen
tipo_votacao: tip_votacao
ExpedienteMateria: {}
ExpedienteMateria: <AbstractOrdemDia>
TipoExpediente:
nome: nom_expediente
@ -39,17 +39,17 @@ IntegranteMesa (MesaSessaoPlenaria):
parlamentar: cod_parlamentar
sessao_plenaria: cod_sessao_plen
AbstractOrador:
<AbstractOrador>:
numero_ordem: num_ordem
parlamentar: cod_parlamentar
sessao_plenaria: cod_sessao_plen
url_discurso: url_discurso
Orador (Oradores): {}
Orador (Oradores): <AbstractOrador>
OradorExpediente (OradoresExpediente): {}
OradorExpediente (OradoresExpediente): <AbstractOrador>
OrdemDia: {}
OrdemDia: <AbstractOrdemDia>
PresencaOrdemDia (OrdemDiaPresenca):
parlamentar: cod_parlamentar

Loading…
Cancel
Save