mirror of https://github.com/interlegis/sapl.git
committed by
GitHub
252 changed files with 5416 additions and 2994 deletions
@ -1,17 +1,17 @@ |
|||
#!/bin/bash |
|||
|
|||
# Check if there's some debug breakpoint in codebase |
|||
# Verifica se um breakpoint foi esquecido no código |
|||
me=`basename "$0"` |
|||
stmts=`grep --exclude=$me -r -l "ipdb.set_trace()" * | wc -l` |
|||
if [ $stmts != '0' ] |
|||
busca=`grep --color=auto --exclude=$me --exclude=ipython_log.py* -r -l "pdb.set_trace()" .` |
|||
|
|||
if [ ! -z "$busca" ] |
|||
then |
|||
echo "==================================================================" |
|||
echo "ERROR: ipdb.set_trace() call in codebase! Remove, please." |
|||
grep --exclude=$me -r -n "ipdb.set_trace()" * |
|||
echo "==================================================================" |
|||
echo "============================================================================" |
|||
echo "ERROR: pdb.set_trace() encontrado nos seguintes arquivos. Remova, por favor." |
|||
echo "$busca" |
|||
echo "============================================================================" |
|||
fi |
|||
|
|||
# QA checks: run this before every commit |
|||
./manage.py check |
|||
flake8 --exclude='ipython_log.py*,migrations,templates' . |
|||
isort --recursive --check-only --skip='migrations' --skip='templates' --skip='ipython_log.py' . |
|||
# ./manage.py check |
|||
# flake8 --exclude='ipython_log.py*,migrations,templates' . |
|||
# isort --recursive --check-only --skip='migrations' --skip='templates' --skip='ipython_log.py' . |
|||
|
|||
@ -0,0 +1,34 @@ |
|||
Créditos do SAPL - até versão 2.5 |
|||
================================= |
|||
|
|||
Obrigado aos colaboradores: |
|||
|
|||
- Adriano Gomes |
|||
- Angelo Marcondes Neto |
|||
- Claudio Morale |
|||
- Daniel C. Azevedo |
|||
- Davi Lima de Medeiros |
|||
- Edson Ma |
|||
- Fernando Ciciliati Júnior |
|||
- Gustavo Lepri |
|||
- Halison Casimiro |
|||
- Helder Vieira |
|||
- Jean Rodrigo Ferri |
|||
- João Lima |
|||
- José Borges |
|||
- Leandro Roberto |
|||
- Leonardo Caballero |
|||
- Luciano Di Fázio |
|||
- Luis Fernando Pires Machado |
|||
- Marcio Mazza |
|||
- Marcos Fragomeni |
|||
- Maria Cristina André de Mello |
|||
- Marta Maria Pincowsca Cardoso Maia |
|||
- Paulo Fernandes de Souza Júnior |
|||
- Petronio Barbosa Carvalho |
|||
- Ricardo Esperandio |
|||
- Rodrigo Barbosa Luz |
|||
- Sesóstris Vieira |
|||
- Sérgio Damiati |
|||
- Wilton Souza Alencar |
|||
- Wu Man Qi |
|||
@ -1,111 +0,0 @@ |
|||
Instruções para Importação da base mysql 2.5 |
|||
============================================ |
|||
|
|||
|
|||
Para entrar no ambiente virtual:: |
|||
|
|||
workon sapl |
|||
|
|||
|
|||
|
|||
Instalar Dependências:: |
|||
|
|||
pip3 install -r requirements/migration-requirements.txt |
|||
|
|||
Criar um arquivo sapl/legacy/.env com o seguinte conteúdo (parametros de acesso ao banco 2.5):: |
|||
|
|||
DATABASE_URL = mysql://[usuario do mysql]:[senha do myuysql]@[host]:[porta]/[banco] |
|||
|
|||
|
|||
o conteúdo do arquivo será semelhante a isso:: |
|||
|
|||
DATABASE_URL = mysql://sapl:sapl@localhost:3306/interlegis |
|||
|
|||
|
|||
Posteriormente rodar a seguinte sequencia de comandos estando no ambiente virtual:: |
|||
|
|||
./manage.py shell --settings=sapl.legacy_migration_settings |
|||
|
|||
%run sapl/legacy/migration.py |
|||
|
|||
migrate() |
|||
|
|||
|
|||
Migração de documentos do sapl 2.5 |
|||
---------------------------------- |
|||
|
|||
No sapl 2.5 todos os documentos ficavam armazenados no ZODB (o banco do Zope). |
|||
No sapl 3.1 eles ficam no sistema de arquivos convencional e portanto precisam: |
|||
|
|||
1. ser exportados para o sistema de arquivos |
|||
2. ser vinculados ao novo banco importado para o sapl 3.1 |
|||
|
|||
|
|||
Exportar os documentos para o sistema de arquivos |
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
|
|||
Siga os seguintes passos: |
|||
|
|||
1. Instale o `Products.FSDump` no sapl 2.5. |
|||
|
|||
Para isso basta colocar a pasta `Products/FSDump` do projeto https://github.com/zopefoundation/Products.FSDump na pasta `Products` da instalação do sapl 2.5 e reiniciar o Zope. |
|||
|
|||
A pasta a ser instalada é a seguinte: |
|||
https://github.com/zopefoundation/Products.FSDump/tree/master/Products/FSDump |
|||
|
|||
2. Na ZMI, na pasta `sapl_documentos`, adicione um objeto do tipo `Dumper`: |
|||
|
|||
- Em `Filesystem path` escolha uma pasta do sistema de arquivos local para onde os arquivos serão copiados |
|||
- Desmarque a opção `Use .metadata file` |
|||
- Clique no botão `Add` |
|||
|
|||
3. Use o objeto `Dumper` criado para exportar os arquivos: |
|||
|
|||
- Clique no objeto `Dumper` criado para ver suas opções |
|||
- Confira seus parametros e clique em `Change and Dump` |
|||
- Aguarde a exportação dos arquivos e verifique que foram copiados para a pasta indicada |
|||
|
|||
|
|||
Vincular os documentos ao novo banco do sapl 3.1 |
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
|
|||
1. Primeiramente migre o banco do sapl 2.5 para o sapl 3.1 |
|||
|
|||
2. Copie a pasta exportada `sapl_documentos` dentro da pasta `media` da instalação do sapl 3.1 |
|||
|
|||
3. De forma semelhante ao realizado na migração do banco, dentro no mesmo ambiente virtual, rode os seguintes comandos:: |
|||
|
|||
./manage.py shell --settings=sapl.legacy_migration_settings |
|||
|
|||
%run sapl/legacy/migracao_documentos.py |
|||
|
|||
migrar_documentos() |
|||
|
|||
|
|||
Para indexar os arquivos para pesquisa textual |
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
1. workon sapl |
|||
2. ./manage.py rebuild_index |
|||
|
|||
|
|||
Dependendo da quantidade de arquivos a serem indexados, pode ser listado o seguinte erro 'Too many open files' |
|||
|
|||
Isto está ligado a quantidade máxima de aquivos que podem ser abertos ao mesmo tempo pelo sistema operacional |
|||
|
|||
Para aumentar este limite:: |
|||
|
|||
sudo nano /etc/security/limits.conf |
|||
* soft nofile 9000 |
|||
* hard nofile 65000 |
|||
|
|||
|
|||
sudo nano /etc/pam.d/common-session |
|||
session required pam_limits.so |
|||
|
|||
Após reiniciar, verificar se foram carregados os novos parâmetros com o comando:: |
|||
ulimit -a |
|||
|
|||
deve ser apresentado o seguinte:: |
|||
open files (-n) 9000 |
|||
|
|||
|
|||
@ -1,9 +1,9 @@ |
|||
-r test-requirements.txt |
|||
autopep8==1.2.4 |
|||
beautifulsoup4==4.4.1 |
|||
beautifulsoup4==4.6.0 |
|||
django-debug-toolbar==1.5 |
|||
ipdb==0.10.1 |
|||
pip-review==0.4 |
|||
pygraphviz==1.3.1 |
|||
pytest-ipdb==0.1-prerelease2 |
|||
pipdeptree |
|||
pipdeptree==0.10.1 |
|||
|
|||
@ -1,2 +1,2 @@ |
|||
-r dev-requirements.txt |
|||
mysqlclient |
|||
mysqlclient==1.3.12 |
|||
|
|||
@ -0,0 +1,20 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.13 on 2017-10-16 20:06 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('base', '0008_auto_20170814_1409'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AddField( |
|||
model_name='appconfig', |
|||
name='mostrar_brasao_painel', |
|||
field=models.BooleanField(default=False, verbose_name='Mostrar brasão da Casa no painel?'), |
|||
), |
|||
] |
|||
@ -0,0 +1,19 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.11 on 2017-10-18 16:50 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('base', '0009_appconfig_mostrar_brasao_painel'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.RemoveField( |
|||
model_name='appconfig', |
|||
name='painel_aberto', |
|||
), |
|||
] |
|||
@ -0,0 +1,19 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.13 on 2017-11-21 11:58 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('base', '0010_remove_appconfig_painel_aberto'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='appconfig', |
|||
options={'ordering': ('-id',), 'permissions': (('menu_sistemas', 'Renderizar Menu Sistemas'), ('view_tabelas_auxiliares', 'Visualizar Tabelas Auxiliares')), 'verbose_name': 'Configurações da Aplicação', 'verbose_name_plural': 'Configurações da Aplicação'}, |
|||
), |
|||
] |
|||
@ -0,0 +1,20 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.13 on 2017-12-05 11:17 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('base', '0011_auto_20171121_0958'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='tipoautor', |
|||
name='descricao', |
|||
field=models.CharField(help_text='Obs: Não crie tipos de autores semelhante aos tipos fixos. ', max_length=50, verbose_name='Descrição'), |
|||
), |
|||
] |
|||
@ -0,0 +1,9 @@ |
|||
|
|||
from django import template |
|||
|
|||
register = template.Library() |
|||
|
|||
|
|||
@register.filter |
|||
def tipoautor_contenttype_list(tipo): |
|||
return 'sapl.'+tipo.content_type.app_label+':'+tipo.content_type.model+'_list' |
|||
@ -0,0 +1,35 @@ |
|||
import pytest |
|||
from django.core.urlresolvers import reverse |
|||
from django.utils.translation import ugettext_lazy as _ |
|||
|
|||
|
|||
@pytest.mark.django_db(transaction=False) |
|||
def test_incluir_casa_legislativa_errors(admin_client): |
|||
|
|||
response = admin_client.post(reverse('sapl.base:casalegislativa_create'), |
|||
{'salvar': 'salvar'}, |
|||
follow=True) |
|||
|
|||
assert (response.context_data['form'].errors['nome'] == |
|||
[_('Este campo é obrigatório.')]) |
|||
assert (response.context_data['form'].errors['sigla'] == |
|||
[_('Este campo é obrigatório.')]) |
|||
assert (response.context_data['form'].errors['endereco'] == |
|||
[_('Este campo é obrigatório.')]) |
|||
assert (response.context_data['form'].errors['cep'] == |
|||
[_('Este campo é obrigatório.')]) |
|||
assert (response.context_data['form'].errors['municipio'] == |
|||
[_('Este campo é obrigatório.')]) |
|||
assert (response.context_data['form'].errors['uf'] == |
|||
[_('Este campo é obrigatório.')]) |
|||
|
|||
|
|||
@pytest.mark.django_db(transaction=False) |
|||
def test_incluir_tipo_autor_errors(admin_client): |
|||
|
|||
response = admin_client.post(reverse('sapl.base:tipoautor_create'), |
|||
{'salvar': 'salvar'}, |
|||
follow=True) |
|||
|
|||
assert (response.context_data['form'].errors['descricao'] == |
|||
[_('Este campo é obrigatório.')]) |
|||
@ -0,0 +1,19 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.11 on 2017-12-04 18:58 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('comissoes', '0002_auto_20170809_1236'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='comissao', |
|||
options={'ordering': ['nome'], 'verbose_name': 'Comissão', 'verbose_name_plural': 'Comissões'}, |
|||
), |
|||
] |
|||
@ -0,0 +1,25 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.13 on 2017-10-31 15:27 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('compilacao', '0003_auto_20170825_1136'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='tipotextoarticulado', |
|||
name='participacao_social', |
|||
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Participação Social'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='tipotextoarticulado', |
|||
name='publicacao_func', |
|||
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Histórico de Publicação'), |
|||
), |
|||
] |
|||
@ -0,0 +1,54 @@ |
|||
import base64 |
|||
import hashlib |
|||
|
|||
from django.contrib.auth.hashers import PBKDF2PasswordHasher, make_password |
|||
from django.utils.encoding import force_bytes |
|||
|
|||
|
|||
def to_base64(source): |
|||
return base64.b64encode(source).decode('utf-8') |
|||
|
|||
|
|||
class ZopeSHA1PasswordHasher(PBKDF2PasswordHasher): |
|||
""" |
|||
The SHA1 password hashing algorithm used by Zope. |
|||
Zope uses `password + salt`, Django has `salt + password`. |
|||
Pre encode with SHA1 in this order and PBKDF2 afterwards. |
|||
|
|||
based on https://www.fourdigits.nl/blog/converting-plone-data-to-django/ |
|||
""" |
|||
|
|||
algorithm = "zope_sha1_pbkdf2" |
|||
|
|||
def encode(self, password, salt, iterations=None): |
|||
assert password is not None |
|||
assert salt |
|||
password = force_bytes(password) |
|||
decoded_salt = base64.b64decode(salt) |
|||
|
|||
# this is what is stored in zope |
|||
hashed = hashlib.sha1(password + decoded_salt).digest() + decoded_salt |
|||
hashed = to_base64(hashed) |
|||
|
|||
# encode again with the standard method |
|||
return super().encode(hashed, salt, iterations) |
|||
|
|||
|
|||
def get_salt_from_zope_sha1(data): |
|||
intermediate = base64.b64decode(data) |
|||
salt = intermediate[20:].strip() |
|||
return to_base64(salt) |
|||
|
|||
|
|||
ZOPE_SHA1_PREFIX = '{SSHA}' |
|||
|
|||
|
|||
def zope_encoded_password_to_django(encoded): |
|||
if encoded.startswith(ZOPE_SHA1_PREFIX): |
|||
data = encoded[len(ZOPE_SHA1_PREFIX):] |
|||
salt = get_salt_from_zope_sha1(data) |
|||
hasher = ZopeSHA1PasswordHasher() |
|||
return super(ZopeSHA1PasswordHasher, hasher).encode(data, salt) |
|||
else: |
|||
# assume it's a plain password and use the default hashing |
|||
return make_password(encoded) |
|||
@ -0,0 +1,79 @@ |
|||
from django.contrib.auth.models import Group, User |
|||
|
|||
from sapl.settings import MEDIA_ROOT |
|||
|
|||
PERFIL_LEGADO_PARA_NOVO = {legado: Group.objects.get(name=novo) |
|||
for legado, novo in [ |
|||
('Autor', 'Autor'), |
|||
('Operador', 'Operador Geral'), |
|||
('Operador 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'), |
|||
] |
|||
} |
|||
|
|||
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 migra_usuarios(): |
|||
""" |
|||
Lê o arquivo media/USERS 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 = MEDIA_ROOT.child('USERS') |
|||
with open(ARQUIVO_USUARIOS, 'r') as f: |
|||
usuarios = eval(f.read()) |
|||
usuarios = [ |
|||
(nome, |
|||
# troca senha "inicial" por uma inutilizável |
|||
senha if senha != 'inicial' else None, |
|||
# filtra perfis ignorados |
|||
{p for p in perfis if p not in IGNORADOS}) |
|||
for nome, senha, perfis in usuarios] |
|||
|
|||
for nome, senha, perfis in usuarios: |
|||
usuario = User.objects.get_or_create(username=nome)[0] |
|||
for perfil in perfis: |
|||
if perfil in ADMINISTRADORES: |
|||
# Manager |
|||
usuario.is_staff = True |
|||
usuario.save() |
|||
else: |
|||
usuario.groups.add(PERFIL_LEGADO_PARA_NOVO[perfil]) |
|||
# apaga arquivo (importante pois contém senhas) |
|||
ARQUIVO_USUARIOS.remove() |
|||
@ -0,0 +1,3 @@ |
|||
Data*.fs* |
|||
sapl_documentos |
|||
XSLT |
|||
@ -0,0 +1,261 @@ |
|||
#!/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 os.path |
|||
import sys |
|||
from collections import defaultdict |
|||
from functools import partial |
|||
from os.path import splitext |
|||
|
|||
import yaml |
|||
import ZODB.DB |
|||
import ZODB.FileStorage |
|||
from ZODB.broken import Broken |
|||
|
|||
EXTENSOES = { |
|||
'application/msword': '.doc', |
|||
'application/pdf': '.pdf', |
|||
'application/vnd.oasis.opendocument.text': '.odt', |
|||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx', # noqa |
|||
'application/xml': '.xml', |
|||
'text/xml': '.xml', |
|||
'application/zip': '.zip', |
|||
'image/jpeg': '.jpeg', |
|||
'image/png': '.png', |
|||
'image/gif': '.gif', |
|||
'text/html': '.html', |
|||
'text/rtf': '.rtf', |
|||
'text/x-python': '.py', |
|||
'text/plain': '.txt', |
|||
'SDE-Document': 'xml', |
|||
|
|||
# TODO rever... |
|||
'text/richtext': '.rtf', |
|||
|
|||
# sem extensao |
|||
'application/octet-stream': '', # binario |
|||
'inode/x-empty': '', # vazio |
|||
'text/x-unknown-content-type': '', |
|||
} |
|||
|
|||
|
|||
def br(obj): |
|||
if isinstance(obj, Broken): |
|||
return obj.__Broken_state__ |
|||
else: |
|||
return obj |
|||
|
|||
|
|||
extensoes_desconhecidas = defaultdict(list) |
|||
|
|||
|
|||
def dump_file(doc, path): |
|||
id = doc['__name__'] |
|||
name, extension = splitext(id) |
|||
content_type = doc['content_type'] |
|||
extension = extension or EXTENSOES.get(content_type, 'ZZZZ') |
|||
|
|||
fullname = os.path.join(path, name + extension) |
|||
print(fullname) |
|||
|
|||
if extension == 'ZZZZ': |
|||
extensoes_desconhecidas[content_type].append(fullname) |
|||
|
|||
# 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 |
|||
|
|||
pdata = br(doc.pop('data')) |
|||
if isinstance(pdata, str): |
|||
# Retrocedemos se pdata ja eh uma str (necessario em Images) |
|||
doc['data'] = pdata |
|||
pdata = doc |
|||
|
|||
with open(fullname, 'w') as arq: |
|||
while pdata: |
|||
arq.write(pdata.pop('data')) |
|||
pdata = br(pdata.pop('next', None)) |
|||
|
|||
return id |
|||
|
|||
|
|||
def enumerate_by_key_list(folder, key_list, type_key): |
|||
for entry in folder.get(key_list, []): |
|||
id, meta_type = entry['id'], entry[type_key] |
|||
obj = br(folder.get(id, None)) |
|||
yield id, obj, meta_type |
|||
|
|||
|
|||
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'] |
|||
for contagem_real, (id, obj) in enumerate(tree.iteritems(), start=1): |
|||
obj, meta_type = br(obj), type(obj).__name__ |
|||
yield id, obj, meta_type |
|||
# verificação de consistência |
|||
assert contagem_esperada == contagem_real |
|||
|
|||
|
|||
nao_identificados = defaultdict(list) |
|||
|
|||
|
|||
def dump_folder(folder, path='', enum=enumerate_folder): |
|||
name = folder['id'] |
|||
path = os.path.join(path, name) |
|||
if not os.path.exists(path): |
|||
os.makedirs(path) |
|||
for id, obj, meta_type in enum(folder): |
|||
dump = DUMP_FUNCTIONS.get(meta_type, '?') |
|||
if dump == '?': |
|||
nao_identificados[meta_type].append(path + '/' + id) |
|||
elif dump: |
|||
id_interno = dump(obj, path) |
|||
assert id == id_interno |
|||
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(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, read_sde(obj) |
|||
|
|||
data = dict(read_properties()) |
|||
children = list(read_children()) |
|||
if children: |
|||
data['children'] = children |
|||
return data |
|||
|
|||
|
|||
def save_as_yaml(path, name, obj): |
|||
fullname = os.path.join(path, name) |
|||
with open(fullname, 'w') as arquivo: |
|||
yaml.safe_dump(obj, arquivo) |
|||
print(fullname) |
|||
return fullname |
|||
|
|||
|
|||
def dump_sde(strdoc, path, tipo): |
|||
id = strdoc['id'] |
|||
sde = read_sde(strdoc) |
|||
save_as_yaml(path, '{}.{}.yaml'.format(id, tipo), sde) |
|||
return id |
|||
|
|||
|
|||
DUMP_FUNCTIONS = { |
|||
'File': dump_file, |
|||
'Image': dump_file, |
|||
'Folder': partial(dump_folder, enum=enumerate_folder), |
|||
'BTreeFolder2': partial(dump_folder, enum=enumerate_btree), |
|||
'SDE-Document': partial(dump_sde, tipo='sde.document'), |
|||
'SDE-Template': partial(dump_sde, tipo='sde.template'), |
|||
|
|||
# explicitamente ignorados |
|||
'ZCatalog': None, |
|||
'Dumper': None, |
|||
} |
|||
|
|||
|
|||
def get_app(data_fs_path): |
|||
storage = ZODB.FileStorage.FileStorage(data_fs_path) |
|||
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): |
|||
for obj in app['_objects']: |
|||
id, meta_type = obj['id'], obj['meta_type'] |
|||
if id.startswith('cm_') and meta_type == 'Folder': |
|||
cm_zzz = br(app[id]) |
|||
sapl = br(cm_zzz.get('sapl', None)) |
|||
if sapl and 'sapl_documentos' in sapl and 'acl_users' in sapl: |
|||
return sapl |
|||
|
|||
|
|||
def dump_propriedades(docs, path): |
|||
props_sapl = br(docs['props_sapl']) |
|||
ids = [p['id'] for p in props_sapl['_properties']] |
|||
props = {id: props_sapl[id] for id in ids} |
|||
props = {id: p.decode('iso-8859-1') if isinstance(p, str) else p |
|||
for id, p in props.items()} |
|||
save_as_yaml(path, 'sapl_documentos/propriedades.yaml', props) |
|||
|
|||
|
|||
def dump_usuarios(sapl, path): |
|||
users = br(br(sapl['acl_users'])['data']) |
|||
users = {k: br(v) for k, v in users['data'].items()} |
|||
save_as_yaml(path, 'usuarios.yaml', users) |
|||
|
|||
|
|||
def dump_sapl(data_fs_path, destino='../../../../media'): |
|||
app, close_db = get_app(data_fs_path) |
|||
try: |
|||
sapl = find_sapl(app) |
|||
# extrai folhas XSLT |
|||
dump_folder(br(sapl['XSLT']), destino) |
|||
# extrai usuários com suas senhas e perfis |
|||
dump_usuarios(sapl, destino) |
|||
|
|||
# extrai documentos |
|||
docs = br(sapl['sapl_documentos']) |
|||
nao_identificados.clear() |
|||
dump_folder(docs, destino) |
|||
dump_propriedades(docs, destino) |
|||
if nao_identificados: |
|||
print('#' * 80) |
|||
print('#' * 80) |
|||
print(u'FORAM ENCONTRADOS ARQUIVOS DE FORMATO NÃO IDENTIFICADO!!!') |
|||
print(u'REFAÇA A EXPORTAÇÃO\n') |
|||
print(nao_identificados) |
|||
print('#' * 80) |
|||
print('#' * 80) |
|||
finally: |
|||
close_db() |
|||
|
|||
|
|||
if __name__ == "__main__": |
|||
if len(sys.argv) == 2: |
|||
data_fs_path = sys.argv[1] |
|||
dump_sapl(data_fs_path) |
|||
else: |
|||
print('Uso: python exporta_zope <caminho p Data.fs>') |
|||
@ -0,0 +1,3 @@ |
|||
# ZODB version 3.7.4 |
|||
PyYAML==3.12 |
|||
ZODB==5.3.0 |
|||
@ -1,28 +0,0 @@ |
|||
-- Apaga as restrições somente para essa sessão |
|||
SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES,','ALLOW_INVALID_DATES'); |
|||
-- Exclui procedures caso já existam |
|||
DROP PROCEDURE IF EXISTS verifica_campos_proposicao; |
|||
DROP PROCEDURE IF EXISTS verifica_campos_tipo_materia_legislativa; |
|||
DROP PROCEDURE IF EXISTS verifica_campos_sessao_plenaria_presenca; |
|||
DROP PROCEDURE IF EXISTS cria_lexml_registro_provedor_e_publicador; |
|||
DROP PROCEDURE IF EXISTS cria_tipo_situacao_militar; |
|||
DROP PROCEDURE IF EXISTS muda_vinculo_norma_juridica_ind_excluido; |
|||
-- Procedure para criar campo num_proposicao em proposicao |
|||
CREATE PROCEDURE verifica_campos_proposicao() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='proposicao' AND column_name='num_proposicao') THEN UPDATE proposicao SET dat_envio = '1800-01-01' WHERE CAST(dat_envio AS CHAR(20)) = '0000-00-00 00:00:00'; ALTER TABLE proposicao ADD COLUMN num_proposicao INT(11) NULL after txt_justif_devolucao; END IF; END; |
|||
-- Procedure para criar campo iind_num_automatica em tipo_materia_legislativa |
|||
CREATE PROCEDURE verifica_campos_tipo_materia_legislativa() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='tipo_materia_legislativa' AND column_name='ind_num_automatica') THEN ALTER TABLE tipo_materia_legislativa ADD COLUMN ind_num_automatica BOOLEAN NULL DEFAULT FALSE after des_tipo_materia; END IF; IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='tipo_materia_legislativa' AND column_name='quorum_minimo_votacao') THEN ALTER TABLE tipo_materia_legislativa ADD COLUMN quorum_minimo_votacao INT(11) NULL after ind_num_automatica; END IF; END; |
|||
-- Procedure para criar campos cod_presenca_sessao (sendo a nova PK da tabela) e dat_sessao em sessao_plenaria_presenca |
|||
CREATE PROCEDURE verifica_campos_sessao_plenaria_presenca() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='sessao_plenaria_presenca' AND column_name='cod_presenca_sessao') THEN ALTER TABLE sessao_plenaria_presenca DROP PRIMARY KEY, ADD cod_presenca_sessao INT AUTO_INCREMENT PRIMARY KEY FIRST; END IF; IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='sessao_plenaria_presenca' AND column_name='dat_sessao') THEN ALTER TABLE sessao_plenaria_presenca ADD COLUMN dat_sessao DATE NULL after cod_parlamentar; END IF; END; |
|||
-- Procedure para criar tabela lexml_registro_provedor e lexml_registro_publicador |
|||
CREATE PROCEDURE cria_lexml_registro_provedor_e_publicador() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='lexml_registro_publicador') THEN CREATE TABLE lexml_registro_publicador (cod_publicador INT AUTO_INCREMENT NOT NULL, id_publicador INT, nom_publicador VARCHAR(255), adm_email VARCHAR(50), sigla VARCHAR(255), nom_responsavel VARCHAR(255), tipo VARCHAR(50), id_responsavel INT, PRIMARY KEY (cod_publicador)); END IF; IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='lexml_registro_provedor') THEN CREATE TABLE lexml_registro_provedor (cod_provedor INT AUTO_INCREMENT NOT NULL, id_provedor INT, nom_provedor VARCHAR(255), sgl_provedor VARCHAR(15), adm_email VARCHAR(50), nom_responsavel VARCHAR(255), tipo VARCHAR(50), id_responsavel INT, xml_provedor LONGTEXT, PRIMARY KEY (cod_provedor)); END IF; END; |
|||
-- Procedure para criar tabela tipo_situacao_militar |
|||
CREATE PROCEDURE cria_tipo_situacao_militar() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='tipo_situacao_militar') THEN CREATE TABLE tipo_situacao_militar (tip_situacao_militar INT AUTO_INCREMENT NOT NULL, des_tipo_situacao VARCHAR(50), ind_excluido INT, PRIMARY KEY (tip_situacao_militar)); END IF; END; |
|||
-- Procedure para mudar valor do campo ind_excluido da tabela vinculo_norma_juridica de 0 para string vazia '' |
|||
CREATE PROCEDURE muda_vinculo_norma_juridica_ind_excluido() BEGIN UPDATE vinculo_norma_juridica SET ind_excluido = '' WHERE trim(ind_excluido) = '0'; END; |
|||
-- Executa as procedures criadas acima |
|||
CALL verifica_campos_proposicao; |
|||
CALL verifica_campos_tipo_materia_legislativa; |
|||
CALL verifica_campos_sessao_plenaria_presenca; |
|||
CALL cria_lexml_registro_provedor_e_publicador; |
|||
CALL cria_tipo_situacao_militar; |
|||
CALL muda_vinculo_norma_juridica_ind_excluido; |
|||
@ -1,31 +1,48 @@ |
|||
#!/bin/bash |
|||
|
|||
# rodar esse script na raiz do projeto |
|||
|
|||
DIR=~/logs_migracao |
|||
mkdir -p $DIR |
|||
|
|||
LOG="$DIR/$1.migracao.log" |
|||
rm -f $LOG |
|||
|
|||
echo "########################################" | tee -a $LOG |
|||
echo "MIGRANDO BANCO $1" | tee -a $LOG |
|||
echo "########################################" | tee -a $LOG |
|||
echo >> $LOG |
|||
|
|||
|
|||
echo "--- DJANGO MIGRATE ---" | tee -a $LOG |
|||
echo >> $LOG |
|||
DATABASE_NAME=$1 ./manage.py migrate --settings sapl.legacy_migration_settings |
|||
echo >> $LOG |
|||
|
|||
echo "--- MIGRACAO DE DADOS ---" | tee -a $LOG |
|||
echo >> $LOG |
|||
DATABASE_NAME=$1 ./manage.py migracao_25_31 -f --settings sapl.legacy_migration_settings |& tee -a $LOG |
|||
echo >> $LOG |
|||
|
|||
|
|||
echo "--- RECRIANDO CONSTRAINTS ---" | tee -a $LOG |
|||
echo >> $LOG |
|||
DATABASE_NAME=$1 ./manage.py recria_constraints --settings sapl.legacy_migration_settings |& tee -a $LOG |
|||
echo >> $LOG |
|||
if [ $# -ge 2 ]; then |
|||
|
|||
# proteje pasta com dumps de alterações acidentais |
|||
chmod -R -w ~/sapl_dumps |
|||
|
|||
DATE=$(date +%Y-%m-%d) |
|||
DIR=~/${DATE}_logs_migracao |
|||
mkdir -p $DIR |
|||
|
|||
LOG="$DIR/$1.migracao.log" |
|||
rm -f $LOG |
|||
|
|||
echo "########################################" | tee -a $LOG |
|||
echo "MIGRANDO BANCO $1" | tee -a $LOG |
|||
echo "########################################" | tee -a $LOG |
|||
echo >> $LOG |
|||
|
|||
if [ $3 ]; then |
|||
# se há senha do mysql |
|||
mysql -u $2 -p "$3" -N -s -e "DROP DATABASE IF EXISTS $1; CREATE DATABASE $1;" |
|||
mysql -u $2 -p "$3" < ~/sapl_dumps/$1.sql |
|||
else |
|||
# se não há senha do mysql |
|||
mysql -u $2 -N -s -e "DROP DATABASE IF EXISTS $1; CREATE DATABASE $1;" |
|||
mysql -u $2 < ~/sapl_dumps/$1.sql |
|||
fi; |
|||
echo "O banco legado foi restaurado" |& tee -a $LOG |
|||
echo >> $LOG |
|||
|
|||
echo "--- DJANGO MIGRATE ---" | tee -a $LOG |
|||
echo >> $LOG |
|||
DATABASE_NAME=$1 ./manage.py migrate --settings sapl.legacy_migration_settings |
|||
echo >> $LOG |
|||
|
|||
# XXX Na primeira execução desse comando aparece o erro de "Coammands out of sync" |
|||
# A solução mais rápida foi executar duas vezes seguidas pra poder migrar. |
|||
DATABASE_NAME=$1 ./manage.py migracao_25_31 -f --settings sapl.legacy_migration_settings |
|||
echo "--- MIGRACAO DE DADOS ---" | tee -a $LOG |
|||
echo >> $LOG |
|||
DATABASE_NAME=$1 ./manage.py migracao_25_31 -f --settings sapl.legacy_migration_settings |& tee -a $LOG |
|||
echo >> $LOG |
|||
else |
|||
echo "USO:" |
|||
echo " $0 <nome_database> <usuário mysql> [senha mysql]" |
|||
fi; |
|||
|
|||
@ -1,5 +1,11 @@ |
|||
#!/bin/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_" |
|||
|
|||
mysql -u root -padmin -e 'show databases;' | grep '^sapl_' | xargs -I{} ./recria_um_db_postgres.sh {} |
|||
|
|||
if [ $# -eq 2 ]; then |
|||
parallel --verbose -j+0 ./recria_um_db_postgres.sh :::: <(mysql -u $1 -p$2 -e 'show databases;' | grep '^sapl_' | grep -v '_copy$') |
|||
else |
|||
echo "USO:" |
|||
echo " $0 [usuário mysql] [senha mysql]" |
|||
fi; |
|||
@ -1,5 +1,6 @@ |
|||
# (Re)cria um db postgres |
|||
# uso: recria_um_db_postgres <NOME DO BANCO> |
|||
|
|||
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;" |
|||
|
|||
@ -1,150 +0,0 @@ |
|||
#!/usr/bin/python |
|||
|
|||
# requisito: pip install PyMySQL |
|||
|
|||
import pymysql.cursors |
|||
|
|||
HOST = 'localhost' |
|||
USER = 'root' |
|||
PASSWORD = '' |
|||
DB = '' |
|||
|
|||
|
|||
SELECT_EXCLUIDOS = "SELECT %s FROM %s WHERE ind_excluido = 1 ORDER BY %s" |
|||
|
|||
REGISTROS_INCONSISTENTES = "DELETE FROM %s WHERE %s " |
|||
"in (%s) AND ind_excluido = 0 " |
|||
|
|||
EXCLUI_REGISTRO = "DELETE FROM %s WHERE ind_excluido=1" |
|||
|
|||
NORMA_DEP = "DELETE FROM vinculo_norma_juridica WHERE cod_norma_referente in (%s) OR \ |
|||
cod_norma_referida in (%s) AND ind_excluido = 0 " |
|||
|
|||
mapa = {} # mapa com tabela principal -> tabelas dependentes |
|||
|
|||
mapa['tipo_autor'] = ['autor'] |
|||
mapa['materia_legislativa'] = ['acomp_materia', 'autoria', 'despacho_inicial', |
|||
'documento_acessorio', 'expediente_materia', |
|||
'legislacao_citada', 'materia_assunto', |
|||
'numeracao', 'ordem_dia', 'parecer', |
|||
'proposicao', 'registro_votacao', |
|||
'relatoria', 'tramitacao'] |
|||
mapa['norma_juridica'] = ['vinculo_norma_juridica'] |
|||
mapa['comissao'] = ['composicao_comissao'] |
|||
mapa['sessao_legislativa'] = ['composicao_mesa'] |
|||
mapa['tipo_expediente'] = ['expediente_sessao_plenaria'] |
|||
|
|||
""" |
|||
mapa['autor'] = ['tipo_autor', 'partido', 'comissao', 'parlamentar'] |
|||
mapa['parlamentar'] = ['autor', 'autoria', 'composicao_comissao', |
|||
'composicao_mesa', 'dependente', 'filiacao', |
|||
'mandato', 'mesa_sessao_plenaria', 'oradores', |
|||
'oradores_expediente', 'ordem_dia_presenca', |
|||
'registro_votacao_parlamentar', 'relatoria', |
|||
'sessao_plenaria_presenca', 'unidade_tramitacao'] |
|||
""" |
|||
|
|||
|
|||
def get_ids_excluidos(cursor, query): |
|||
""" |
|||
recupera as PKs de registros com ind_excluido = 1 da tabela principal |
|||
""" |
|||
cursor.execute(query) |
|||
excluidos = cursor.fetchall() |
|||
# flat tuple of tuples with map transformation into string |
|||
excluidos = [str(val) for sublist in excluidos for val in sublist] |
|||
return excluidos |
|||
|
|||
|
|||
def remove_tabelas(cursor, tabela_principal, pk, query_dependentes=None): |
|||
|
|||
QUERY = SELECT_EXCLUIDOS % (pk, tabela_principal, pk) |
|||
ids_excluidos = get_ids_excluidos(cursor, QUERY) |
|||
print("\nRegistros da tabela '%s' com ind_excluido = 1: %s" % |
|||
(tabela_principal.upper(), len(ids_excluidos))) |
|||
|
|||
""" |
|||
Remove registros de tabelas que dependem da tabela principal, |
|||
e que se encontram com ind_excluido = 0 (nao excluidas), se |
|||
tais registros existirem. |
|||
""" |
|||
if ids_excluidos: |
|||
print("Dependencias inconsistentes") |
|||
for tabela in mapa[tabela_principal]: |
|||
|
|||
QUERY_DEP = REGISTROS_INCONSISTENTES % ( |
|||
tabela, pk, ','.join(ids_excluidos)) |
|||
|
|||
# Trata caso especifico de norma_juridica |
|||
if query_dependentes: |
|||
QUERY_DEP = query_dependentes % (','.join(ids_excluidos), |
|||
','.join(ids_excluidos)) |
|||
|
|||
print(tabela.upper(), cursor.execute(QUERY_DEP)) |
|||
|
|||
""" |
|||
Remove todos os registros com ind_excluido = 1 das tabelas |
|||
dependentes e da tabela principal, nesta ordem. |
|||
""" |
|||
print("\n\nRegistros com ind_excluido = 1") |
|||
for tabela in mapa[tabela_principal] + [tabela_principal]: |
|||
QUERY = EXCLUI_REGISTRO % tabela |
|||
print(tabela.upper(), cursor.execute(QUERY)) |
|||
|
|||
|
|||
def remove_excluidas(cursor): |
|||
cursor.execute("SHOW_TABLES") |
|||
for row in cursor.fetchall(): |
|||
print(row) |
|||
|
|||
|
|||
def remove_proposicao_invalida(cursor): |
|||
return cursor.execute( |
|||
"DELETE FROM proposicao WHERE cod_mat_ou_doc is null") |
|||
|
|||
|
|||
def remove_materia_assunto_invalida(cursor): |
|||
return cursor.execute( |
|||
"DELETE FROM materia_assunto WHERE cod_assunto = 0") |
|||
|
|||
|
|||
def shotgun_remove(cursor): |
|||
for tabela in get_ids_excluidos(cursor, "SHOW TABLES"): |
|||
try: |
|||
cursor.execute("DELETE FROM %s WHERE ind_excluido = 1" % tabela) |
|||
except: |
|||
pass |
|||
|
|||
|
|||
if __name__ == '__main__': |
|||
connection = pymysql.connect(host=HOST, |
|||
user=USER, |
|||
password=PASSWORD, |
|||
db=DB) |
|||
cursor = connection.cursor() |
|||
# TIPO AUTOR |
|||
remove_tabelas(cursor, 'tipo_autor', 'tip_autor') |
|||
# MATERIA LEGISLATIVA |
|||
remove_tabelas(cursor, 'materia_legislativa', 'cod_materia') |
|||
# NORMA JURIDICA |
|||
remove_tabelas(cursor, 'norma_juridica', 'cod_norma', NORMA_DEP) |
|||
# COMISSAO |
|||
remove_tabelas(cursor, 'comissao', 'cod_comissao') |
|||
# SESSAO LEGISLATIVA |
|||
remove_tabelas(cursor, 'sessao_legislativa', 'cod_sessao_leg') |
|||
# EXPEDIENTE SESSAO |
|||
remove_tabelas(cursor, 'tipo_expediente', 'cod_expediente') |
|||
# AUTOR |
|||
remove_tabelas(cursor, 'autor', 'cod_autor') |
|||
# PARLAMENTAR |
|||
remove_tabelas(cursor, 'parlamentar', 'cod_parlamentar') |
|||
|
|||
# PROPOSICAO |
|||
remove_proposicao_invalida(cursor) |
|||
|
|||
# MATERIA_ASSUNTO |
|||
remove_materia_assunto_invalida(cursor) |
|||
|
|||
# shotgun_remove(cursor) |
|||
|
|||
cursor.close() |
|||
@ -0,0 +1,26 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.12 on 2017-08-15 12:38 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
import django.db.models.deletion |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('materia', '0011_auto_20170808_1034'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='proposicao', |
|||
name='tipo', |
|||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='materia.TipoProposicao', verbose_name='Tipo'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='tramitacao', |
|||
name='status', |
|||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='materia.StatusTramitacao', verbose_name='Status'), |
|||
), |
|||
] |
|||
@ -0,0 +1,21 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.12 on 2017-08-16 11:36 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
import django.db.models.deletion |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('materia', '0012_auto_20170815_1238'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='tramitacao', |
|||
name='unidade_tramitacao_destino', |
|||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='tramitacoes_destino', to='materia.UnidadeTramitacao', verbose_name='Unidade Destino'), |
|||
), |
|||
] |
|||
@ -0,0 +1,19 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.7 on 2017-09-05 08:18 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('materia', '0013_adiciona_status_tramitacao'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='unidadetramitacao', |
|||
options={'ordering': ['orgao', 'comissao', 'parlamentar'], 'verbose_name': 'Unidade de Tramitação', 'verbose_name_plural': 'Unidades de Tramitação'}, |
|||
), |
|||
] |
|||
@ -0,0 +1,37 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.13 on 2017-09-08 10:24 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
from sapl.materia.models import TipoProposicao |
|||
|
|||
|
|||
class AlterUniqueTogetherFixConstraintInexistente( |
|||
migrations.AlterUniqueTogether): |
|||
|
|||
def database_forwards(self, |
|||
app_label, schema_editor, from_state, to_state): |
|||
constraint_names = schema_editor._constraint_names( |
|||
TipoProposicao, ['content_type_id', 'object_id'], unique=True) |
|||
if constraint_names: |
|||
# por alguma razão a constraint não existe em alguns bancos |
|||
# se ela existir continua a exetução normal |
|||
super(AlterUniqueTogetherFixConstraintInexistente, |
|||
self).database_forwards( |
|||
app_label, schema_editor, from_state, to_state |
|||
) |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('materia', '0014_auto_20170905_0818'), |
|||
] |
|||
|
|||
operations = [ |
|||
AlterUniqueTogetherFixConstraintInexistente( |
|||
name='tipoproposicao', |
|||
unique_together=set([]), |
|||
), |
|||
] |
|||
@ -0,0 +1,16 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.13 on 2017-09-08 11:57 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('materia', '0015_auto_20170908_1024'), |
|||
('materia', '0013_auto_20170816_1136'), |
|||
] |
|||
|
|||
operations = [ |
|||
] |
|||
@ -0,0 +1,20 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.13 on 2017-09-18 12:57 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('materia', '0016_merge'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='proposicao', |
|||
name='data_envio', |
|||
field=models.DateTimeField(null=True, verbose_name='Data de Envio'), |
|||
), |
|||
] |
|||
@ -0,0 +1,101 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.11 on 2017-11-13 15:39 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
import django.db.models.deletion |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('materia', '0017_auto_20170918_1257'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='anexada', |
|||
name='materia_anexada', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materia_anexada_set', to='materia.MateriaLegislativa'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='anexada', |
|||
name='materia_principal', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materia_principal_set', to='materia.MateriaLegislativa'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='autoria', |
|||
name='autor', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='base.Autor', verbose_name='Autor'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='autoria', |
|||
name='materia', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa', verbose_name='Matéria Legislativa'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='despachoinicial', |
|||
name='comissao', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='comissoes.Comissao'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='despachoinicial', |
|||
name='materia', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='documentoacessorio', |
|||
name='materia', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='materiaassunto', |
|||
name='assunto', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.AssuntoMateria', verbose_name='Assunto'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='materiaassunto', |
|||
name='materia', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa', verbose_name='Matéria'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='numeracao', |
|||
name='materia', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='parecer', |
|||
name='materia', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='parecer', |
|||
name='relatoria', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.Relatoria'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='proposicao', |
|||
name='materia_de_vinculo', |
|||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='proposicao_set', to='materia.MateriaLegislativa', verbose_name='Matéria anexadora'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='relatoria', |
|||
name='comissao', |
|||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comissoes.Comissao', verbose_name='Comissão'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='relatoria', |
|||
name='materia', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='relatoria', |
|||
name='parlamentar', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='parlamentares.Parlamentar', verbose_name='Parlamentar'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='tramitacao', |
|||
name='materia', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa'), |
|||
), |
|||
] |
|||
@ -0,0 +1,26 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.13 on 2017-11-27 17:00 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
import django.db.models.deletion |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('materia', '0018_auto_20171113_1339'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='anexada', |
|||
name='materia_anexada', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materia_anexada_set', to='materia.MateriaLegislativa', verbose_name='Matéria Anexada'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='anexada', |
|||
name='materia_principal', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materia_principal_set', to='materia.MateriaLegislativa', verbose_name='Matéria Principal'), |
|||
), |
|||
] |
|||
@ -0,0 +1,27 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.11 on 2017-12-04 18:58 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('materia', '0019_auto_20171127_1500'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='orgao', |
|||
options={'ordering': ['nome'], 'verbose_name': 'Órgão', 'verbose_name_plural': 'Órgãos'}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='tipodocumento', |
|||
options={'ordering': ['descricao'], 'verbose_name': 'Tipo de Documento', 'verbose_name_plural': 'Tipos de Documento'}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='unidadetramitacao', |
|||
options={'verbose_name': 'Unidade de Tramitação', 'verbose_name_plural': 'Unidades de Tramitação'}, |
|||
), |
|||
] |
|||
@ -0,0 +1,68 @@ |
|||
import pytest |
|||
from django.utils.translation import ugettext as _ |
|||
from model_mommy import mommy |
|||
|
|||
from sapl.materia import forms |
|||
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa |
|||
|
|||
|
|||
@pytest.mark.django_db(transaction=False) |
|||
def test_valida_campos_obrigatorios_ficha_pesquisa_form(): |
|||
form = forms.FichaPesquisaForm(data={}) |
|||
|
|||
assert not form.is_valid() |
|||
|
|||
errors = form.errors |
|||
|
|||
assert errors['tipo_materia'] == [_('Este campo é obrigatório.')] |
|||
assert errors['data_inicial'] == [_('Este campo é obrigatório.')] |
|||
assert errors['data_final'] == [_('Este campo é obrigatório.')] |
|||
|
|||
assert len(errors) == 3 |
|||
|
|||
|
|||
@pytest.mark.django_db(transaction=False) |
|||
def test_ficha_pesquisa_form_datas_invalidas(): |
|||
tipo = mommy.make(TipoMateriaLegislativa) |
|||
|
|||
form = forms.FichaPesquisaForm(data={'tipo_materia': str(tipo.pk), |
|||
'data_inicial': '10/11/2017', |
|||
'data_final': '09/11/2017' |
|||
}) |
|||
assert not form.is_valid() |
|||
assert form.errors['__all__'] == [_('A Data Final não pode ser menor que ' |
|||
'a Data Inicial')] |
|||
|
|||
|
|||
@pytest.mark.django_db(transaction=False) |
|||
def test_ficha_pesquisa_form_invalido(): |
|||
tipo = mommy.make(TipoMateriaLegislativa) |
|||
|
|||
form = forms.FichaPesquisaForm(data={'tipo_materia': str(tipo.pk), |
|||
'data_inicial': '10/11/2017', |
|||
'data_final': '09/11/2017' |
|||
}) |
|||
|
|||
assert not form.is_valid() |
|||
|
|||
|
|||
@pytest.mark.django_db(transaction=False) |
|||
def test_valida_campos_obrigatorios_ficha_seleciona_form(): |
|||
form = forms.FichaSelecionaForm(data={}) |
|||
|
|||
assert not form.is_valid() |
|||
|
|||
errors = form.errors |
|||
|
|||
assert errors['materia'] == [_('Este campo é obrigatório.')] |
|||
|
|||
assert len(errors) == 1 |
|||
|
|||
|
|||
@pytest.mark.django_db(transaction=False) |
|||
def test_ficha_seleciona_form_valido(): |
|||
materia = mommy.make(MateriaLegislativa) |
|||
|
|||
form = forms.FichaSelecionaForm(data={'materia': str(materia.pk)}) |
|||
|
|||
assert form.is_valid() |
|||
@ -0,0 +1,119 @@ |
|||
[ |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Altera o(a)", |
|||
"descricao_passiva": "Alterado(a) pelo(a)", |
|||
"sigla": "A" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "1" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Revoga integralmente o(a)", |
|||
"descricao_passiva": "Revogado(a) integralmente pelo(a)", |
|||
"sigla": "R" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "2" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Revoga parcialmente o(a)", |
|||
"descricao_passiva": "Revogado(a) parcialmente pelo(a)", |
|||
"sigla": "P" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "3" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Revoga integralmente por consolida\u00e7\u00e3o", |
|||
"descricao_passiva": "Revogado(a) integralmente por consolida\u00e7\u00e3o", |
|||
"sigla": "T" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "4" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Norma correlata", |
|||
"descricao_passiva": "Norma correlata", |
|||
"sigla": "C" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "5" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Ressalva o(a)", |
|||
"descricao_passiva": "Ressalvada pelo(a)", |
|||
"sigla": "S" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "6" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Reedita o(a)", |
|||
"descricao_passiva": "Reeditada pelo(a)", |
|||
"sigla": "E" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "7" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Reedita com altera\u00e7\u00e3o o(a)", |
|||
"descricao_passiva": "Reeditada com altera\u00e7\u00e3o pelo(a)", |
|||
"sigla": "I" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "8" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Regulamenta o(a)", |
|||
"descricao_passiva": "Regulamentada pelo(a)", |
|||
"sigla": "G" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "9" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Suspende parcialmente o(a)", |
|||
"descricao_passiva": "Suspenso(a) parcialmente pelo(a)", |
|||
"sigla": "K" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "10" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Suspende integralmente o(a)", |
|||
"descricao_passiva": "Suspenso(a) integralmente pelo(a)", |
|||
"sigla": "L" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "11" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Julga integralmente inconstitucional", |
|||
"descricao_passiva": "Julgada integralmente inconstitucional", |
|||
"sigla": "N" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "12" |
|||
}, |
|||
{ |
|||
"fields": { |
|||
"descricao_ativa": "Julga parcialmente inconstitucional", |
|||
"descricao_passiva": "Julgada parcialmente inconstitucional", |
|||
"sigla": "O" |
|||
}, |
|||
"model": "norma.TipoVinculoNormaJuridica", |
|||
"pk": "13" |
|||
} |
|||
] |
|||
@ -0,0 +1,39 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from __future__ import unicode_literals |
|||
|
|||
import os |
|||
|
|||
from django.core.management import call_command |
|||
from django.db import migrations |
|||
|
|||
|
|||
def gera_tipo_vinculo(apps, schema_editor): |
|||
TipoVinculoNormaJuridica = apps.get_model("norma", "TipoVinculoNormaJuridica") |
|||
|
|||
db_alias = schema_editor.connection.alias |
|||
tipo_vinculos = TipoVinculoNormaJuridica.objects.all().exists() |
|||
|
|||
if tipo_vinculos: |
|||
# Caso haja algum TipoVinculoNormaJuridica cadastrado na base de dados, |
|||
# a migração não deve ser carregada para evitar duplicações de dados. |
|||
print("Carga de {} não efetuada. Já Existem {} cadastrados...".format( |
|||
TipoVinculoNormaJuridica._meta.verbose_name, |
|||
TipoVinculoNormaJuridica._meta.verbose_name_plural |
|||
) |
|||
) |
|||
else: |
|||
fixture_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../fixtures')) |
|||
# pega tipo_vinculo_norma_juridica listados em fixtures/pre_popula_tipo_vinculo_norma.json |
|||
fixture_filename = 'pre_popula_tipo_vinculo_norma.json' |
|||
fixture_file = os.path.join(fixture_dir, fixture_filename) |
|||
call_command('loaddata', fixture_file) |
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('norma', '0007_auto_20170904_1708'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.RunPython(gera_tipo_vinculo), |
|||
] |
|||
@ -0,0 +1,26 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.11 on 2017-11-13 15:39 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
import django.db.models.deletion |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('norma', '0008_normajuridica_popula_tipo_vinculo_norma'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='legislacaocitada', |
|||
name='materia', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='legislacaocitada', |
|||
name='norma', |
|||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='norma.NormaJuridica'), |
|||
), |
|||
] |
|||
@ -0,0 +1,27 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.13 on 2017-09-05 16:17 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('parlamentares', '0008_adiciona_cargos_mesa'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='situacaomilitar', |
|||
options={'ordering': ['descricao'], 'verbose_name': 'Tipo Situação Militar', 'verbose_name_plural': 'Tipos Situações Militares'}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='tipoafastamento', |
|||
options={'ordering': ['descricao'], 'verbose_name': 'Tipo de Afastamento', 'verbose_name_plural': 'Tipos de Afastamento'}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='tipodependente', |
|||
options={'ordering': ['descricao'], 'verbose_name': 'Tipo de Dependente', 'verbose_name_plural': 'Tipos de Dependente'}, |
|||
), |
|||
] |
|||
@ -0,0 +1,36 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from __future__ import unicode_literals |
|||
|
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
def altera_data_inicio_mandato(apps, schema_editor): |
|||
Mandato = apps.get_model("parlamentares", "Mandato") |
|||
mandatos = Mandato.objects.all() |
|||
|
|||
for mandato in mandatos: |
|||
data_inicio = mandato.data_inicio_mandato |
|||
data_inicio_legislatura = mandato.legislatura.data_inicio |
|||
|
|||
days = abs((data_inicio - data_inicio_legislatura |
|||
).days) if data_inicio else 60 |
|||
|
|||
if days >= 60: |
|||
mandato.data_inicio_mandato = data_inicio_legislatura |
|||
mandato.save() |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
# A dependencia real desse script é o arquivo 0001_initial.py, mas |
|||
# isso gera um erro (Conflicting migrations detected; multiple leaf |
|||
# nodes in the migration graph). para não ocasionar problemas de migração, |
|||
# vamos manter a ordem padrão do django. |
|||
('parlamentares', '0009_auto_20170905_1617'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.RunPython(altera_data_inicio_mandato), |
|||
] |
|||
@ -0,0 +1,20 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.3 on 2017-10-10 17:33 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('parlamentares', '0010_corrige_data_inicio_mandato'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='mandato', |
|||
name='data_inicio_mandato', |
|||
field=models.DateField(null=True, verbose_name='Início do Mandato'), |
|||
), |
|||
] |
|||
@ -0,0 +1,25 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.11 on 2017-10-20 12:45 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('parlamentares', '0011_auto_20171010_1433'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='dependente', |
|||
name='nome', |
|||
field=models.CharField(max_length=150, verbose_name='Nome'), |
|||
), |
|||
migrations.AlterField( |
|||
model_name='tipodependente', |
|||
name='descricao', |
|||
field=models.CharField(max_length=150, verbose_name='Descrição'), |
|||
), |
|||
] |
|||
@ -0,0 +1,19 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.3 on 2017-09-20 21:52 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('protocoloadm', '0001_initial'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.RemoveField( |
|||
model_name='documentoadministrativo', |
|||
name='numero_protocolo', |
|||
), |
|||
] |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue