Browse Source

Merge branch 'master' into 1012-bug-mesa-diretora

pull/1022/head
Edward 9 years ago
committed by GitHub
parent
commit
8a58e991b6
  1. 4
      .gitignore
  2. 4
      .travis.yml
  3. 99
      Dockerfile
  4. 0
      bug.txt
  5. 10
      busy-wait.sh
  6. 8
      config/env-sample
  7. 8
      config/env_dockerfile
  8. 31
      config/nginx/nginx.conf
  9. 39
      config/nginx/sapl.conf
  10. 33
      create_admin.py
  11. 19
      docker-compose.yml
  12. 6
      docker-env.sh
  13. 1
      envfile
  14. 7
      genkey.py
  15. 15
      gunicorn_start.sh
  16. 2
      requirements/requirements.txt
  17. 2
      sapl/.env_test
  18. 51
      sapl/base/migrations/0002_auto_20170331_1900.py
  19. 33
      sapl/base/models.py
  20. 8
      sapl/env-backup
  21. 12
      sapl/legacy/management/commands/recria_constraints.py
  22. 28
      sapl/legacy/migracao_documentos.py
  23. 177
      sapl/legacy/migration.py
  24. 4
      sapl/legacy/scripts/fix_tables.sql
  25. 6
      sapl/legacy/scripts/migra_um_db.sh
  26. 32
      sapl/materia/migrations/0004_auto_20170504_1751.py
  27. 33
      sapl/materia/models.py
  28. 22
      sapl/materia/signals.py
  29. 8
      sapl/norma/legacy.yaml
  30. 22
      sapl/norma/signals.py
  31. 25
      sapl/parlamentares/migrations/0002_auto_20170504_1751.py
  32. 5
      sapl/parlamentares/models.py
  33. 43
      sapl/parlamentares/views.py
  34. 43
      sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
  35. 70
      sapl/relatorios/views.py
  36. 2
      sapl/rules/map_rules.py
  37. 13
      sapl/rules/tests/test_rules.py
  38. 22
      sapl/sessao/forms.py
  39. 90
      sapl/sessao/views.py
  40. 8
      sapl/static/styles/style_tinymce.css
  41. 2
      sapl/templates/base/RelatorioPresencaSessao_filter.html
  42. 11
      sapl/templates/materia/materialegislativa_filter.html
  43. 2
      sapl/templates/parlamentares/parlamentar_perfil_publico.html
  44. 2
      sapl/templates/parlamentares/public_composicaomesa_form.html
  45. 1
      sapl/templates/protocoloadm/protocolo_mostrar.html
  46. 4
      sapl/templates/sessao/presenca.html
  47. 4
      sapl/templates/sessao/presenca_ordemdia.html
  48. 28
      sapl/templates/sessao/resumo.html
  49. 10
      sapl/templates/sessao/votacao/votacao_edit.html
  50. 20
      sapl/utils.py
  51. 3
      scripts_docker/shell_sapl.sh
  52. 69
      start.sh

4
.gitignore

@ -92,4 +92,6 @@ collected_static
bower
bower_components
media
whoosh/
whoosh/
postgres-data/
data/

4
.travis.yml

@ -20,3 +20,7 @@ script:
- ./manage.py bower install
- py.test --create-db
# - ./test_and_check_qa.sh
addons:
hosts:
- 127.0.0.1 sapldb

99
Dockerfile

