Browse Source

Reverte reversion (#3605)

* Reverte reversion

* Remove arquivos legacy.yaml
pull/3607/head
Edward 2 years ago
committed by GitHub
parent
commit
b7bdbb1cc9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      requirements/requirements.txt
  2. 4
      sapl/audiencia/models.py
  3. 13
      sapl/base/admin.py
  4. 7
      sapl/base/legacy.yaml
  5. 15
      sapl/base/migrations/0052_auto_20220914_1125.py
  6. 5
      sapl/base/models.py
  7. 51
      sapl/comissoes/legacy.yaml
  8. 8
      sapl/comissoes/models.py
  9. 16
      sapl/compilacao/models.py
  10. 68
      sapl/legacy/Docs/verificação verbose names.txt
  11. 0
      sapl/legacy/__init__.py
  12. 0
      sapl/legacy/admin.py
  13. 0
      sapl/legacy/management/__init__.py
  14. 0
      sapl/legacy/management/commands/__init__.py
  15. 20
      sapl/legacy/management/commands/migracao_25_31.py
  16. 11
      sapl/legacy/management/commands/migracao_documentos.py
  17. 12
      sapl/legacy/management/commands/ressuscitar_deps.py
  18. 82
      sapl/legacy/migracao.py
  19. 1473
      sapl/legacy/migracao_dados.py
  20. 215
      sapl/legacy/migracao_documentos.py
  21. 109
      sapl/legacy/migracao_usuarios.py
  22. 1101
      sapl/legacy/models.py
  23. 22
      sapl/legacy/router.py
  24. 6
      sapl/legacy/run_legacy_tests.sh
  25. 3
      sapl/legacy/scripts/.flake8
  26. 0
      sapl/legacy/scripts/__init__.py
  27. 3
      sapl/legacy/scripts/exporta_zope/.gitignore
  28. 31
      sapl/legacy/scripts/exporta_zope/dump30.py
  29. 498
      sapl/legacy/scripts/exporta_zope/exporta_zope.py
  30. 8
      sapl/legacy/scripts/exporta_zope/requirements.txt
  31. 4
      sapl/legacy/scripts/exporta_zope/variaveis_comuns.py
  32. 15
      sapl/legacy/scripts/migra_dbs.sh
  33. 27
      sapl/legacy/scripts/migra_um_db.sh
  34. 40
      sapl/legacy/scripts/normaliza_dump_mysql.py
  35. 11
      sapl/legacy/scripts/recria_dbs_postgres.sh
  36. 15
      sapl/legacy/scripts/recria_um_db_postgres.sh
  37. 427
      sapl/legacy/scripts/ressuscita_dependencias.py
  38. 8
      sapl/legacy/scripts/shell_para_migracao.sh
  39. 14
      sapl/legacy/scripts/utils.py
  40. 62
      sapl/legacy/test_migracao_dados.py
  41. 113
      sapl/legacy/test_renames.py
  42. 206
      sapl/legacy/timezonesbrasil.py
  43. 0
      sapl/legacy/views.py
  44. 64
      sapl/legacy_migration_settings.py
  45. 18
      sapl/lexml/legacy.yaml
  46. 3
      sapl/lexml/models.py
  47. 146
      sapl/materia/legacy.yaml
  48. 24
      sapl/materia/models.py
  49. 46
      sapl/norma/legacy.yaml
  50. 9
      sapl/norma/models.py
  51. 3
      sapl/painel/models.py
  52. 101
      sapl/parlamentares/legacy.yaml
  53. 23
      sapl/parlamentares/models.py
  54. 62
      sapl/protocoloadm/legacy.yaml
  55. 10
      sapl/protocoloadm/models.py
  56. 9
      sapl/rules/apps.py
  57. 77
      sapl/sessao/legacy.yaml
  58. 28
      sapl/sessao/models.py
  59. 4
      sapl/settings.py
  60. 3
      sapl/utils.py
  61. 2
      setup.py

2
requirements/requirements.txt

@ -9,8 +9,6 @@ django-contrib-postgres==0.0.1
django-floppyforms==1.8.0
django-extra-views==0.12.0
django-model-utils==3.1.2
django-reversion==3.0.2
django-reversion-compare==0.8.6
django-speedinfo==1.4.0
django-extensions==2.1.4
django-image-cropping==1.2

4
sapl/audiencia/models.py

@ -1,4 +1,3 @@
import reversion
from django.db import models
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
@ -29,7 +28,6 @@ def anexo_upload_path(instance, filename):
instance, filename, subpath='anexo', pk_first=True)
@reversion.register()
class TipoAudienciaPublica(models.Model):
TIPO_AUDIENCIA_CHOICES = Choices(('A', 'audiencia', _('Audiência Pública')),
('P', 'plebiscito', _('Plebiscito')),
@ -51,7 +49,6 @@ class TipoAudienciaPublica(models.Model):
return self.nome
@reversion.register()
class AudienciaPublica(models.Model):
materia = models.ForeignKey(
MateriaLegislativa,
@ -175,7 +172,6 @@ class AudienciaPublica(models.Model):
update_fields=update_fields)
@reversion.register()
class AnexoAudienciaPublica(models.Model):
audiencia = models.ForeignKey(AudienciaPublica,
on_delete=models.PROTECT)

13
sapl/base/admin.py

@ -1,7 +1,6 @@
from django.contrib import admin
from django.shortcuts import redirect
from django.utils.translation import ugettext_lazy as _
from reversion.models import Revision
from sapl.base.models import AuditLog
from sapl.utils import register_all_models_in_admin
@ -12,18 +11,6 @@ admin.site.site_title = 'Administração - SAPL'
admin.site.site_header = 'Administração - SAPL'
class RevisionAdmin(admin.ModelAdmin):
list_display = ('user', 'comment', 'date_created')
search_fields = ('=user__username', '=user__email')
date_hierarchy = ('date_created')
def change_view(self, request, obj=None):
self.message_user(request, _('You cannot change history.'))
return redirect('admin:reversion_revision_changelist')
admin.site.register(Revision, RevisionAdmin)
class AuditLogAdmin(admin.ModelAdmin):
pass

7
sapl/base/legacy.yaml

@ -1,7 +0,0 @@
TipoAutor:
descricao: des_tipo_autor
Autor:
nome: nom_autor
cargo: des_cargo
tipo: tip_autor

15
sapl/base/migrations/0052_auto_20220914_1125.py

@ -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"),
]

5
sapl/base/models.py

@ -8,7 +8,6 @@ from django.db.models.deletion import CASCADE
from django.db.models.signals import post_migrate
from django.db.utils import DEFAULT_DB_ALIAS
from django.utils.translation import ugettext_lazy as _
import reversion
from sapl.utils import (LISTA_DE_UFS, YES_NO_CHOICES,
get_settings_auth_user_model, models_with_gr_for_model)
@ -42,7 +41,6 @@ ASSINATURA_ATA_CHOICES = (
)
@reversion.register()
class CasaLegislativa(models.Model):
# TODO ajustar todos os max_length !!!!
# cod_casa => id (pk)
@ -85,7 +83,6 @@ class CasaLegislativa(models.Model):
'municipio': self.municipio}
@reversion.register()
class AppConfig(models.Model):
POLITICA_PROTOCOLO_CHOICES = (
@ -298,7 +295,6 @@ class AppConfig(models.Model):
'id': self.id}
@reversion.register()
class TipoAutor(models.Model):
descricao = models.CharField(
max_length=50,
@ -323,7 +319,6 @@ class TipoAutor(models.Model):
return self.descricao
@reversion.register()
class Autor(models.Model):
operadores = models.ManyToManyField(
get_settings_auth_user_model(),

51
sapl/comissoes/legacy.yaml

@ -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

8
sapl/comissoes/models.py

@ -1,4 +1,3 @@
import reversion
from django.db import models
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
@ -10,7 +9,6 @@ from sapl.utils import (YES_NO_CHOICES, SaplGenericRelation,
OverwriteStorage)
@reversion.register()
class TipoComissao(models.Model):
NATUREZA_CHOICES = Choices(('T', 'temporaria', _('Temporária')),
('P', 'permanente', _('Permanente')))
@ -32,7 +30,6 @@ class TipoComissao(models.Model):
return self.nome
@reversion.register()
class Comissao(models.Model):
tipo = models.ForeignKey(TipoComissao,
on_delete=models.PROTECT,
@ -99,7 +96,6 @@ class Comissao(models.Model):
return self.sigla + ' - ' + self.nome
@reversion.register()
class Periodo(models.Model): # PeriodoCompComissao
data_inicio = models.DateField(verbose_name=_('Data Início'))
data_fim = models.DateField(
@ -120,7 +116,6 @@ class Periodo(models.Model): # PeriodoCompComissao
return '-'
@reversion.register()
class CargoComissao(models.Model):
id_ordenacao = models.PositiveIntegerField(
blank=True, null=True, verbose_name=_('Posição na Ordenação'),
@ -139,7 +134,6 @@ class CargoComissao(models.Model):
return self.nome
@reversion.register()
class Composicao(models.Model): # IGNORE
comissao = models.ForeignKey(Comissao,
on_delete=models.CASCADE,
@ -157,7 +151,6 @@ class Composicao(models.Model): # IGNORE
return '%s: %s' % (self.comissao.sigla, self.periodo)
@reversion.register()
class Participacao(models.Model): # ComposicaoComissao
composicao = models.ForeignKey(Composicao,
related_name='participacao_set',
@ -314,7 +307,6 @@ class Reuniao(models.Model):
update_fields=update_fields)
@reversion.register()
class DocumentoAcessorio(models.Model):
reuniao = models.ForeignKey(Reuniao,
related_name='documentoacessorio_set',

16
sapl/compilacao/models.py

@ -12,7 +12,6 @@ from django.utils.decorators import classonlymethod
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from image_cropping.fields import ImageCropField, ImageRatioField
import reversion
from sapl.compilacao.utils import (get_integrations_view_names, int_to_letter,
int_to_roman)
@ -20,7 +19,6 @@ from sapl.utils import YES_NO_CHOICES, get_settings_auth_user_model,\
texto_upload_path, restringe_tipos_de_arquivo_img
@reversion.register()
class TimestampedMixin(models.Model):
created = models.DateTimeField(
verbose_name=_('created'),
@ -32,7 +30,6 @@ class TimestampedMixin(models.Model):
abstract = True
@reversion.register()
class BaseModel(models.Model):
class Meta:
@ -87,7 +84,6 @@ class BaseModel(models.Model):
update_fields=update_fields)
@reversion.register()
class PerfilEstruturalTextoArticulado(BaseModel):
sigla = models.CharField(
max_length=10, unique=True, verbose_name=_('Sigla'))
@ -121,7 +117,6 @@ class PerfilEstruturalTextoArticulado(BaseModel):
return parents
@reversion.register()
class TipoTextoArticulado(models.Model):
sigla = models.CharField(max_length=3, verbose_name=_('Sigla'))
descricao = models.CharField(max_length=50, verbose_name=_('Descrição'))
@ -190,7 +185,6 @@ PRIVACIDADE_STATUS = (
)
@reversion.register()
class TextoArticulado(TimestampedMixin):
data = models.DateField(
blank=True,
@ -564,7 +558,6 @@ class TextoArticulado(TimestampedMixin):
update(dpk)
@reversion.register()
class TipoNota(models.Model):
sigla = models.CharField(
max_length=10, unique=True, verbose_name=_('Sigla'))
@ -581,7 +574,6 @@ class TipoNota(models.Model):
return '%s: %s' % (self.sigla, self.nome)
@reversion.register()
class TipoVide(models.Model):
sigla = models.CharField(
max_length=10, unique=True, verbose_name=_('Sigla'))
@ -596,7 +588,6 @@ class TipoVide(models.Model):
return '%s: %s' % (self.sigla, self.nome)
@reversion.register()
class TipoDispositivo(BaseModel):
"""
- no attributo rotulo_prefixo_texto, caso haja um ';' (ponto e vírgula), e
@ -806,7 +797,6 @@ class TipoDispositivo(BaseModel):
return False
@reversion.register()
class TipoDispositivoRelationship(BaseModel):
pai = models.ForeignKey(
TipoDispositivo,
@ -855,7 +845,6 @@ class TipoDispositivoRelationship(BaseModel):
self.filho_permitido.nome if self.filho_permitido else '')
@reversion.register()
class TipoPublicacao(models.Model):
sigla = models.CharField(
max_length=10, unique=True, verbose_name=_('Sigla'))
@ -870,7 +859,6 @@ class TipoPublicacao(models.Model):
return self.nome
@reversion.register()
class VeiculoPublicacao(models.Model):
sigla = models.CharField(
max_length=10, unique=True, verbose_name=_('Sigla'))
@ -885,7 +873,6 @@ class VeiculoPublicacao(models.Model):
return '%s: %s' % (self.sigla, self.nome)
@reversion.register()
class Publicacao(TimestampedMixin):
ta = models.ForeignKey(
TextoArticulado,
@ -965,7 +952,6 @@ def imagem_upload_path(instance, filename):
return texto_upload_path(instance, filename, subpath='')
@reversion.register()
class Dispositivo(BaseModel, TimestampedMixin):
TEXTO_PADRAO_DISPOSITIVO_REVOGADO = force_text(_('(Revogado)'))
INTERVALO_ORDEM = 1000
@ -1907,7 +1893,6 @@ class Dispositivo(BaseModel, TimestampedMixin):
ordem_bloco_atualizador=count)
@reversion.register()
class Vide(TimestampedMixin):
texto = models.TextField(verbose_name=_('Texto do Vide'))
@ -1954,7 +1939,6 @@ NOTAS_PUBLICIDADE_CHOICES = (
)
@reversion.register()
class Nota(TimestampedMixin):
NPRIV = 1

68
sapl/legacy/Docs/verificação verbose names.txt

@ -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?'

0
sapl/legacy/__init__.py

0
sapl/legacy/admin.py

0
sapl/legacy/management/__init__.py

0
sapl/legacy/management/commands/__init__.py

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

@ -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'])

11
sapl/legacy/management/commands/migracao_documentos.py

@ -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()

12
sapl/legacy/management/commands/ressuscitar_deps.py

@ -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()

82
sapl/legacy/migracao.py

@ -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)

1473
sapl/legacy/migracao_dados.py

File diff suppressed because it is too large

215
sapl/legacy/migracao_documentos.py

@ -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()

109
sapl/legacy/migracao_usuarios.py

@ -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):
"""
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)

1101
sapl/legacy/models.py

File diff suppressed because it is too large

22
sapl/legacy/router.py

@ -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

6
sapl/legacy/run_legacy_tests.sh

@ -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

3
sapl/legacy/scripts/.flake8

@ -1,3 +0,0 @@
[flake8]
ignore = E501

0
sapl/legacy/scripts/__init__.py

3
sapl/legacy/scripts/exporta_zope/.gitignore

@ -1,3 +0,0 @@
Data*.fs*
sapl_documentos
XSLT

31
sapl/legacy/scripts/exporta_zope/dump30.py

@ -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()

498
sapl/legacy/scripts/exporta_zope/exporta_zope.py

@ -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>')

8
sapl/legacy/scripts/exporta_zope/requirements.txt

@ -1,8 +0,0 @@
# ZODB version 3.7.4
ZODB==5.3.0
PyYAML
Unipath
GitPython
pyaml
python-magic
ipython

4
sapl/legacy/scripts/exporta_zope/variaveis_comuns.py

@ -1,4 +0,0 @@
from unipath import Path
DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand()
TAG_ZOPE = 'zope'

15
sapl/legacy/scripts/migra_dbs.sh

@ -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;

27
sapl/legacy/scripts/migra_um_db.sh

@ -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;

40
sapl/legacy/scripts/normaliza_dump_mysql.py

@ -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)

11
sapl/legacy/scripts/recria_dbs_postgres.sh

@ -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;

15
sapl/legacy/scripts/recria_um_db_postgres.sh

@ -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

427
sapl/legacy/scripts/ressuscita_dependencias.py

@ -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 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))

8
sapl/legacy/scripts/shell_para_migracao.sh

@ -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

14
sapl/legacy/scripts/utils.py

@ -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)]

62
sapl/legacy/test_migracao_dados.py

@ -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

113
sapl/legacy/test_renames.py

@ -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')

206
sapl/legacy/timezonesbrasil.py

@ -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)

0
sapl/legacy/views.py

64
sapl/legacy_migration_settings.py

@ -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

18
sapl/lexml/legacy.yaml

@ -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

3
sapl/lexml/models.py

@ -1,9 +1,7 @@
import reversion
from django.db import models
from django.utils.translation import ugettext_lazy as _
@reversion.register()
class LexmlProvedor(models.Model): # LexmlRegistroProvedor
id_provedor = models.PositiveIntegerField(verbose_name=_('Id do provedor'))
nome = models.CharField(max_length=255, verbose_name=_('Nome do provedor'))
@ -38,7 +36,6 @@ class LexmlProvedor(models.Model): # LexmlRegistroProvedor
return self.nome
@reversion.register()
class LexmlPublicador(models.Model):
id_publicador = models.PositiveIntegerField(
verbose_name=_('Id do publicador'))

146
sapl/materia/legacy.yaml

@ -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

24
sapl/materia/models.py

@ -8,7 +8,6 @@ from django.template import defaultfilters
from django.utils import formats, timezone
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
import reversion
from sapl.base.models import SEQUENCIA_NUMERACAO_PROTOCOLO, Autor
from sapl.comissoes.models import Comissao, Reuniao
@ -34,7 +33,6 @@ def grupo_autor():
return grupo.id
@reversion.register()
class TipoProposicao(models.Model):
descricao = models.CharField(
max_length=50,
@ -108,7 +106,6 @@ class TipoMateriaManager(models.Manager):
)
@reversion.register()
class TipoMateriaLegislativa(models.Model):
objects = TipoMateriaManager()
sigla = models.CharField(max_length=5, verbose_name=_('Sigla'))
@ -148,7 +145,6 @@ class TipoMateriaLegislativa(models.Model):
return self.descricao
@reversion.register()
class RegimeTramitacao(models.Model):
descricao = models.CharField(max_length=50, verbose_name=_('Descrição'))
@ -161,7 +157,6 @@ class RegimeTramitacao(models.Model):
return self.descricao
@reversion.register()
class Origem(models.Model):
sigla = models.CharField(max_length=10, verbose_name=_('Sigla'))
nome = models.CharField(max_length=50, verbose_name=_('Nome'))
@ -187,7 +182,6 @@ def anexo_upload_path(instance, filename):
return texto_upload_path(instance, filename, subpath=instance.materia.ano)
@reversion.register()
class MateriaLegislativa(models.Model):
tipo = models.ForeignKey(
@ -384,7 +378,6 @@ class MateriaLegislativa(models.Model):
update_fields=update_fields)
@reversion.register()
class Autoria(models.Model):
autor = models.ForeignKey(Autor,
verbose_name=_('Autor'),
@ -407,7 +400,6 @@ class Autoria(models.Model):
'autor': self.autor, 'materia': self.materia}
@reversion.register()
class AcompanhamentoMateria(models.Model):
usuario = models.CharField(max_length=50)
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
@ -436,7 +428,6 @@ class AcompanhamentoMateria(models.Model):
}
@reversion.register()
class PautaReuniao(models.Model):
reuniao = models.ForeignKey(
Reuniao, related_name='reuniao_set',
@ -462,7 +453,6 @@ class PautaReuniao(models.Model):
}
@reversion.register()
class Anexada(models.Model):
materia_principal = models.ForeignKey(
MateriaLegislativa, related_name='materia_principal_set',
@ -488,7 +478,6 @@ class Anexada(models.Model):
'materia_anexada': self.materia_anexada}
@reversion.register()
class AssuntoMateria(models.Model):
assunto = models.CharField(
max_length=50,
@ -507,7 +496,6 @@ class AssuntoMateria(models.Model):
return self.assunto
@reversion.register()
class DespachoInicial(models.Model):
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
comissao = models.ForeignKey(
@ -524,7 +512,6 @@ class DespachoInicial(models.Model):
'comissao': self.comissao}
@reversion.register()
class TipoDocumento(models.Model):
descricao = models.CharField(
max_length=50, verbose_name=_('Tipo Documento'))
@ -545,7 +532,6 @@ class TipoDocumento(models.Model):
return self.descricao
@reversion.register()
class DocumentoAcessorio(models.Model):
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
tipo = models.ForeignKey(
@ -613,7 +599,6 @@ class DocumentoAcessorio(models.Model):
update_fields=update_fields)
@reversion.register()
class MateriaAssunto(models.Model):
# TODO M2M ??
assunto = models.ForeignKey(
@ -635,7 +620,6 @@ class MateriaAssunto(models.Model):
'materia': self.materia, 'assunto': self.assunto}
@reversion.register()
class Numeracao(models.Model):
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
tipo_materia = models.ForeignKey(
@ -663,7 +647,6 @@ class Numeracao(models.Model):
'ano': self.ano_materia}
@reversion.register()
class Orgao(models.Model):
nome = models.CharField(max_length=256, verbose_name=_('Nome'))
sigla = models.CharField(max_length=15, verbose_name=_('Sigla'))
@ -693,7 +676,6 @@ class Orgao(models.Model):
'%(nome)s - %(sigla)s') % {'nome': self.nome, 'sigla': self.sigla}
@reversion.register()
class TipoFimRelatoria(models.Model):
descricao = models.CharField(
max_length=50, verbose_name=_('Tipo Fim Relatoria'))
@ -707,7 +689,6 @@ class TipoFimRelatoria(models.Model):
return self.descricao
@reversion.register()
class Relatoria(models.Model):
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
parlamentar = models.ForeignKey(Parlamentar,
@ -744,7 +725,6 @@ class Relatoria(models.Model):
'data': self.data_designacao_relator.strftime("%d/%m/%Y")}
@reversion.register()
class Parecer(models.Model):
relatoria = models.ForeignKey(Relatoria, on_delete=models.CASCADE)
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
@ -764,7 +744,6 @@ class Parecer(models.Model):
}
@reversion.register()
class Proposicao(models.Model):
autor = models.ForeignKey(
Autor,
@ -1074,7 +1053,6 @@ class HistoricoProposicao(models.Model):
return f'{self.data_hora} - {self.STATUS_PROPOSICAO[self.status]} - {str(self.proposicao)}'
@reversion.register()
class StatusTramitacao(models.Model):
INDICADOR_CHOICES = Choices(('F', 'fim', _('Fim')),
('R', 'retorno', _('Retorno')))
@ -1110,7 +1088,6 @@ class UnidadeTramitacaoManager(models.Manager):
).order_by('nome_composto')
@reversion.register()
class UnidadeTramitacao(models.Model):
comissao = models.ForeignKey(
Comissao, blank=True, null=True,
@ -1156,7 +1133,6 @@ class UnidadeTramitacao(models.Model):
return _('%(parlamentar)s') % {'parlamentar': self.parlamentar}
@reversion.register()
class Tramitacao(models.Model):
TURNO_CHOICES = Choices(
('P', 'primeiro', _('Primeiro')),

46
sapl/norma/legacy.yaml

@ -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

9
sapl/norma/models.py

@ -4,7 +4,6 @@ from django.template import defaultfilters
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
import reversion
from sapl.base.models import Autor
from sapl.compilacao.models import TextoArticulado
@ -16,7 +15,6 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
OverwriteStorage)
@reversion.register()
class AssuntoNorma(models.Model):
assunto = models.CharField(max_length=50, verbose_name=_('Assunto'))
descricao = models.CharField(
@ -31,7 +29,6 @@ class AssuntoNorma(models.Model):
return self.assunto
@reversion.register()
class TipoNormaJuridica(models.Model):
# TODO transform into Domain Model and use an FK for the field
EQUIVALENTE_LEXML_CHOICES = ((name, name) for name in
@ -126,7 +123,6 @@ class NormaJuridicaManager(models.Manager):
return qs
@reversion.register()
class NormaJuridica(models.Model):
objects = NormaJuridicaManager()
@ -346,7 +342,6 @@ class ViewNormasEstatisticas(models.Model):
db_table = "norma_viewnormasestatisticas"
@reversion.register()
class AutoriaNorma(models.Model):
autor = models.ForeignKey(Autor,
verbose_name=_('Autor'),
@ -369,7 +364,6 @@ class AutoriaNorma(models.Model):
'autor': self.autor, 'norma': self.norma}
@reversion.register()
class LegislacaoCitada(models.Model):
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
norma = models.ForeignKey(NormaJuridica, on_delete=models.CASCADE)
@ -407,7 +401,6 @@ class LegislacaoCitada(models.Model):
return str(self.norma)
@reversion.register()
class TipoVinculoNormaJuridica(models.Model):
sigla = models.CharField(
max_length=1, blank=True, verbose_name=_('Sigla'))
@ -428,7 +421,6 @@ class TipoVinculoNormaJuridica(models.Model):
return self.descricao_ativa
@reversion.register()
class NormaRelacionada(models.Model):
norma_principal = models.ForeignKey(
NormaJuridica,
@ -462,7 +454,6 @@ class NormaRelacionada(models.Model):
'norma_relacionada': str(self.norma_relacionada)}
@reversion.register()
class AnexoNormaJuridica(models.Model):
norma = models.ForeignKey(
NormaJuridica,

3
sapl/painel/models.py

@ -1,9 +1,7 @@
import reversion
from django.db import models
from django.utils.translation import ugettext_lazy as _
@reversion.register()
class Painel(models.Model):
PAINEL_TYPES = (
('C', 'Completo'),
@ -24,7 +22,6 @@ class Painel(models.Model):
return str(self.aberto) + ":" + self.data_painel.strftime("%d/%m/%Y")
@reversion.register()
class Cronometro(models.Model):
CRONOMETRO_TYPES = (
('A', _('Aparte')),

101
sapl/parlamentares/legacy.yaml

@ -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

23
sapl/parlamentares/models.py

@ -5,7 +5,6 @@ from django.utils.translation import ugettext_lazy as _
from image_cropping.fields import ImageCropField, ImageRatioField
from model_utils import Choices
from prompt_toolkit.key_binding.bindings.named_commands import self_insert
import reversion
from sapl.base.models import Autor
from sapl.decorators import vigencia_atual
@ -15,7 +14,6 @@ from sapl.utils import (LISTA_DE_UFS, YES_NO_CHOICES, SaplGenericRelation,
restringe_tipos_de_arquivo_img, texto_upload_path)
@reversion.register()
class Legislatura(models.Model):
numero = models.PositiveIntegerField(verbose_name=_('Número'))
data_inicio = models.DateField(verbose_name=_('Data Início'))
@ -47,7 +45,6 @@ class Legislatura(models.Model):
'end': self.data_fim.year}
@reversion.register()
class SessaoLegislativa(models.Model):
TIPO_SESSAO_CHOICES = Choices(
('O', 'ordinaria', _('Ordinária')),
@ -81,7 +78,6 @@ class SessaoLegislativa(models.Model):
'fim': self.data_fim.year}
@reversion.register()
class Coligacao(models.Model):
legislatura = models.ForeignKey(Legislatura,
on_delete=models.PROTECT,
@ -108,7 +104,6 @@ def logo_upload_path(instance, filename):
return get_logo_media_path(instance, 'logo', filename)
@reversion.register()
class Partido(models.Model):
sigla = models.CharField(max_length=20, verbose_name=_('Sigla'))
nome = models.CharField(max_length=50, verbose_name=_('Nome'))
@ -136,7 +131,6 @@ class Partido(models.Model):
}
@reversion.register()
class ComposicaoColigacao(models.Model):
# TODO M2M
partido = models.ForeignKey(Partido,
@ -155,7 +149,6 @@ class ComposicaoColigacao(models.Model):
}
@reversion.register()
class NivelInstrucao(models.Model):
descricao = models.CharField(
max_length=50, verbose_name=_('Nível de Instrução'))
@ -169,7 +162,6 @@ class NivelInstrucao(models.Model):
return self.descricao
@reversion.register()
class SituacaoMilitar(models.Model):
descricao = models.CharField(
max_length=50, verbose_name=_('Situação Militar'))
@ -196,7 +188,6 @@ def true_false_none(x):
return None
@reversion.register()
class Parlamentar(models.Model):
FEMININO = 'F'
MASCULINO = 'M'
@ -342,7 +333,6 @@ class Parlamentar(models.Model):
update_fields=update_fields)
@reversion.register()
class TipoDependente(models.Model):
descricao = models.CharField(max_length=150, verbose_name=_('Descrição'))
@ -355,7 +345,6 @@ class TipoDependente(models.Model):
return self.descricao
@reversion.register()
class Dependente(models.Model):
FEMININO = 'F'
MASCULINO = 'M'
@ -388,7 +377,6 @@ class Dependente(models.Model):
return self.nome
@reversion.register()
class Filiacao(models.Model):
data = models.DateField(verbose_name=_('Data Filiação'))
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.CASCADE)
@ -411,7 +399,6 @@ class Filiacao(models.Model):
}
@reversion.register()
class TipoAfastamento(models.Model):
descricao = models.CharField(max_length=50, verbose_name=_('Descrição'))
indicador = models.CharField(
@ -430,7 +417,6 @@ class TipoAfastamento(models.Model):
return self.descricao
@reversion.register()
class Mandato(models.Model):
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.CASCADE)
tipo_afastamento = models.ForeignKey(
@ -484,7 +470,6 @@ class Mandato(models.Model):
f.data_desfiliacao or timezone.datetime.max.date())]
@reversion.register()
class CargoMesa(models.Model):
# TODO M2M ????
descricao = models.CharField(
@ -501,7 +486,6 @@ class CargoMesa(models.Model):
return self.descricao
@reversion.register()
class MesaDiretora(models.Model):
data_inicio = models.DateField(verbose_name=_('Data Início'), null=True)
data_fim = models.DateField(verbose_name=_('Data Fim'), null=True)
@ -520,7 +504,6 @@ class MesaDiretora(models.Model):
}
@reversion.register()
class ComposicaoMesa(models.Model):
# TODO M2M ???? Ternary?????
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.PROTECT)
@ -539,7 +522,6 @@ class ComposicaoMesa(models.Model):
}
@reversion.register()
class Frente(models.Model):
'''
* Uma frente agrupa vários parlamentares
@ -581,7 +563,6 @@ class Frente(models.Model):
return self.nome
@reversion.register()
class FrenteCargo(models.Model):
nome_cargo = models.CharField(
max_length=80,
@ -600,7 +581,6 @@ class FrenteCargo(models.Model):
return f"{self.nome_cargo}"
@reversion.register()
class FrenteParlamentar(models.Model):
frente = models.ForeignKey(
Frente,
@ -652,7 +632,6 @@ class Votante(models.Model):
return self.user.username
@reversion.register()
class Bloco(models.Model):
'''
* blocos podem existir por mais de uma legislatura
@ -694,7 +673,6 @@ class Bloco(models.Model):
return self.nome
@reversion.register()
class BlocoCargo(models.Model):
nome_cargo = models.CharField(
max_length=120,
@ -713,7 +691,6 @@ class BlocoCargo(models.Model):
return f"{self.nome_cargo}"
@reversion.register()
class BlocoMembro(models.Model):
bloco = models.ForeignKey(
Bloco,

62
sapl/protocoloadm/legacy.yaml

@ -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

10
sapl/protocoloadm/models.py

@ -5,7 +5,6 @@ from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
import reversion
from sapl.base.models import Autor, AppConfig as SaplAppConfig
from sapl.materia.models import TipoMateriaLegislativa, UnidadeTramitacao,\
@ -15,7 +14,6 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, texto_upload_path,
OverwriteStorage)
@reversion.register()
class TipoDocumentoAdministrativo(models.Model):
sigla = models.CharField(max_length=5, verbose_name=_('Sigla'))
descricao = models.CharField(max_length=50, verbose_name=_('Descrição'))
@ -54,7 +52,6 @@ def texto_upload_path(instance, filename):
"""
@reversion.register()
class Protocolo(models.Model):
numero = models.PositiveIntegerField(
blank=False,
@ -157,7 +154,6 @@ class Protocolo(models.Model):
}
@reversion.register()
class DocumentoAdministrativo(models.Model):
tipo = models.ForeignKey(
TipoDocumentoAdministrativo, on_delete=models.PROTECT,
@ -345,7 +341,6 @@ class DocumentoAdministrativo(models.Model):
update_fields=update_fields)
@reversion.register()
class DocumentoAcessorioAdministrativo(models.Model):
documento = models.ForeignKey(DocumentoAdministrativo,
on_delete=models.PROTECT)
@ -403,7 +398,6 @@ class DocumentoAcessorioAdministrativo(models.Model):
update_fields=update_fields)
@reversion.register()
class StatusTramitacaoAdministrativo(models.Model):
INDICADOR_CHOICES = Choices(
('F', 'fim', _('Fim')),
@ -427,7 +421,6 @@ class StatusTramitacaoAdministrativo(models.Model):
return self.descricao
@reversion.register()
class TramitacaoAdministrativo(models.Model):
status = models.ForeignKey(
StatusTramitacaoAdministrativo,
@ -481,7 +474,6 @@ class TramitacaoAdministrativo(models.Model):
}
@reversion.register()
class Anexado(models.Model):
documento_principal = models.ForeignKey(
DocumentoAdministrativo, related_name='documento_principal_set',
@ -512,7 +504,6 @@ class Anexado(models.Model):
}
@reversion.register()
class VinculoDocAdminMateria(models.Model):
documento = models.ForeignKey(
DocumentoAdministrativo, related_name='materialegislativa_vinculada_set',
@ -543,7 +534,6 @@ class VinculoDocAdminMateria(models.Model):
return f'Vinculo: {self.documento} - {self.materia}'
@reversion.register()
class AcompanhamentoDocumento(models.Model):
usuario = models.CharField(max_length=50)
documento = models.ForeignKey(

9
sapl/rules/apps.py

@ -9,7 +9,6 @@ from django.core import exceptions
from django.db import models, router
from django.db.utils import DEFAULT_DB_ALIAS
from django.utils.translation import ugettext_lazy as _
import reversion
from sapl.rules import (SAPL_GROUP_ADMINISTRATIVO, SAPL_GROUP_COMISSOES,
SAPL_GROUP_GERAL, SAPL_GROUP_MATERIA, SAPL_GROUP_NORMA,
@ -237,14 +236,6 @@ def cria_usuarios_padrao():
rules.cria_usuarios_padrao()
def revision_pre_delete_signal(sender, **kwargs):
with reversion.create_revision():
kwargs['instance'].save()
reversion.set_comment("Deletado pelo sinal.")
models.signals.post_migrate.connect(receiver=update_groups)
models.signals.post_migrate.connect(
receiver=create_proxy_permissions, dispatch_uid="django.contrib.auth.management.create_permissions")
models.signals.pre_delete.connect(
receiver=revision_pre_delete_signal, dispatch_uid="pre_delete_signal")

77
sapl/sessao/legacy.yaml

@ -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

28
sapl/sessao/models.py

@ -6,7 +6,6 @@ from django.db.models import Q, F
from django.utils import timezone, formats
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
import reversion
from sapl.base.models import Autor
from sapl.materia.models import MateriaLegislativa
@ -20,7 +19,6 @@ from sapl.utils import (YES_NO_CHOICES, SaplGenericRelation,
OverwriteStorage)
@reversion.register()
class CargoBancada(models.Model):
nome_cargo = models.CharField(max_length=80,
verbose_name=_('Cargo de Bancada'))
@ -38,7 +36,6 @@ class CargoBancada(models.Model):
return self.nome_cargo
@reversion.register()
class Bancada(models.Model):
legislatura = models.ForeignKey(Legislatura,
on_delete=models.PROTECT,
@ -76,7 +73,6 @@ class Bancada(models.Model):
return self.nome
@reversion.register()
class TipoSessaoPlenaria(models.Model):
TIPO_NUMERACAO_CHOICES = Choices(
@ -157,7 +153,6 @@ def anexo_upload_path(instance, filename):
# return get_sessao_media_path(instance, 'anexo', filename)
@reversion.register()
class SessaoPlenaria(models.Model):
# TODO trash??? Seems to have been a FK in the past. Would be:
# andamento_sessao = models.ForeignKey(
@ -359,7 +354,6 @@ class SessaoPlenaria(models.Model):
).update(data_ordem=self.data_inicio)
@reversion.register()
class AbstractOrdemDia(models.Model):
TIPO_VOTACAO_CHOICES = Choices(
(1, 'simbolica', 'Simbólica'),
@ -413,7 +407,6 @@ class AbstractOrdemDia(models.Model):
self.numero_ordem, self.materia, self.sessao_plenaria)
@reversion.register()
class ExpedienteMateria(AbstractOrdemDia):
class Meta:
@ -422,7 +415,6 @@ class ExpedienteMateria(AbstractOrdemDia):
ordering = ['numero_ordem']
@reversion.register()
class TipoExpediente(models.Model):
nome = models.CharField(max_length=100, verbose_name=_('Tipo'))
ordenacao = models.PositiveIntegerField(
@ -439,7 +431,6 @@ class TipoExpediente(models.Model):
return self.nome
@reversion.register()
class ExpedienteSessao(models.Model): # ExpedienteSessaoPlenaria
sessao_plenaria = models.ForeignKey(
SessaoPlenaria,
@ -459,7 +450,6 @@ class ExpedienteSessao(models.Model): # ExpedienteSessaoPlenaria
return '%s - %s' % (self.tipo, self.sessao_plenaria)
@reversion.register()
class OcorrenciaSessao(models.Model): # OcorrenciaSessaoPlenaria
sessao_plenaria = models.OneToOneField(SessaoPlenaria,
on_delete=models.PROTECT)
@ -475,7 +465,6 @@ class OcorrenciaSessao(models.Model): # OcorrenciaSessaoPlenaria
return '%s - %s' % (self.sessao_plenaria, self.conteudo)
@reversion.register()
class ConsideracoesFinais(models.Model): # ConsideracoesFinaisSessaoPlenaria
sessao_plenaria = models.OneToOneField(SessaoPlenaria,
on_delete=models.PROTECT)
@ -491,7 +480,6 @@ class ConsideracoesFinais(models.Model): # ConsideracoesFinaisSessaoPlenaria
return '%s - %s' % (self.sessao_plenaria, self.conteudo)
@reversion.register()
class IntegranteMesa(models.Model): # MesaSessaoPlenaria
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.CASCADE)
@ -507,7 +495,6 @@ class IntegranteMesa(models.Model): # MesaSessaoPlenaria
return '%s - %s' % (self.cargo, self.parlamentar)
@reversion.register()
class AbstractOrador(models.Model): # Oradores
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.CASCADE)
@ -546,7 +533,6 @@ class AbstractOrador(models.Model): # Oradores
return result
@reversion.register()
class Orador(AbstractOrador): # Oradores
class Meta:
@ -555,7 +541,6 @@ class Orador(AbstractOrador): # Oradores
ordering = ('id',)
@reversion.register()
class OradorExpediente(AbstractOrador): # OradoresExpediente
class Meta:
@ -564,7 +549,6 @@ class OradorExpediente(AbstractOrador): # OradoresExpediente
ordering = ('id',)
@reversion.register()
class OradorOrdemDia(AbstractOrador): # OradoresOrdemDia
class Meta:
@ -573,7 +557,6 @@ class OradorOrdemDia(AbstractOrador): # OradoresOrdemDia
ordering = ('id',)
@reversion.register()
class OrdemDia(AbstractOrdemDia):
class Meta:
@ -582,7 +565,6 @@ class OrdemDia(AbstractOrdemDia):
ordering = ['numero_ordem']
@reversion.register()
class PresencaOrdemDia(models.Model): # OrdemDiaPresenca
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.CASCADE)
@ -600,7 +582,6 @@ class PresencaOrdemDia(models.Model): # OrdemDiaPresenca
'parlamentar': self.parlamentar}
@reversion.register()
class TipoResultadoVotacao(models.Model):
NATUREZA_CHOICES = Choices(
('A', 'aprovado', 'Aprovado'),
@ -620,7 +601,6 @@ class TipoResultadoVotacao(models.Model):
return self.nome
@reversion.register()
class RegistroVotacao(models.Model):
tipo_resultado_votacao = models.ForeignKey(
TipoResultadoVotacao,
@ -679,7 +659,6 @@ class RegistroVotacao(models.Model):
'{}, {}'. format(self.ordem, self.expediente))
@reversion.register()
class VotoParlamentar(models.Model): # RegistroVotacaoParlamentar
'''
As colunas ordem e expediente são redundantes, levando em consideração
@ -724,7 +703,6 @@ class VotoParlamentar(models.Model): # RegistroVotacaoParlamentar
'votacao': self.votacao, 'parlamentar': self.parlamentar}
@reversion.register()
class SessaoPlenariaPresenca(models.Model):
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.CASCADE)
@ -757,7 +735,6 @@ ORDENACAO_RESUMO = [
]
@reversion.register()
class ResumoOrdenacao(models.Model):
'''
Tabela para registrar em qual ordem serão renderizados os componentes
@ -837,7 +814,6 @@ class ResumoOrdenacao(models.Model):
return 'Ordenação do Resumo de uma Sessão'
@reversion.register()
class TipoRetiradaPauta(models.Model):
descricao = models.CharField(max_length=150, verbose_name=_('Descrição'))
@ -850,7 +826,6 @@ class TipoRetiradaPauta(models.Model):
return self.descricao
@reversion.register()
class TipoJustificativa(models.Model):
descricao = models.CharField(max_length=150, verbose_name=_('Descrição'))
@ -863,7 +838,6 @@ class TipoJustificativa(models.Model):
return self.descricao
@reversion.register()
class JustificativaAusencia(models.Model):
TIPO_AUSENCIA_CHOICES = Choices(
(1, 'materia', 'Matéria'),
@ -988,7 +962,6 @@ class RetiradaPauta(models.Model):
'{}, {}'. format(self.ordem, self.expediente))
@reversion.register()
class RegistroLeitura(models.Model):
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
ordem = models.ForeignKey(OrdemDia,
@ -1037,7 +1010,6 @@ class RegistroLeitura(models.Model):
'{}, {}'. format(self.ordem, self.expediente))
@reversion.register()
class Correspondencia(models.Model):
TIPO_CHOICES = Choices(
(1, 'recebida', 'Recebida'),

4
sapl/settings.py

@ -88,9 +88,6 @@ INSTALLED_APPS = (
'easy_thumbnails',
'image_cropping',
'reversion',
'reversion_compare',
'haystack',
'django.contrib.postgres',
'speedinfo',
@ -127,7 +124,6 @@ HAYSTACK_CONNECTIONS = {
}
MIDDLEWARE = [
'reversion.middleware.RevisionMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',

3
sapl/utils.py

@ -37,7 +37,6 @@ from easy_thumbnails import source_generators
from floppyforms import ClearableFileInput
import magic
import requests
from reversion_compare.admin import CompareVersionAdmin
from unipath.path import Path
from sapl.crispy_layout_mixin import (form_actions, SaplFormHelper,
@ -363,7 +362,7 @@ def register_all_models_in_admin(module_name, exclude_list=[]):
app = apps.get_app_config(appname)
for model in app.get_models():
class CustomModelAdmin(CompareVersionAdmin):
class CustomModelAdmin(admin.ModelAdmin):
list_display = [f.name for f in model._meta.fields
if f.name != 'id' and f.name not in exclude_list]

2
setup.py

@ -19,8 +19,6 @@ install_requires = [
'django-floppyforms==1.7.0',
'django-extra-views==0.12.0',
'django-model-utils==3.1.2',
'django-reversion==3.0.2',
'django-reversion-compare==0.8.6',
'django-speedinfo==1.4.0',
'django-extensions==2.1.4',
'django-image-cropping==1.2.0',

Loading…
Cancel
Save