@ -1,53 +1,46 @@
FROM ubuntu:15.04
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
RUN mkdir /sapl
RUN echo "deb http://archive.ubuntu.com/ubuntu/ vivid universe" | tee -a "/etc/apt/sources.list"
RUN \
apt-get update && \
apt-get install -y -f \
software-properties-common \
libpq-dev \
graphviz-dev \
graphviz \
build-essential \
git \
pkg-config \
python3-dev \
libxml2-dev \
libjpeg-dev \
libssl-dev \
libffi-dev \
libxslt1-dev \
python3-setuptools \
curl
# use python3 in pip
RUN easy_install3 pip lxml
# install nodejs
RUN DEBIAN_FRONTEND=noninteractive curl -sL https://deb.nodesource.com/setup_5.x | bash -
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y nodejs
# install bower
RUN npm install -g bower
# Bower aceitar root
RUN touch /root/.bowerrc
RUN chmod 751 /root/.bowerrc
RUN echo "{ \"allow_root\": true }" >> /root/.bowerrc
WORKDIR /sapl
ADD . /sapl
RUN pip install -r requirements/dev-requirements.txt
RUN pip install --upgrade setuptools
# RUN python3 manage.py bower install
FROM alpine:3.5
ENV BUILD_PACKAGES postgresql-dev graphviz-dev graphviz build-base git pkgconfig \
python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev nodejs py3-lxml \
py3-magic postgresql-client vim
RUN apk add --no-cache python3 nginx && \
python3 -m ensurepip && \
rm -r /usr/lib/python*/ensurepip && \
pip3 install --upgrade pip setuptools && \
rm -r /root/.cache && \
rm -f /etc/nginx/conf.d/*
RUN mkdir -p /var/interlegis/sapl && \
apk add --update --no-cache $BUILD_PACKAGES && \
npm install -g bower && \
npm cache clean
WORKDIR /var/interlegis/sapl/
ADD . /var/interlegis/sapl/
COPY start.sh /var/interlegis/sapl/
COPY config/nginx/sapl.conf /etc/nginx/conf.d
COPY config/nginx/nginx.conf /etc/nginx/nginx.conf
RUN pip install -r /var/interlegis/sapl/requirements/requirements.txt --upgrade setuptools && \
rm -r /root/.cache && \
rm -r /tmp/*
COPY config/env_dockerfile /var/interlegis/sapl/sapl/.env
# manage.py bower install bug: https://github.com/nvbn/django-bower/issues/51
RUN python3 manage.py bower_install -- --allow-root --no-input && \
python3 manage.py collectstatic --no-input && \
rm -rf /var/interlegis/sapl/sapl/.env && \
rm -rf /var/interlegis/sapl/sapl.db
RUN chmod +x /var/interlegis/sapl/start.sh && \
ln -sf /dev/stdout /var/log/nginx/access.log && \
ln -sf /dev/stderr /var/log/nginx/error.log
VOLUME ["/var/interlegis/sapl/data", "/var/interlegis/sapl/media"]
CMD ["/var/interlegis/sapl/start.sh"]

0
bug.txt

10
busy-wait.sh

@ -0,0 +1,10 @@
#!/bin/sh
while true; do
COUNT_PG=`psql $1 -c '\l \q' | grep sapl | wc -l`
if ! [ "$COUNT_PG" -eq "0" ]; then
break
fi
echo "Esperando Database Setup"
sleep 10
done

8
config/env-sample

@ -0,0 +1,8 @@
DATABASE_URL = postgresql://postgres:@sapldb:/sapl
KEY
DEBUG = False
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST = ''
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''

8
config/env_dockerfile

@ -0,0 +1,8 @@
DATABASE_URL = sqlite:///sapl.db
SECRET_KEY = 'Dockerfile_Key'
DEBUG = False
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST = ''
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''

31
config/nginx/nginx.conf

@ -0,0 +1,31 @@
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile off;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

39
config/nginx/sapl.conf

@ -0,0 +1,39 @@
upstream sapl_server {
server unix:/var/interlegis/sapl/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name sapl.test;
client_max_body_size 4G;
location /static/ {
alias /var/interlegis/sapl/collected_static/;
}
location /media/ {
alias /var/interlegis/sapl/media/;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://sapl_server;
break;
}
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/interlegis/sapl/sapl/static/;
}
}

33
create_admin.py

@ -0,0 +1,33 @@
import sys
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sapl.settings")
django.setup()
from django.contrib.auth.models import User
def create_superuser():
username = "admin"
password = os.environ['ADMIN_PASSWORD'] if 'ADMIN_PASSWORD' in os.environ else None
email = os.environ['ADMIN_EMAIL'] if 'ADMIN_EMAIL' in os.environ else ''
if User.objects.filter(username=username).exists():
print("[SUPERUSER] User %s already exists. Exiting without change." % username)
sys.exit('ADMIN_USER_EXISTS')
else:
if not password:
print("[SUPERUSER] Environment variable $ADMIN_PASSWORD for user %s was not set. Leaving..." % username)
sys.exit('MISSING_ADMIN_PASSWORD')
print("[SUPERUSER] Creating superuser...")
u = User.objects.create_superuser(username=username, password=password, email=email)
u.save()
print("[SUPERUSER] Done.")
sys.exit(0)
if __name__ == '__main__':
create_superuser()

19
docker-compose.yml

@ -1,17 +1,20 @@
localhost:
sapldb:
image: postgres
environment:
POSTGRES_PASSWORD: sapl
POSTGRES_USER: sapl
POSTGRES_DB: sapl
PGDATA : /var/lib/postgresql/data/
volumes:
- sapldb_data:/var/lib/postgresql/data/
ports:
- "5532:5432"
web:
build: .
command: /bin/sh -c "/bin/sh busy-wait.sh && python3 manage.py bower install && python3 manage.py migrate && /bin/sh gunicorn_start.sh /sapl"
sapl:
image: interlegis/sapl:latest
volumes:
- .:/sapl
ports:
- "8000:8000"
- sapl_data:/var/interlegis/sapl/data
- sapl_media:/var/interlegis/sapl/media
links:
- localhost
- sapldb
ports:
- "80:80"

6
docker-env.sh

@ -0,0 +1,6 @@
#/bin/bash
KEY=`python gen-key.py`
echo $KEY
sed -e "s/SECRET_KEY = None/SECRET_KEY = $KEY/g" config/env-sample

1
envfile

@ -0,0 +1 @@
EMAIL_HOST_USER=foo

7
genkey.py

@ -0,0 +1,7 @@
import random
def generate_secret():
return ''.join([random.SystemRandom().choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])
if __name__ == '__main__':
print(generate_secret())

15
gunicorn_start.sh

@ -12,7 +12,7 @@ then
fi
NAME="SAPL" # Name of the application (*)
DJANGODIR=/var/interlegis/sapl # Django project directory (*)
DJANGODIR=/var/interlegis/sapl/ # Django project directory (*)
SOCKFILE=/var/interlegis/sapl/run/gunicorn.sock # we will communicate using this unix socket (*)
USER=`whoami` # the user to run as (*)
GROUP=`whoami` # the group to run as (*)
@ -23,11 +23,14 @@ DJANGO_WSGI_MODULE=sapl.wsgi # WSGI module name (*)
echo "Starting $NAME as `whoami` on base dir $SAPL_DIR"
# Activate the virtual environment
cd $DJANGODIR
source /var/interlegis/.virtualenvs/sapl/bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH
# parameter can be passed to run without virtualenv
if [[ "$@" != "no-venv" ]]; then
# Activate the virtual environment
cd $DJANGODIR
source /var/interlegis/.virtualenvs/sapl/bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH
fi
# Create the run directory if it doesn't exist
RUNDIR=$(dirname $SOCKFILE)

2
requirements/requirements.txt

@ -15,7 +15,7 @@ django-extra-views==0.8.0
django-filter==0.15.3
django-floppyforms==1.6.2
django-model-utils==2.5
django-sass-processor==0.4.6
django-sass-processor==0.5.3
djangorestframework
drfdocs
easy-thumbnails==2.3

2
sapl/.env_test

@ -1,4 +1,4 @@
DATABASE_URL = postgresql://postgres:@localhost:/sapl
DATABASE_URL = postgresql://postgres:@sapldb:/sapl
SECRET_KEY=TravisTest
DEBUG=False
EMAIL_USE_TLS = True

51
sapl/base/migrations/0002_auto_20170331_1900.py

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-03-31 19:00
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('base', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Argumento',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('argumento', models.CharField(max_length=50, verbose_name='Argumento')),
],
options={
'verbose_name': 'Argumento da constraint',
'verbose_name_plural': 'Argumentos da constraint',
},
),
migrations.CreateModel(
name='Constraint',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nome_tabela', models.CharField(max_length=50, verbose_name='Nome da tabela')),
('nome_constraint', models.CharField(max_length=100, verbose_name='Nome da constraint')),
('nome_model', models.CharField(max_length=50, verbose_name='Nome da model')),
('tipo_constraint', models.CharField(max_length=50, verbose_name='Tipo da constraint')),
],
options={
'verbose_name': 'Constraint removida',
'verbose_name_plural': 'Constraints removidas',
},
),
migrations.AddField(
model_name='problemamigracao',
name='eh_importante',
field=models.BooleanField(default=False, verbose_name='É importante?'),
),
migrations.AddField(
model_name='argumento',
name='constraint',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='base.Constraint'),
),
]

33
sapl/base/models.py

@ -61,16 +61,45 @@ class ProblemaMigracao(models.Model):
content_object = GenericForeignKey('content_type', 'object_id')
nome_campo = models.CharField(max_length=100,
blank=True,
verbose_name='Nome do(s) Campo(s)')
verbose_name=_('Nome do(s) Campo(s)'))
problema = models.CharField(max_length=300, verbose_name=_('Problema'))
descricao = models.CharField(max_length=300, verbose_name=_('Descrição'))
eh_stub = models.BooleanField(verbose_name='É stub?')
eh_stub = models.BooleanField(verbose_name=_('É stub?'))
eh_importante = models.BooleanField(
default=False, verbose_name=_('É importante?'))
class Meta:
verbose_name = _('Problema na Migração')
verbose_name_plural = _('Problemas na Migração')
@reversion.register()
class Constraint(models.Model):
nome_tabela = models.CharField(
max_length=50, verbose_name=_('Nome da tabela'))
nome_constraint = models.CharField(
max_length=100, verbose_name=_('Nome da constraint'))
nome_model = models.CharField(
max_length=50, verbose_name=_('Nome da model'))
tipo_constraint = models.CharField(
max_length=50, verbose_name=_('Tipo da constraint'))
class Meta:
verbose_name = _('Constraint removida')
verbose_name_plural = _('Constraints removidas')
@reversion.register()
class Argumento(models.Model):
constraint = models.ForeignKey(Constraint)
argumento = models.CharField(
max_length=50, verbose_name=_('Argumento'))
class Meta:
verbose_name = _('Argumento da constraint')
verbose_name_plural = _('Argumentos da constraint')
@reversion.register()
class AppConfig(models.Model):

8
sapl/env-backup

@ -0,0 +1,8 @@
SECRET_KEY=qbl0+_+h6^u_k0ggkv&+ff&56s!d(*k+vk^_eu3-to_w&k-kp@
DATABASE_URL = postgresql://sapl:sapl@localhost:5432/sapl
DEBUG = True
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST = ''
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''

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

@ -0,0 +1,12 @@
from django.core.management.base import BaseCommand
from sapl.legacy.migration import recria_constraints
class Command(BaseCommand):
help = (u'Recria constraints do PostgreSQL excluidas durante '
'migração de dados')
def handle(self, *args, **options):
recria_constraints()

28
sapl/legacy/migracao_documentos.py

@ -4,6 +4,7 @@ import re
import magic
from django.db.models.signals import post_delete, post_save
from sapl.base.models import CasaLegislativa
from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa,
Proposicao)
@ -12,6 +13,8 @@ from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import DocumentoAdministrativo
from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MEDIA_ROOT
from sapl.utils import delete_texto, save_texto
# MIGRAÇÃO DE DOCUMENTOS ###################################################
EXTENSOES = {
@ -160,7 +163,29 @@ def migrar_docs_por_ids(tipo):
tipo.__name__, id, destino))
def desconecta_sinais_indexacao():
post_save.disconnect(save_texto, NormaJuridica)
post_save.disconnect(save_texto, DocumentoAcessorio)
post_save.disconnect(save_texto, MateriaLegislativa)
post_delete.disconnect(delete_texto, NormaJuridica)
post_delete.disconnect(delete_texto, DocumentoAcessorio)
post_delete.disconnect(delete_texto, MateriaLegislativa)
def conecta_sinais_indexacao():
post_save.connect(save_texto, NormaJuridica)
post_save.connect(save_texto, DocumentoAcessorio)
post_save.connect(save_texto, MateriaLegislativa)
post_delete.connect(delete_texto, NormaJuridica)
post_delete.connect(delete_texto, DocumentoAcessorio)
post_delete.connect(delete_texto, MateriaLegislativa)
def migrar_documentos():
# precisamos excluir os sinais de post_save e post_delete para não que o
# computador não trave com a criação de threads desnecessárias
desconecta_sinais_indexacao()
# aqui supomos que uma pasta chamada sapl_documentos está em MEDIA_ROOT
# com o conteúdo da pasta de mesmo nome do zope
# Os arquivos da pasta serão movidos para a nova estrutura e a pasta será
@ -186,3 +211,6 @@ def migrar_documentos():
len(sobrando)))
for doc in sobrando:
print(' {}'. format(doc))
#
# reconexão dos sinais desligados no inicio da migração de documentos
conecta_sinais_indexacao()

177
sapl/legacy/migration.py

@ -13,22 +13,24 @@ from django.core.exceptions import ObjectDoesNotExist
from django.db import OperationalError, ProgrammingError, connections, models
from django.db.models import CharField, Max, ProtectedError, TextField
from django.db.models.base import ModelBase
from django.db.models.signals import post_delete, post_save
from model_mommy import mommy
from model_mommy.mommy import foreign_key_required, make
from sapl.base.models import Autor, ProblemaMigracao
from sapl.base.models import Argumento, Autor, Constraint, ProblemaMigracao
from sapl.comissoes.models import Comissao, Composicao, Participacao
from sapl.legacy.models import Protocolo as ProtocoloLegado
from sapl.materia.models import (StatusTramitacao, TipoDocumento,
from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa,
StatusTramitacao, TipoDocumento,
TipoMateriaLegislativa, TipoProposicao,
Tramitacao)
from sapl.norma.models import (AssuntoNorma, NormaJuridica,
TipoVinculoNormaJuridica)
TipoVinculoNormaJuridica, NormaRelacionada)
from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import Protocolo, StatusTramitacaoAdministrativo
from sapl.sessao.models import ExpedienteMateria, OrdemDia
from sapl.settings import PROJECT_DIR
from sapl.utils import normalize
from sapl.utils import delete_texto, normalize, save_texto
# BASE ######################################################################
# apps to be migrated, in app dependency order (very important)
@ -109,6 +111,10 @@ def warn(msg):
print('CUIDADO! ' + msg)
def erro(msg):
print('ERRO: ' + msg)
def get_fk_related(field, value, label=None):
if value is None and field.null is False:
value = 0
@ -124,9 +130,7 @@ def get_fk_related(field, value, label=None):
if not field.null:
fields_dict = get_fields_dict(field.related_model)
# Cria stub ao final da tabela para evitar erros
pk = 1
if hasattr(field.related_model.objects.last(), 'pk'):
pk = field.related_model.objects.last().pk
pk = get_last_value(field.related_model)
with reversion.create_revision():
reversion.set_comment('Stub criado pela migração')
value = mommy.make(
@ -197,6 +201,12 @@ def iter_sql_records(sql, db):
record.__dict__.update(zip(fieldnames, row))
yield record
# Todos os models têm no máximo uma constraint unique together
# Isso é necessário para que o método delete_constraints funcione corretamente
assert all(len(model._meta.unique_together) <= 1
for app in appconfs
for model in app.models.values())
def delete_constraints(model):
# pega nome da unique constraint dado o nome da tabela
@ -210,40 +220,66 @@ def delete_constraints(model):
for r in result:
if r[0].endswith('key'):
words_list = r[0].split('_')
one_to_one_constraints.append([table, r[0], words_list, model])
constraint = Constraint.objects.create(
nome_tabela=table, nome_constraint=r[0],
nome_model=model.__name__, tipo_constraint='one_to_one')
for w in words_list:
Argumento.objects.create(constraint=constraint, argumento=w)
else:
args = None
args_list = []
if model._meta.unique_together:
args = model._meta.unique_together[0]
args_list = list(args)
unique_constraints.append([table, r[0], args_list, model])
args_list = model._meta.unique_together[0]
constraint = Constraint.objects.create(
nome_tabela=table, nome_constraint=r[0],
nome_model=model.__name__,
tipo_constraint='unique_together')
for a in args_list:
Argumento.objects.create(constraint=constraint,
argumento=a)
warn('Excluindo unique constraint de nome %s' % r[0])
exec_sql("ALTER TABLE %s DROP CONSTRAINT %s;" %
(table, r[0]))
def recreate_constraints():
if one_to_one_constraints:
for constraint in one_to_one_constraints:
table, name, args, model = constraint
def recria_constraints():
constraints = Constraint.objects.all()
for con in constraints:
if con.tipo_constraint == 'one_to_one':
nome_tabela = con.nome_tabela
nome_constraint = con.nome_constraint
args = [a.argumento for a in con.argumento_set.all()]
args_string = ''
args_string = "(" + "_".join(map(str, args[2:-1])) + ")"
exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" %
(table, name, args_string))
if unique_constraints:
for constraint in unique_constraints:
table, name, args, model = constraint
try:
exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" %
(nome_tabela, nome_constraint, args_string))
except ProgrammingError:
info('A constraint %s já foi recriada!' % nome_constraint)
if con.tipo_constraint == 'unique_together':
nome_tabela = con.nome_tabela
nome_constraint = con.nome_constraint
# Pegando explicitamente o primeiro valor do filter,
# pois pode ser que haja mais de uma ocorrência
model = ContentType.objects.filter(
model=con.nome_model.lower())[0].model_class()
args = [a.argumento for a in con.argumento_set.all()]
for i in range(len(args)):
if isinstance(model._meta.get_field(args[i]),
models.ForeignKey):
args[i] = args[i] + '_id'
args_string = ''
args_string += "(" + ', '.join(map(str, args)) + ")"
exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" %
(table, name, args_string))
one_to_one_constraints.clear()
unique_constraints.clear()
try:
exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" %
(nome_tabela, nome_constraint, args_string))
except ProgrammingError:
info('A constraint %s já foi recriada!' % nome_constraint)
except Exception as err:
problema = re.findall('\(.*?\)', err.args[0])
erro('A constraint [%s] da tabela [%s] não pode ser recriada' %
(nome_constraint, nome_tabela))
erro('Os dados %s = %s estão duplicados. '
'Arrume antes de recriar as constraints!' %
(problema[0], problema[1]))
def obj_desnecessario(obj):
@ -262,8 +298,8 @@ def get_last_value(model):
def alter_sequence(model, id):
sequence_name = '%s_id_seq' % model._meta.db_table
exec_sql('ALTER SEQUENCE %s RESTART WITH %s MINVALUE %s;' % (
sequence_name, id, id))
exec_sql('ALTER SEQUENCE %s RESTART WITH %s MINVALUE -1;' % (
sequence_name, id))
def save_with_id(new, id):
@ -278,8 +314,7 @@ def save_relation(obj, nome_campo='', problema='', descricao='',
eh_stub=False):
link = ProblemaMigracao(
content_object=obj, nome_campo=nome_campo, problema=problema,
descricao=descricao, eh_stub=eh_stub,
)
descricao=descricao, eh_stub=eh_stub,)
link.save()
@ -302,20 +337,34 @@ def get_fields_dict(model):
def fill_vinculo_norma_juridica():
lista = [('A', 'Altera a norma'),
('R', 'Revoga integralmente a norma'),
('P', 'Revoga parcialmente a norma'),
('T', 'Revoga integralmente por consolidação'),
('C', 'Norma Correlata'),
('S', 'Ressalva a Norma'),
('E', 'Reedita a Norma'),
('I', 'Reedita a Norma com Alteração'),
('G', 'Regulamenta a Norma'),
('K', 'Suspende parcialmente a norma'),
('L', 'Suspende integralmente a norma'),
('N', 'Julgada integralmente inconstitucional'),
('O', 'Julgada parcialmente inconstitucional')]
lista_objs = [TipoVinculoNormaJuridica(sigla=item[0], descricao=item[1])
lista = [('A', 'Altera o(a)',
'Alterado(a) pelo(a)'),
('R', 'Revoga integralmente o(a)',
'Revogado(a) integralmente pelo(a)'),
('P', 'Revoga parcialmente o(a)',
'Revogado(a) parcialmente pelo(a)'),
('T', 'Revoga integralmente por consolidação',
'Revogado(a) integralmente por consolidação'),
('C', 'Norma correlata',
'Norma correlata'),
('S', 'Ressalva o(a)',
'Ressalvada pelo(a)'),
('E', 'Reedita o(a)',
'Reeditada pelo(a)'),
('I', 'Reedita com alteração o(a)',
'Reeditada com alteração pelo(a)'),
('G', 'Regulamenta o(a)',
'Regulamentada pelo(a)'),
('K', 'Suspende parcialmente o(a)',
'Suspenso(a) parcialmente pelo(a)'),
('L', 'Suspende integralmente o(a)',
'Suspenso(a) integralmente pelo(a)'),
('N', 'Julga integralmente inconstitucional',
'Julgada integralmente inconstitucional'),
('O', 'Julga parcialmente inconstitucional',
'Julgada parcialmente inconstitucional')]
lista_objs = [TipoVinculoNormaJuridica(
sigla=item[0], descricao_ativa=item[1], descricao_passiva=item[2])
for item in lista]
TipoVinculoNormaJuridica.objects.bulk_create(lista_objs)
@ -416,6 +465,9 @@ class DataMigrator:
call([PROJECT_DIR.child('manage.py'), 'flush',
'--database=default', '--no-input'], stdout=PIPE)
desconecta_sinais_indexacao()
fill_vinculo_norma_juridica()
info('Começando migração: %s...' % obj)
self._do_migrate(obj)
@ -427,7 +479,7 @@ class DataMigrator:
for obj in self.to_delete:
msg = 'A entrada de PK %s da model %s não pode ser ' \
'excluida' % (obj.pk, obj._meta.model_name)
descricao = 'Um ou mais objetos protegidos '
descricao = 'Um ou mais objetos protegidos'
warn(msg + ' => ' + descricao)
save_relation(obj=obj, problema=msg,
descricao=descricao, eh_stub=False)
@ -435,8 +487,8 @@ class DataMigrator:
info('Deletando stubs desnecessários...')
while self.delete_stubs():
pass
info('Recriando unique constraints...')
# recreate_constraints()
conecta_sinais_indexacao()
def _do_migrate(self, obj):
if isinstance(obj, AppConfig):
@ -504,6 +556,10 @@ class DataMigrator:
if getattr(old, 'ind_excluido', False):
self.to_delete.append(new)
# necessário para ajustar sequence da tabela para o ultimo valor de id
ultimo_valor = get_last_value(model)
alter_sequence(model, ultimo_valor+1)
def delete_ind_excluido(self):
excluidos = 0
for obj in self.to_delete:
@ -580,6 +636,12 @@ def adjust_participacao(new, old):
new.composicao = composicao
def adjust_normarelacionada(new, old):
tipo = TipoVinculoNormaJuridica.objects.filter(sigla=old.tip_vinculo)
assert len(tipo) == 1
new.tipo_vinculo = tipo[0]
def adjust_protocolo(new, old):
if new.numero is None and not primeira_vez:
p = ProtocoloLegado.objects.filter(
@ -685,6 +747,7 @@ AJUSTE_ANTES_SALVAR = {
Autor: adjust_autor,
Comissao: adjust_comissao,
NormaJuridica: adjust_normajuridica_antes_salvar,
NormaRelacionada: adjust_normarelacionada,
OrdemDia: adjust_ordemdia,
Parlamentar: adjust_parlamentar,
Participacao: adjust_participacao,
@ -731,3 +794,23 @@ def make_with_log(model, _quantity=None, make_m2m=False, **attrs):
return stub
make_with_log.required = foreign_key_required
# DISCONNECT SIGNAL ########################################################
def desconecta_sinais_indexacao():
post_save.disconnect(save_texto, NormaJuridica)
post_save.disconnect(save_texto, DocumentoAcessorio)
post_save.disconnect(save_texto, MateriaLegislativa)
post_delete.disconnect(delete_texto, NormaJuridica)
post_delete.disconnect(delete_texto, DocumentoAcessorio)
post_delete.disconnect(delete_texto, MateriaLegislativa)
def conecta_sinais_indexacao():
post_save.connect(save_texto, NormaJuridica)
post_save.connect(save_texto, DocumentoAcessorio)
post_save.connect(save_texto, MateriaLegislativa)
post_delete.connect(delete_texto, NormaJuridica)
post_delete.connect(delete_texto, DocumentoAcessorio)
post_delete.connect(delete_texto, MateriaLegislativa)

4
sapl/legacy/scripts/fix_tables.sql

@ -2,15 +2,19 @@
SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES,','');
-- 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;
-- 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 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;
-- 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;

6
sapl/legacy/scripts/migra_um_db.sh

@ -23,3 +23,9 @@ 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

32
sapl/materia/migrations/0004_auto_20170504_1751.py

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.11 on 2017-05-04 17:51
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('materia', '0003_auto_20170403_1505'),
]
operations = [
migrations.AlterField(
model_name='assuntomateria',
name='dispositivo',
field=models.CharField(blank=True, default='', max_length=200, verbose_name='Descrição do Dispositivo Legal'),
preserve_default=False,
),
migrations.AlterField(
model_name='materiaassunto',
name='assunto',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='materia.AssuntoMateria', verbose_name='Assunto'),
),
migrations.AlterField(
model_name='materiaassunto',
name='materia',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='materia.MateriaLegislativa', verbose_name='Matéria'),
),
]

33
sapl/materia/models.py

@ -4,6 +4,7 @@ import reversion
from django.contrib.auth.models import Group
from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.utils import formats
from django.utils.translation import ugettext_lazy as _
@ -215,6 +216,22 @@ class MateriaLegislativa(models.Model):
return _('%(tipo)s%(numero)s de %(ano)s') % {
'tipo': self.tipo, 'numero': self.numero, 'ano': self.ano}
def data_entrada_protocolo(self):
'''
hack: recuperar a data de entrada do protocolo sem gerar
dependência circular
'''
from sapl.protocoloadm.models import Protocolo
if self.ano and self.numero_protocolo:
try:
return Protocolo.objects.get(
ano=self.ano,
numero=self.numero_protocolo).data
except ObjectDoesNotExist:
pass
return ''
def delete(self, using=None, keep_parents=False):
if self.texto_original:
self.texto_original.delete()
@ -668,9 +685,19 @@ class Proposicao(models.Model):
)
def __str__(self):
return '%s %s/%s' % (Proposicao._meta.verbose_name,
self.numero_proposicao,
self.ano)
if self.ano and self.numero_proposicao:
return '%s %s/%s' % (Proposicao._meta.verbose_name,
self.numero_proposicao,
self.ano)
else:
if len(self.descricao) < 30:
descricao = self.descricao[:28] + ' ...'
else:
descricao = self.descricao
return '%s %s/%s' % (Proposicao._meta.verbose_name,
self.id,
descricao)
def delete(self, using=None, keep_parents=False):
if self.texto_original:

22
sapl/materia/signals.py

@ -1,29 +1,9 @@
from subprocess import PIPE, call
from threading import Thread
from django.db.models.signals import post_delete, post_save
from sapl.settings import PROJECT_DIR
from sapl.utils import save_texto, delete_texto
from .models import DocumentoAcessorio, MateriaLegislativa
class UpdateIndexCommand(Thread):
def run(self):
call([PROJECT_DIR.child('manage.py'), 'update_index'],
stdout=PIPE)
def save_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
def delete_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
post_save.connect(save_texto, sender=MateriaLegislativa)
post_save.connect(save_texto, sender=DocumentoAcessorio)
post_delete.connect(delete_texto, sender=MateriaLegislativa)

8
sapl/norma/legacy.yaml

@ -42,8 +42,6 @@ LegislacaoCitada:
subsecao: des_subsecao
titulo: des_titulo
# TODO Descomentar quando a issue #832 for concluida
# TipoVinculoNormaJuridica (VinculoNormaJuridica):
# norma_referente: cod_norma_referente
# norma_referida: cod_norma_referida
# tipo_vinculo: tip_vinculo
NormaRelacionada (VinculoNormaJuridica):
norma_principal: cod_norma_referente
norma_relacionada: cod_norma_referida

22
sapl/norma/signals.py

@ -1,28 +1,8 @@
from subprocess import PIPE, call
from threading import Thread
from django.db.models.signals import post_delete, post_save
from sapl.settings import PROJECT_DIR
from sapl.utils import save_texto, delete_texto
from .models import NormaJuridica
class UpdateIndexCommand(Thread):
def run(self):
call([PROJECT_DIR.child('manage.py'), 'update_index'],
stdout=PIPE)
def save_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
def delete_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
post_save.connect(save_texto, sender=NormaJuridica)
post_delete.connect(delete_texto, sender=NormaJuridica)

25
sapl/parlamentares/migrations/0002_auto_20170504_1751.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.11 on 2017-05-04 17:51
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='coligacao',
name='numero_votos',
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Nº Votos Recebidos (Coligação)'),
),
migrations.AlterField(
model_name='mandato',
name='votos_recebidos',
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Votos Recebidos (Mandato)'),
),
]

5
sapl/parlamentares/models.py

@ -85,7 +85,8 @@ class Coligacao(models.Model):
verbose_name=_('Legislatura'))
nome = models.CharField(max_length=50, verbose_name=_('Nome'))
numero_votos = models.PositiveIntegerField(
blank=True, null=True, verbose_name=_('Nº Votos Recebidos'))
blank=True, null=True,
verbose_name=_('Nº Votos Recebidos (Coligação)'))
class Meta:
verbose_name = _('Coligação')
@ -448,7 +449,7 @@ class Mandato(models.Model):
tipo_causa_fim_mandato = models.PositiveIntegerField(blank=True, null=True)
data_fim_mandato = models.DateField(verbose_name=_('Fim do Mandato'))
votos_recebidos = models.PositiveIntegerField(
blank=True, null=True, verbose_name=_('Votos Recebidos'))
blank=True, null=True, verbose_name=_('Votos Recebidos (Mandato)'))
data_expedicao_diploma = models.DateField(
verbose_name=_('Expedição do Diploma'))
titular = models.BooleanField(

43
sapl/parlamentares/views.py

@ -1,7 +1,7 @@
from django.contrib import messages
from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.core.urlresolvers import reverse, reverse_lazy
from django.db.models import F
from django.db.models import F, Q
from django.http import JsonResponse
from django.http.response import HttpResponseRedirect
from django.utils.datastructures import MultiValueDictKeyError
@ -345,8 +345,47 @@ class ParlamentarCrud(Crud):
# Tira Link do avatar_html e coloca no nome
for row in context['rows']:
# Coloca a filiação atual ao invés da última
if row[0][1]:
# Pega o Parlamentar por meio da pk
parlamentar = Parlamentar.objects.get(
id=(row[0][1].split('/')[-1]))
# Pega a Legislatura
legislatura = Legislatura.objects.get(
id=context['legislatura_id'])
# As condições para mostrar a filiação são:
# A data de filiacao deve ser menor que a data de fim
# da legislatura e data de desfiliação deve nula, ou maior,
# ou igual a data de fim da legislatura
try:
filiacao = parlamentar.filiacao_set.get(Q(
data__lte=legislatura.data_fim,
data_desfiliacao__gte=legislatura.data_fim) | Q(
data__lte=legislatura.data_fim,
data_desfiliacao__isnull=True))
# Caso não exista filiação com essas condições
except ObjectDoesNotExist:
row[2] = ('Não possui filiação', None)
# Caso exista mais de uma filiação nesse intervalo
# Entretanto, NÃO DEVE OCORRER
except MultipleObjectsReturned:
filiacao = parlamentar.filiacao_set.filter(Q(
data__lte=legislatura.data_fim,
data_desfiliacao__gte=legislatura.data_fim) | Q(
data__lte=legislatura.data_fim,
data_desfiliacao__isnull=True)).last()
# Caso encontre UMA filiação nessas condições
else:
row[2] = (filiacao.partido.sigla, None)
row[1] = (row[1][0], row[0][1])
row[0] = (row[0][0], None)
return context

43
sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py

@ -101,7 +101,7 @@ def inf_basicas(inf_basicas_dic):
tmp += '\t\t<para style="P1">Informações Básicas</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Tipo da Sessão: </b> ' + \
nom_sessao + '</para>\n'
@ -120,7 +120,7 @@ def mesa(lst_mesa):
tmp = ''
tmp += '\t\t<para style="P1">Mesa Diretora</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for mesa in lst_mesa:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \
@ -136,7 +136,7 @@ def presenca(lst_presenca_sessao):
tmp = ''
tmp += '\t\t<para style="P1">Lista de Presença da Sessão</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for presenca in lst_presenca_sessao:
tmp += '\t\t<para style="P2" spaceAfter="5">' + \
@ -154,10 +154,10 @@ def expedientes(lst_expedientes):
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t</para>\n'
for expediente in lst_expedientes:
tmp += '\t\t<para style="P2"><b>' + \
for idx, expediente in enumerate(lst_expedientes):
tmp += '\t\t<para style="P2"><b>' + '<br/> ' + \
expediente['nom_expediente'] + ': </b></para>\n' + \
'<para style="P2">' + \
'<para style="P2">' + \
expediente['txt_expediente'] + '</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
@ -171,18 +171,22 @@ def expediente_materia(lst_expediente_materia):
tmp = ''
tmp += '\t\t<para style="P1">Matérias do Expediente</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n'
for expediente_materia in lst_expediente_materia:
tmp += '<tr><td><para style="P3"><b>' + str(expediente_materia['num_ordem']) + '</b> - ' + expediente_materia['id_materia'] + '</para>\n' + '<para style="P3"><b>Turno: </b>' + expediente_materia[
'des_turno'] + '</para>\n' + '<para style="P3"><b>Autor: </b>' + expediente_materia['nom_autor'] + '</para></td>\n'
tmp += '<tr><td><para style="P3"><b>' + str(expediente_materia['num_ordem']) + '</b> - ' + expediente_materia['id_materia'] + '</para>\n' + '<para style="P3"><b>Turno: </b>' + str(expediente_materia[
'des_turno']) + '</para>\n' + '<para style="P3"><b>Autor: </b>' + str(expediente_materia['nom_autor']) + '</para></td>\n'
txt_ementa = expediente_materia['txt_ementa'].replace('&', '&amp;')
tmp += '<td><para style="P4">' + txt_ementa + '</para></td>\n'
tmp += '<td><para style="P3"><b>' + \
str(expediente_materia['nom_resultado']) + '</b></para>\n' + '<para style="P3">' + \
'</para></td></tr>\n'
str(expediente_materia['nom_resultado']) + '</b></para>\n' + '<para style="P3">'
if expediente_materia['votacao_observacao'] != txt_ementa:
tmp += str(expediente_materia['votacao_observacao'])
else:
tmp += ' '
tmp += '</para></td></tr>\n'
tmp += '\t\t</blockTable>\n'
return tmp
@ -195,7 +199,7 @@ def oradores_expediente(lst_oradores_expediente):
tmp = ''
tmp += '\t\t<para style="P1">Oradores do Expediente</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for orador_expediente in lst_oradores_expediente:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + str(orador_expediente['num_ordem']) + '</b> - ' + orador_expediente[
@ -210,7 +214,7 @@ def presenca_ordem_dia(lst_presenca_ordem_dia):
tmp = ''
tmp += '\t\t<para style="P1">Lista de Presença da Ordem do Dia</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for presenca_ordem_dia in lst_presenca_ordem_dia:
tmp += '\t\t<para style="P2" spaceAfter="5">' + \
@ -226,7 +230,7 @@ def votacao(lst_votacao):
tmp = ''
tmp += '<para style="P1">Matérias da Ordem do Dia</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n'
@ -236,8 +240,12 @@ def votacao(lst_votacao):
txt_ementa = votacao['txt_ementa'].replace('&', '&amp;')
tmp += '<td><para style="P4">' + txt_ementa + '</para></td>\n'
tmp += '<td><para style="P3"><b>' + \
str(votacao['nom_resultado']) + '</b></para>\n' + '<para style="P3">' + \
'</para></td></tr>\n'
str(votacao['nom_resultado']) + '</b></para>\n' + '<para style="P3">'
if votacao['votacao_observacao'] != txt_ementa:
tmp += str(votacao['votacao_observacao'])
else:
tmp += ' '
tmp += '</para></td></tr>\n'
tmp += '\t\t</blockTable>\n'
return tmp
@ -250,7 +258,7 @@ def oradores(lst_oradores):
tmp = ''
tmp += '\t\t<para style="P1">Oradores das Explicações Pessoais</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for orador in lst_oradores:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \
@ -290,6 +298,7 @@ def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_me
tmp += oradores(lst_oradores)
tmp += '\t</story>\n'
tmp += '</document>\n'
tmp_pdf = parseString(tmp)
return tmp_pdf
# if hasattr(context.temp_folder,arquivoPdf):

70
sapl/relatorios/views.py

@ -1,5 +1,8 @@
from datetime import datetime
import re
import html
from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404, HttpResponse
from django.utils.translation import ugettext_lazy as _
@ -518,14 +521,28 @@ def get_sessao_plenaria(sessao, casa):
# Exibe os Expedientes
lst_expedientes = []
for tip_expediente in TipoExpediente.objects.all():
for expediente in ExpedienteSessao.objects.filter(
sessao_plenaria=sessao, tipo=tip_expediente):
dic_expedientes = {}
dic_expedientes["nom_expediente"] = str(tip_expediente)
dic_expedientes["txt_expediente"] = (expediente.conteudo)
if dic_expedientes:
lst_expedientes.append(dic_expedientes)
expedientes = ExpedienteSessao.objects.filter(
sessao_plenaria=sessao).order_by('tipo__nome')
for e in expedientes:
dic_expedientes = {}
dic_expedientes["nom_expediente"] = e.tipo.nome
conteudo = e.conteudo
# unescape HTML codes
# https://github.com/interlegis/sapl/issues/1046
conteudo = re.sub('style=".*?"', '', conteudo)
conteudo = html.unescape(conteudo)
# escape special character '&'
# https://github.com/interlegis/sapl/issues/1009
conteudo = conteudo.replace('&', '&amp;')
dic_expedientes["txt_expediente"] = conteudo
if dic_expedientes:
lst_expedientes.append(dic_expedientes)
# Lista das matérias do Expediente, incluindo o resultado das votacoes
lst_expediente_materia = []
@ -594,18 +611,16 @@ def get_sessao_plenaria(sessao, casa):
dic_expediente_materia["nom_autor"] = 'Desconhecido'
dic_expediente_materia["votacao_observacao"] = ' '
if not expediente_materia.resultado:
resultado = RegistroVotacao.objects.filter(
tipo_resultado_votacao=expediente_materia.tipo_votacao)
for i in resultado:
resultados = expediente_materia.registrovotacao_set.all()
if resultados:
for i in resultados:
dic_expediente_materia["nom_resultado"] = (
i.tipo_resultado_votacao.nome)
dic_expediente_materia["votacao_observacao"] = (
expediente_materia.observacao)
i.observacao)
else:
dic_expediente_materia["nom_resultado"] = _("Matéria não votada")
dic_expediente_materia["votacao_observacao"] = _("Vazio")
dic_expediente_materia["votacao_observacao"] = _(" ")
lst_expediente_materia.append(dic_expediente_materia)
# Lista dos oradores do Expediente
@ -664,9 +679,9 @@ def get_sessao_plenaria(sessao, casa):
materia=votacao.materia).first()
if numeracao is not None:
dic_votacao["des_numeracao"] = (
str(numeracao.numero) +
str(numeracao.numero_materia) +
'/' +
str(numeracao.ano))
str(numeracao.ano_materia))
dic_votacao["des_turno"] = ' '
tramitacao = Tramitacao.objects.filter(
@ -710,16 +725,15 @@ def get_sessao_plenaria(sessao, casa):
dic_votacao["nom_autor"] = 'Desconhecido'
dic_votacao["votacao_observacao"] = ' '
if not votacao.resultado:
resultado = RegistroVotacao.objects.filter(
tipo_resultado_votacao=votacao.tipo_votacao)
for i in resultado:
resultados = votacao.registrovotacao_set.all()
if resultados:
for i in resultados:
dic_votacao["nom_resultado"] = i.tipo_resultado_votacao.nome
if votacao.observacao:
dic_votacao["votacao_observacao"] = votacao.observacao
dic_votacao["votacao_observacao"] = i.observacao
else:
dic_votacao["nom_resultado"] = _("Matéria não votada")
dic_votacao["votacao_observacao"] = _("Vazio")
dic_votacao["votacao_observacao"] = _(" ")
lst_votacao.append(dic_votacao)
# Lista dos oradores nas Explicações Pessoais
@ -1086,11 +1100,11 @@ def get_pauta_sessao(sessao, casa):
dic_votacao["ordem_observacao"] = votacao.observacao
dic_votacao["des_numeracao"] = ' '
numeracao = Numeracao.objects.filter(materia=materia)
# if numeracao is not None:
# numeracao = numeracao.first()
# dic_votacao["des_numeracao"] = str(
# numeracao.numero) + '/' + str(numeracao.ano)
# numeracao = Numeracao.objects.filter(materia=materia)
# if numeracao is not None:
# numeracao = numeracao.first()
# dic_votacao["des_numeracao"] = str(
# numeracao.numero_materia) + '/' + str(numeracao.ano_materia)
dic_votacao["nom_autor"] = ' '
autoria = Autoria.objects.filter(

2
sapl/rules/map_rules.py

@ -197,6 +197,8 @@ rules_group_geral = {
(base.CasaLegislativa, __listdetailchange__),
(base.ProblemaMigracao, []),
(base.Argumento, []),
(base.Constraint, []),
(base.TipoAutor, __base__),
(base.Autor, __base__),

13
sapl/rules/tests/test_rules.py

@ -6,7 +6,8 @@ from django.contrib.contenttypes.models import ContentType
from django.utils import six
from django.utils.translation import ugettext_lazy as _
from sapl.base.models import CasaLegislativa, ProblemaMigracao
from sapl.base.models import (CasaLegislativa, ProblemaMigracao, Argumento,
Constraint)
from sapl.compilacao.models import (PerfilEstruturalTextoArticulado,
TipoDispositivo,
TipoDispositivoRelationship)
@ -56,11 +57,15 @@ def test_models_in_rules_patterns(model_item):
__fp__in__test_permission_of_models_in_rules_patterns = {
map_rules.RP_ADD: [CasaLegislativa,
ProblemaMigracao,
Argumento,
Constraint,
TipoDispositivo,
TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado],
map_rules.RP_CHANGE: [ProblemaMigracao,
Argumento,
Constraint,
AcompanhamentoMateria,
TipoDispositivo,
TipoDispositivoRelationship,
@ -68,17 +73,23 @@ __fp__in__test_permission_of_models_in_rules_patterns = {
map_rules.RP_DELETE: [CasaLegislativa,
ProblemaMigracao,
Argumento,
Constraint,
TipoDispositivo,
TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado],
map_rules.RP_LIST: [ProblemaMigracao,
Argumento,
Constraint,
AcompanhamentoMateria,
TipoDispositivo,
TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado],
map_rules.RP_DETAIL: [ProblemaMigracao,
Argumento,
Constraint,
AcompanhamentoMateria,
TipoDispositivo,
TipoDispositivoRelationship,

22
sapl/sessao/forms.py

@ -83,11 +83,11 @@ class ExpedienteMateriaForm(ModelForm):
def clean_numero_ordem(self):
sessao = self.instance.sessao_plenaria
ex = ExpedienteMateria.objects.filter(
numero_ordem_exists = ExpedienteMateria.objects.filter(
sessao_plenaria=sessao,
numero_ordem=self.cleaned_data['numero_ordem']).count()
numero_ordem=self.cleaned_data['numero_ordem']).exists()
if ex >= 1:
if numero_ordem_exists:
msg = _('Esse número de ordem já existe.')
raise ValidationError(msg)
@ -139,6 +139,22 @@ class OrdemDiaForm(ExpedienteMateriaForm):
def clean_data_ordem(self):
return self.instance.sessao_plenaria.data_inicio
def clean_numero_ordem(self):
sessao = self.instance.sessao_plenaria
numero_ordem_exists = OrdemDia.objects.filter(
sessao_plenaria=sessao,
numero_ordem=self.cleaned_data[
'numero_ordem']).exists()
if numero_ordem_exists:
msg = _('Esse número de ordem já existe.')
raise ValidationError(msg)
return self.cleaned_data['numero_ordem']
def clean(self):
cleaned_data = self.cleaned_data
sessao = self.instance.sessao_plenaria

90
sapl/sessao/views.py

@ -28,7 +28,7 @@ from sapl.materia.models import (Autoria, DocumentoAcessorio,
TipoMateriaLegislativa, Tramitacao)
from sapl.materia.views import MateriaLegislativaPesquisaView
from sapl.norma.models import NormaJuridica
from sapl.parlamentares.models import (Legislatura, Parlamentar,
from sapl.parlamentares.models import (Filiacao, Legislatura, Parlamentar,
SessaoLegislativa)
from sapl.sessao.apps import AppConfig
from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm
@ -164,7 +164,10 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
def get_rows(self, object_list):
for obj in object_list:
if not obj.resultado:
exist_resultado = obj.registrovotacao_set.filter(
materia=obj.materia
).exists()
if not exist_resultado:
if obj.votacao_aberta:
url = ''
if obj.tipo_votacao == 1:
@ -208,6 +211,11 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
else:
obj.resultado = '''Não há resultado'''
else:
resultado = obj.registrovotacao_set.get(
materia_id=obj.materia_id)
resultado_descricao = resultado.tipo_resultado_votacao.nome
resultado_observacao = resultado.observacao
if self.request.user.has_module_perms(AppConfig.label):
url = ''
if obj.tipo_votacao == 1:
@ -228,10 +236,14 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
'pk': obj.sessao_plenaria_id,
'oid': obj.materia_id,
'mid': obj.pk})
obj.resultado = '<a href="%s">%s</a>' % (url,
obj.resultado)
obj.resultado = ('<a href="%s">%s</a><br/>%s' %
(url,
resultado_descricao,
resultado_observacao))
else:
obj.resultado = '%s' % (obj.resultado)
obj.resultado = ('%s<br/>%s' %
(resultado_descricao,
resultado_observacao))
return [self._as_row(obj) for obj in object_list]
@ -268,7 +280,10 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
def get_rows(self, object_list):
for obj in object_list:
if not obj.resultado:
exist_resultado = obj.registrovotacao_set.filter(
materia=obj.materia
).exists()
if not exist_resultado:
if obj.votacao_aberta:
url = ''
if obj.tipo_votacao == 1:
@ -310,7 +325,10 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
obj.resultado = btn_abrir
else:
url = ''
resultado = obj.registrovotacao_set.get(
materia_id=obj.materia_id)
resultado_descricao = resultado.tipo_resultado_votacao.nome
resultado_observacao = resultado.observacao
if self.request.user.has_module_perms(AppConfig.label):
if obj.tipo_votacao == 1:
url = reverse(
@ -331,8 +349,14 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
'pk': obj.sessao_plenaria_id,
'oid': obj.materia_id,
'mid': obj.pk})
obj.resultado = '<a href="%s">%s</a>' % (url,
obj.resultado)
obj.resultado = ('<a href="%s">%s</a><br/>%s' %
(url,
resultado_descricao,
resultado_observacao))
else:
obj.resultado = ('%s<br/>%s' %
(resultado_descricao,
resultado_observacao))
return [self._as_row(obj) for obj in object_list]
class CreateView(MasterDetailCrud.CreateView):
@ -982,12 +1006,14 @@ class ResumoView(DetailView):
materias_expediente = []
for m in materias:
ementa = m.observacao
titulo = m.materia
numero = m.numero_ordem
if m.resultado:
resultado = m.resultado
resultado = m.registrovotacao_set.all()
if resultado:
resultado = resultado[0].tipo_resultado_votacao.nome
else:
resultado = _('Matéria não votada')
@ -1039,7 +1065,6 @@ class ResumoView(DetailView):
# Matérias Ordem do Dia
ordem = OrdemDia.objects.filter(
sessao_plenaria_id=self.object.id)
materias_ordem = []
for o in ordem:
ementa = o.observacao
@ -1047,8 +1072,9 @@ class ResumoView(DetailView):
numero = o.numero_ordem
# Verificar resultado
if o.resultado:
resultado = o.resultado
resultado = o.registrovotacao_set.filter(materia=o.materia)
if resultado:
resultado = resultado[0].tipo_resultado_votacao.nome
else:
resultado = _('Matéria não votada')
@ -1066,6 +1092,24 @@ class ResumoView(DetailView):
context.update({'materias_ordem': materias_ordem})
# =====================================================================
# Oradores nas Explicações Pessoais
oradores_explicacoes = []
for orador in Orador.objects.filter(sessao_plenaria_id=self.object.id):
for parlamentar in Parlamentar.objects.filter(
id=orador.parlamentar.id):
partido_sigla = Filiacao.objects.filter(
parlamentar=parlamentar).last().partido.sigla
if not partido_sigla:
partido_sigla = ''
oradores = {
'numero_ordem': orador.numero_ordem,
'parlamentar': parlamentar,
'sgl_partido': partido_sigla
}
oradores_explicacoes.append(oradores)
context.update({'oradores_explicacoes': oradores_explicacoes})
return self.render_to_response(context)
@ -1196,6 +1240,7 @@ class VotacaoEditView(SessaoPermissionMixin):
ordem_id=ordem_id).last()
votacao_existente = {'observacao': sub(
'&nbsp;', ' ', strip_tags(votacao.observacao)),
'resultado': votacao.tipo_resultado_votacao.nome,
'tipo_resultado':
votacao.tipo_resultado_votacao_id}
context.update({'votacao_titulo': titulo,
@ -1506,6 +1551,7 @@ class VotacaoNominalEditView(SessaoPermissionMixin):
votacao_existente = {'observacao': sub(
'&nbsp;', ' ', strip_tags(votacao.observacao)),
'resultado': votacao.tipo_resultado_votacao.nome,
'tipo_resultado':
votacao.tipo_resultado_votacao_id}
context.update({'votacao': votacao_existente,
@ -1738,6 +1784,7 @@ class VotacaoNominalExpedienteEditView(SessaoPermissionMixin):
votacao_existente = {'observacao': sub(
'&nbsp;', ' ', strip_tags(votacao.observacao)),
'resultado': votacao.tipo_resultado_votacao.nome,
'tipo_resultado':
votacao.tipo_resultado_votacao_id}
context.update({'votacao': votacao_existente,
@ -1972,6 +2019,7 @@ class VotacaoExpedienteEditView(SessaoPermissionMixin):
expediente_id=expediente_id).last()
votacao_existente = {'observacao': sub(
'&nbsp;', ' ', strip_tags(votacao.observacao)),
'resultado': votacao.tipo_resultado_votacao.nome,
'tipo_resultado':
votacao.tipo_resultado_votacao_id}
context.update({'votacao_titulo': titulo,
@ -2065,9 +2113,9 @@ class PautaSessaoDetailView(DetailView):
situacao = m.materia.tramitacao_set.last().status
if situacao is None:
situacao = _("Não informada")
if m.resultado:
resultado = m.resultado
resultado = m.registrovotacao_set.all()
if resultado:
resultado = resultado[0].tipo_resultado_votacao.nome
else:
resultado = _('Matéria não votada')
@ -2118,8 +2166,9 @@ class PautaSessaoDetailView(DetailView):
numero = o.numero_ordem
# Verificar resultado
if o.resultado:
resultado = o.resultado
resultado = o.registrovotacao_set.all()
if resultado:
resultado = resultado[0].tipo_resultado_votacao.nome
else:
resultado = _('Matéria não votada')
@ -2413,12 +2462,13 @@ class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente):
@csrf_exempt
@permission_required('sessao.change_expedientemateria',
'sessao.change_ordemdia')
def mudar_ordem_materia_sessao(request):
# Pega os dados vindos da requisição
posicao_inicial = int(request.POST['pos_ini']) + 1
posicao_final = int(request.POST['pos_fim']) + 1
pk_sessao = int(request.POST['pk_sessao'])
pk_list = request.POST.getlist('pk_list[]')
materia = request.POST['materia']

8
sapl/static/styles/style_tinymce.css

@ -1,8 +0,0 @@
.mce-content-body {
font-family: "Open Sans" "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
font-style: normal;
font-weight: normal;
line-height: 1.5;
font-size: 1em;
color: #444444;
}

2
sapl/templates/base/RelatorioPresencaSessao_filter.html

@ -37,7 +37,7 @@
<tbody>
{% for p in parlamentares %}
<tr>
<td><b>{{p}}</b> / {{p.filiacao_set.first.partido.sigla|default:"Sem Partido"}}</td>
<td><b>{{p}}</b> / {{p.filiacao_atual|default:"Sem Partido"}}</td>
<td>{{p.sessao_count}}</td>
<td>{{p.sessao_porc}}</td>
<td>{{p.ordemdia_count}}</td>

11
sapl/templates/materia/materialegislativa_filter.html

@ -47,6 +47,14 @@
<strong>Apresentação: </strong>{{ m.data_apresentacao }}
</br>
{% endif %}
{% if m.numeracao_set.first %}
<strong>Processo: </strong>{{ m.numeracao_set.first.numero_materia }} / {{ m.numeracao_set.first.ano_materia }}
</br>
{% endif %}
{% if m.numero_protocolo %}
<strong>Protocolo: </strong>{{m.numero_protocolo}}/{{m.ano}} &nbsp;&nbsp; <strong>Data Entrada:</strong> {{m.data_entrada_protocolo}} </br>
{% endif %}
{% if m.autoria_set.all %}
<strong>Autores:</strong>
{% for a in m.autoria_set.all %}
@ -57,7 +65,7 @@
{% endif %}
{% endfor %}
</br>
{% endif %}
{% endif %}
{% if m.tramitacao_set.last.unidade_tramitacao_destino %}
<strong>Localização Atual:</strong> &nbsp;{{m.tramitacao_set.last.unidade_tramitacao_destino}}</br>
{% endif %}
@ -79,6 +87,7 @@
{% endif %}
{% if m.tramitacao_set.last.data_tramitacao %}
<strong>Data da última Tramitação:</strong> &nbsp;{{m.tramitacao_set.last.data_tramitacao}}</br>
<strong>Ultima Ação:</strong> &nbsp; {{m.tramitacao_set.last.texto}}</br>
{% endif %}
{% if m.anexo_de.exists %}
{% for a in m.materia_anexada_set.all %}

2
sapl/templates/parlamentares/parlamentar_perfil_publico.html

@ -31,7 +31,7 @@
<div class="col-sm-8">
<div id="div_data_nascimento" class="form-group">
<p><b>Partido: </b> &nbsp {{object.filiacao_set.first.partido|default_if_none:"Não informado"}}</p>
<p><b>Partido: </b> &nbsp {{object.filiacao_atual|default_if_none:"Não informado"}}</p>
</div>
</div>

2
sapl/templates/parlamentares/public_composicaomesa_form.html

@ -51,7 +51,7 @@
<td></td>
{% endif %}
<td><a href="{% url 'sapl.parlamentares:parlamentar_detail' p.parlamentar.pk %}">{{p.parlamentar.nome_parlamentar}}</a></td>
<td>{{p.parlamentar.filiacao_set.last.partido.sigla}}</td>
<td>{{p.parlamentar.filiacao_atual}}</td>
<td>{{p.cargo}}</td>
</tr>
{% endfor %}

1
sapl/templates/protocoloadm/protocolo_mostrar.html

@ -6,6 +6,7 @@
<strong>Protocolo: </strong>{{ protocolo.numero|stringformat:'06d' }}/{{ protocolo.ano }}</br>
<strong>Assunto: </strong> {{ protocolo.assunto_ementa|default:" Não informado." }}</br>
<strong>Data Protocolo: </strong> {{ protocolo.data|date:"d/m/Y" }} - Horário: {{ protocolo.hora|date:"H:i" }}</br>
<strong>Autor:</strong> {{protocolo.autor.nome}} </br>
<strong>Interessado: </strong> {{ protocolo.interessado|default:" Não informado." }}</br>
<!-- TODO: convert if-else to custom tag -->
<strong>Natureza do Processo: </strong>{% if protocolo.tipo_processo == 0 %} Administrativo {% elif protocolo.tipo_processo == 1 %} Legislativo {% endif %}</br>

4
sapl/templates/sessao/presenca.html

@ -23,7 +23,7 @@
<div class="checkbox">
<label for="id_presenca_{{forloop.counter}}">
<input type="checkbox" id="id_presenca_{{forloop.counter}}" name="presenca" value="{{ parlamentar.id }}" {% if check %} checked {% endif %}/>
{{ parlamentar }}
{{ parlamentar.nome_parlamentar }} / {{ parlamentar.filiacao_atual }}
</label>
</div>
{% endfor %}
@ -42,7 +42,7 @@
{% for parlamentar, check in view.get_presencas %}
{% if check %}
<div class="row">
<div class="col-md-6"><label for="parlamentar"> - {{ parlamentar }}</label></div>
<div class="col-md-6"><label for="parlamentar"> - {{ parlamentar.nome_parlamentar }} / {{ parlamentar.filiacao_atual }}</label></div>
</div>
{% endif %}
{% endfor %}

4
sapl/templates/sessao/presenca_ordemdia.html

@ -24,7 +24,7 @@
<div class="checkbox">
<label for="id_presenca_{{forloop.counter}}">
<input type="checkbox" id="id_presenca_{{forloop.counter}}" name="presenca" value="{{ parlamentar.id }}" {% if check %} checked {% endif %}/>
{{ parlamentar }}
{{ parlamentar.nome_parlamentar }} / {{ parlamentar.filiacao_atual }}
</label>
</div>
{% endfor %}
@ -44,7 +44,7 @@
{% for parlamentar, check in view.get_presencas_ordem %}
{% if check %}
<div class="row">
<div class="col-md-6"><label for="parlamentar"> - {{ parlamentar }}</label></div>
<div class="col-md-6"><label for="parlamentar"> - {{ parlamentar.nome_parlamentar }} / {{ parlamentar.filiacao_atual }}</label></div>
</div>
{% endif %}
{% endfor %}

28
sapl/templates/sessao/resumo.html

@ -42,7 +42,8 @@
<legend>Mesa Diretora</legend>
<div class="row">
{% for m in mesa %}
<div class="col-md-12"><b>{{m.cargo}}: </b>{{m.parlamentar.nome_parlamentar}}</div>
<div class="col-md-12"><b>{{m.cargo}}:
</b>{{m.parlamentar.nome_parlamentar}} / {{ m.parlamentar.filiacao_atual }}</div>
{% endfor %}
</div>
</fieldset>
@ -52,7 +53,7 @@
<legend>Lista de Presença na Sessão</legend>
<div class="row">
{% for p in presenca_sessao %}
<div class="col-md-12">{{p}}</div>
<div class="col-md-12">{{p.nome_parlamentar}} / {{ p.filiacao_atual }}</div>
{% endfor %}
</div>
</fieldset>
@ -112,8 +113,9 @@
</div>
<div class="row">
{% for o in oradores %}
<div class="col-md-6"><b>{{o.numero_ordem}}</b> - {{o.parlamentar}}</div>
<div class="col-md-6">{{o.url_discurso}}</div>
<div class="col-md-6"><b>{{o.numero_ordem}}</b> - {{o.parlamentar}}</div>
<div class="col-md-6">{{o.url_discurso}}</div>
</br>
{% endfor %}
</div>
</fieldset>
@ -123,7 +125,7 @@
<legend>Lista de Presença na Ordem do Dia</legend>
<div class="row">
{% for p in presenca_ordem %}
<div class="col-md-12">{{p}}</div>
<div class="col-md-12">{{p.nome_parlamentar}} / {{ p.filiacao_atual }}</div>
{% endfor %}
</div>
</fieldset>
@ -154,4 +156,20 @@
</tbody>
</table>
</fieldset>
<fieldset>
<legend>Oradores das Explicações Pessoais</legend>
<div class="row">
<div class="col-md-6">Parlamentar</div>
<div class="col-md-6">Discurso</div>
</div>
<div class="row">
{% for o in oradores_explicacoes %}
<div class="col-md-6"><b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_parlamentar}} / {{ o.parlamentar.filiacao_atual }}</div>
<div class="col-md-6">{{o.url_discurso}}</div>
</br>
{% endfor %}
</div>
</fieldset>
{% endblock detail_content %}

10
sapl/templates/sessao/votacao/votacao_edit.html

@ -26,12 +26,10 @@
<div class="row">
<div class="col-md-12">
Resultado da Votação:
{% for tipo in view.get_tipos_votacao %}
{% if votacao.tipo_resultado == tipo.id %}
<b>{{ tipo.nome }}</b>
{% endif %}
{% endfor %}
<br/>
Resultado da Votação: <strong>{{ votacao.resultado }}</strong>
<br/>
<br/>
</div>
</div>

20
sapl/utils.py

@ -5,6 +5,8 @@ import re
from datetime import date
from functools import wraps
from unicodedata import normalize as unicodedata_normalize
from subprocess import PIPE, call
from threading import Thread
import django_filters
import magic
@ -22,7 +24,7 @@ from floppyforms import ClearableFileInput
from reversion.admin import VersionAdmin
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
from sapl.settings import BASE_DIR
from sapl.settings import BASE_DIR, PROJECT_DIR
sapl_logger = logging.getLogger(BASE_DIR.name)
@ -632,3 +634,19 @@ def texto_upload_path(instance, filename, subpath=''):
}
return path
class UpdateIndexCommand(Thread):
def run(self):
call([PROJECT_DIR.child('manage.py'), 'update_index'],
stdout=PIPE)
def save_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
def delete_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()

3
scripts_docker/shell_sapl.sh

@ -1,2 +1,3 @@
#!/bin/bash
docker run -ti sapl_web /bin/bash
docker run --rm -ti sapl_web /bin/sh

69
start.sh

@ -0,0 +1,69 @@
#!/bin/sh
create_env() {
echo "[ENV FILE] creating .env file..."
# check if file exists
if [ -f "/var/interlegis/sapl/data/secret.key" ]; then
KEY=`cat /var/interlegis/sapl/data/secret.key`
else
KEY=`python3 genkey.py`
echo $KEY > data/secret.key
fi
FILENAME="/var/interlegis/sapl/sapl/.env"
if [ -z "${DATABASE_URL:-}" ]; then
DATABASE_URL="postgresql://sapl:sapl@sapldb:5432/sapl"
fi
# ALWAYS replace the content of .env variable
# If want to conditionally create only if absent then use IF below
# if [ ! -f $FILENAME ]; then
touch $FILENAME
# explicitly use '>' to erase any previous content
echo "SECRET_KEY="$KEY > $FILENAME
# now only appends
echo "DATABASE_URL = "$DATABASE_URL >> $FILENAME
echo "DEBUG = ""${DEBUG-False}" >> $FILENAME
echo "EMAIL_USE_TLS = ""${USE_TLS-True}" >> $FILENAME
echo "EMAIL_PORT = ""${EMAIL_PORT-587}" >> $FILENAME
echo "EMAIL_HOST = ""${EMAIL_HOST-''}" >> $FILENAME
echo "EMAIL_HOST_USER = ""${EMAIL_HOST_USER-''}" >> $FILENAME
echo "EMAIL_HOST_PASSWORD = ""${EMAIL_HOST_PASSWORD-''}" >> $FILENAME
echo "[ENV FILE] done."
}
create_env
#python3 manage.py bower install
/bin/sh busy-wait.sh $DATABASE_URL
python3 manage.py migrate
#python3 manage.py collectstatic --no-input
python3 manage.py rebuild_index --noinput &
user_created=$(python3 create_admin.py 2>&1)
cmd=$(echo $user_created | grep 'ADMIN_USER_EXISTS')
user_exists=$?
cmd=$(echo $user_created | grep 'MISSING_ADMIN_PASSWORD')
lack_pwd=$?
if [ $user_exists -eq 0 ]; then
echo "[SUPERUSER CREATION] User admin already exists. Not creating"
fi
if [ $lack_pwd -eq 0 ]; then
echo "[SUPERUSER] Environment variable $ADMIN_PASSWORD for superuser admin was not set. Leaving container"
# return -1
fi
/bin/sh gunicorn_start.sh no-venv &
/usr/sbin/nginx -g "daemon off;"
Loading…
Cancel
Save