Browse Source

Faz o merge com o branch do GitHub

pull/271/head
Eduardo Calil 9 years ago
parent
commit
04f497def2
  1. 12
      README.rst
  2. 5
      base/forms.py
  3. 21
      compilacao/migrations/0045_auto_20160404_1411.py
  4. 3
      compilacao/models.py
  5. 11
      materia/forms.py
  6. 27
      materia/migrations/0027_auto_20160404_1409.py
  7. 9
      materia/models.py
  8. 1
      materia/test_materia_urls.py
  9. 11
      materia/views.py
  10. 11
      parlamentares/forms.py
  11. 22
      parlamentares/migrations/0016_auto_20160404_1409.py
  12. 5
      parlamentares/models.py
  13. 7
      parlamentares/test_parlamentares.py
  14. 6
      parlamentares/views.py
  15. 4
      requirements/requirements.txt
  16. 29
      sapl/settings.py
  17. 18
      sapl/test_general.py
  18. 61
      sapl/utils.py
  19. 27
      sessao/migrations/0016_auto_20160404_1409.py
  20. 8
      sessao/models.py
  21. 14
      templates/materia/proposicao/proposicao_list.html
  22. 2
      templates/sessao/sessao_list.html

12
README.rst

@ -56,6 +56,18 @@ Development Environment Installation
* Either run ``./manage.py migrate`` (for an empty database) or restore a database dump.
* In ``sapl/sapl`` directory create one file called ``.env``. Write the following attributes in it:
- DATABASE_URL = postgresql://USER:PASSWORD@HOST:PORT/NAME
- SECRET_KEY = Generate some key and paste here
- DEBUG = [True/False]
- EMAIL_USE_TLS = [True/False]
- EMAIL_PORT = [Set this parameter]
- EMAIL_HOST = [Set this parameter]
- EMAIL_HOST_USER = [Set this parameter]
- EMAIL_HOST_PASSWORD = [Set this parameter]
`Generate your secret key here <https://docs.djangoproject.com/es/1.9/ref/settings/#std:setting-SECRET_KEY>`_
Instructions for Translators
============================

5
base/forms.py

@ -88,8 +88,9 @@ class CasaLegislativaTabelaAuxForm(ModelForm):
row3,
row4,
row5,
HTML("""<div class="col-md-12">
{% if form.logotipo.value %}
HTML("""
<div class="col-md-12">
{% if not form.fotografia.errors and form.fotografia.value %}
<img class="img-responsive" width="225" height="300"
src="{{ MEDIA_URL }}{{ form.logotipo.value }}">
<br />

21
compilacao/migrations/0045_auto_20160404_1411.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-04-04 17:11
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0044_auto_20160307_0918'),
]
operations = [
migrations.AlterField(
model_name='textoarticulado',
name='observacao',
field=models.TextField(blank=True, default='', verbose_name='Observação'),
preserve_default=False,
),
]

3
compilacao/models.py

@ -90,8 +90,7 @@ PARTICIPACAO_SOCIAL_CHOICES = [
class TextoArticulado(TimestampedMixin):
data = models.DateField(blank=True, null=True, verbose_name=_('Data'))
ementa = models.TextField(verbose_name=_('Ementa'))
observacao = models.TextField(
blank=True, null=True, verbose_name=_('Observação'))
observacao = models.TextField(blank=True, verbose_name=_('Observação'))
numero = models.PositiveIntegerField(verbose_name=_('Número'))
ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'))
tipo_ta = models.ForeignKey(

11
materia/forms.py

@ -70,6 +70,17 @@ class ProposicaoForm(ModelForm):
self.helper.layout = Layout(
Fieldset(_('Incluir Proposição'),
row1, row2, row3, row4,
HTML("""
<div class="img-responsive" width="225" height="300"
src="{{ MEDIA_URL }}{{ form.texto_original.value }}">
<br /><br />
<input type="submit"
name="remover-texto"
id="remover-texto"
class="btn btn-warning"
value="Remover Texto"/>
<p></p>
""", ),
form_actions(more=more))
)
super(ProposicaoForm, self).__init__(

27
materia/migrations/0027_auto_20160404_1409.py

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-04-04 17:09
from __future__ import unicode_literals
from django.db import migrations, models
import materia.models
import sapl.utils
class Migration(migrations.Migration):
dependencies = [
('materia', '0026_auto_20160322_1514'),
]
operations = [
migrations.AlterField(
model_name='materialegislativa',
name='texto_original',
field=models.FileField(blank=True, null=True, upload_to=materia.models.texto_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Texto Original (PDF)'),
),
migrations.AlterField(
model_name='proposicao',
name='texto_original',
field=models.FileField(blank=True, null=True, upload_to=materia.models.texto_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Texto Original (PDF)'),
),
]

9
materia/models.py

@ -4,7 +4,8 @@ from model_utils import Choices
from comissoes.models import Comissao
from parlamentares.models import Parlamentar, Partido
from sapl.utils import RANGE_ANOS, YES_NO_CHOICES, xstr
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
restringe_tipos_de_arquivo_txt, xstr)
class TipoMateriaLegislativa(models.Model):
@ -122,7 +123,8 @@ class MateriaLegislativa(models.Model):
blank=True,
null=True,
upload_to=texto_upload_path,
verbose_name=_('Texto Original (PDF)'))
verbose_name=_('Texto Original (PDF)'),
validators=[restringe_tipos_de_arquivo_txt])
class Meta:
verbose_name = _('Matéria Legislativa')
@ -457,7 +459,8 @@ class Proposicao(models.Model):
blank=True,
null=True,
upload_to=texto_upload_path,
verbose_name=_('Texto Original (PDF)'))
verbose_name=_('Texto Original (PDF)'),
validators=[restringe_tipos_de_arquivo_txt])
class Meta:
verbose_name = _('Proposição')

1
materia/test_materia_urls.py

@ -1,5 +1,6 @@
import pytest
from django.core.urlresolvers import reverse
import pytest
@pytest.mark.parametrize("test_input,kwargs,expected", [

11
materia/views.py

@ -1,3 +1,4 @@
import os
from datetime import datetime
from random import choice
from string import ascii_letters, digits
@ -1362,8 +1363,10 @@ class ProposicaoEditView(CreateView):
proposicao.save()
else:
proposicao.delete()
elif 'salvar' in request.POST:
if 'salvar' or "remover-foto" in request.POST:
if 'texto_original' in request.FILES:
# if os.unlink(proposicao.texto_original.path):
# proposicao.texto_original = None
proposicao.texto_original = request.FILES['texto_original']
tipo = TipoProposicao.objects.get(id=form.data['tipo'])
proposicao.tipo = tipo
@ -1383,6 +1386,12 @@ class ProposicaoEditView(CreateView):
proposicao.materia = materia
if not proposicao.data_envio:
proposicao.data_envio = datetime.now()
if "remover-texto" in request.POST:
try:
os.unlink(proposicao.texto_original.path)
except OSError:
pass # Should log this error!!!!!
proposicao.texto_original = None
proposicao.save()
return redirect(self.get_success_url())
else:

11
parlamentares/forms.py

@ -131,17 +131,18 @@ class ParlamentaresForm (ModelForm):
row6, row7, row8, row9, row10,
row11, row12, row13,
HTML("""<div class="col-md-12">
{% if not form.fotografia.errors %}
{% if form.fotografia.value %}
<img class="img-responsive"
width="225" height="300"
<img class="img-responsive" width="225" height="300"
src="{{ MEDIA_URL }}{{ form.fotografia.value }}">
<br />
<br /><br />
<input type="submit"
name="remover"
id="remover"
name="remover-foto"
id="remover-foto"
class="btn btn-warning"
value="Remover Foto"/>
{% endif %}
{% endif %}
</div>""", ),
row14,
form_actions())

22
parlamentares/migrations/0016_auto_20160404_1409.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-04-04 17:09
from __future__ import unicode_literals
from django.db import migrations, models
import parlamentares.models
import sapl.utils
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0015_auto_20160322_1401'),
]
operations = [
migrations.AlterField(
model_name='parlamentar',
name='fotografia',
field=models.ImageField(blank=True, null=True, upload_to=parlamentares.models.foto_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_img], verbose_name='Fotografia'),
),
]

5
parlamentares/models.py

@ -4,7 +4,7 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
from sapl.utils import UF, YES_NO_CHOICES
from sapl.utils import UF, YES_NO_CHOICES, restringe_tipos_de_arquivo_img
class Legislatura(models.Model):
@ -244,7 +244,8 @@ class Parlamentar(models.Model):
blank=True,
null=True,
upload_to=foto_upload_path,
verbose_name=_('Fotografia'))
verbose_name=_('Fotografia'),
validators=[restringe_tipos_de_arquivo_img])
class Meta:
verbose_name = _('Parlamentar')

7
parlamentares/test_parlamentares.py

@ -6,8 +6,9 @@ from .models import (Dependente, Filiacao, Legislatura, Mandato, Parlamentar,
Partido, TipoDependente)
# vamos refazer a funcionalidade adicionando os campos ogrigatórios de mandato
@pytest.mark.django_db(transaction=False)
def test_cadastro_parlamentar(client):
def TODO_DESLIGADO_RELIGAR_test_cadastro_parlamentar(client):
mommy.make(Legislatura, pk=5)
response = client.get(reverse('parlamentares:parlamentares_cadastro',
@ -19,8 +20,8 @@ def test_cadastro_parlamentar(client):
{'nome_completo': 'Teresa Barbosa',
'nome_parlamentar': 'Terezinha',
'sexo': 'F',
'ativo': 'True',
})
'ativo': 'True'}, follow=True)
parlamentar = Parlamentar.objects.first()
assert "Terezinha" == parlamentar.nome_parlamentar
if not parlamentar.ativo:

6
parlamentares/views.py

@ -186,10 +186,6 @@ class ParlamentaresCadastroView(CreateView):
def form_valid(self, form):
form.save()
mandato = Mandato()
mandato.parlamentar = form.instance
mandato.legislatura = Legislatura.objects.get(id=self.kwargs['pk'])
mandato.save()
return redirect(self.get_success_url())
@ -206,7 +202,7 @@ class ParlamentaresEditarView(UpdateView):
elif 'excluir' in self.request.POST:
Mandato.objects.get(parlamentar=parlamentar).delete()
parlamentar.delete()
elif "remover" in self.request.POST:
elif "remover-foto" in self.request.POST:
try:
os.unlink(parlamentar.fotografia.path)
except OSError:

4
requirements/requirements.txt

@ -1,10 +1,11 @@
dj-database-url
django-admin-bootstrapped==2.5.7
django-bootstrap3==7.0.0
django-bower==5.1.0
django-braces==1.8.1
django-compressor==2.0
django-crispy-forms==1.6.0
python-decouple==3.0
django-extra-views==0.7.1
django-model-utils==2.4
django-sass-processor==0.3.4
@ -17,3 +18,4 @@ pytz==2015.7
pyyaml==3.11
rtyaml==0.0.2
unipath==1.1
python-magic==0.4.10

29
sapl/settings.py

@ -9,6 +9,8 @@ https://docs.djangoproject.com/en/1.8/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""
from decouple import config
from dj_database_url import parse as db_url
from unipath import Path
from .temp_suppress_crispy_form_warnings import \
@ -16,14 +18,15 @@ from .temp_suppress_crispy_form_warnings import \
BASE_DIR = Path(__file__).ancestor(2)
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '!9g1-#la+#(oft(v-y1qhy$jk-2$24pdk69#b_jfqyv!*%a_)t'
SECRET_KEY = config('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = ['*']
@ -105,21 +108,17 @@ WSGI_APPLICATION = 'sapl.wsgi.application'
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'sapl',
'USER': 'sapl',
'PASSWORD': 'sapl',
'HOST': 'localhost',
'PORT': '5432',
}
'default': config(
'DATABASE_URL',
cast=db_url,
)
}
EMAIL_USE_TLS = True
EMAIL_HOST = ''
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_PORT = 587
EMAIL_USE_TLS = config('EMAIL_USE_TLS', cast=bool)
EMAIL_HOST = config('EMAIL_HOST', cast=str)
EMAIL_HOST_USER = config('EMAIL_HOST_USER', cast=str)
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', cast=str)
EMAIL_PORT = config('EMAIL_PORT', cast=int)
MAX_DOC_UPLOAD_SIZE = 5*1024*1024 # 5MB
MAX_IMAGE_UPLOAD_SIZE = 2*1024*1024 # 2MB

18
sapl/test_general.py

@ -1,16 +1,32 @@
import pytest
from django.apps import apps
from django.db.models import CharField, TextField
from model_mommy import mommy
from .settings import SAPL_APPS
pytestmark = pytest.mark.django_db
sapl_appconfs = [apps.get_app_config(n) for n in SAPL_APPS]
def test_charfiled_textfield():
for app in sapl_appconfs:
for model in app.get_models():
fields = model._meta.local_fields
for field in fields:
if isinstance(field, (CharField, TextField)):
msg = 'Model = %s || Field = %s - %s - %s' % (
model.__name__,
field.attname,
type(field).__name__,
field.null)
assert not field.null, msg
def test_str_sanity():
# this simply a sanity check
# __str__ semantics is not considered and should be tested separetely
sapl_appconfs = [apps.get_app_config(n) for n in SAPL_APPS]
for app in sapl_appconfs:
for model in app.get_models():
obj = mommy.prepare(model)

61
sapl/utils.py

@ -1,8 +1,10 @@
from datetime import date
from functools import wraps
import magic
from django.apps import apps
from django.contrib import admin
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
@ -123,3 +125,62 @@ UF = [
]
RANGE_ANOS = [(year, year) for year in range(date.today().year, 1889, -1)]
TIPOS_TEXTO_PERMITIDOS = (
'application/vnd.oasis.opendocument.text',
'application/x-vnd.oasis.opendocument.text',
'application/pdf',
'application/x-pdf',
'application/acrobat',
'applications/vnd.pdf',
'text/pdf',
'text/x-pdf',
'text/plain',
'application/txt',
'browser/internal',
'text/anytext',
'widetext/plain',
'widetext/paragraph',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/xml',
'text/xml',
'text/html',
)
TIPOS_IMG_PERMITIDOS = (
'image/jpeg',
'image/jpg',
'image/jpe_',
'image/pjpeg',
'image/vnd.swiftview-jpeg',
'application/jpg',
'application/x-jpg',
'image/pjpeg',
'image/pipeg',
'image/vnd.swiftview-jpeg',
'image/x-xbitmap',
'image/bmp',
'image/x-bmp',
'image/x-bitmap',
'image/png',
'application/png',
'application/x-png',
)
def fabrica_validador_de_tipos_de_arquivo(lista, nome):
def restringe_tipos_de_arquivo(value):
mime = magic.from_buffer(value.read(), mime=True)
mime = mime.decode()
if mime not in lista:
raise ValidationError(_('Tipo de arquivo não suportado'))
# o nome é importante para as migrations
restringe_tipos_de_arquivo.__name__ = nome
return restringe_tipos_de_arquivo
restringe_tipos_de_arquivo_txt = fabrica_validador_de_tipos_de_arquivo(
TIPOS_TEXTO_PERMITIDOS, 'restringe_tipos_de_arquivo_txt')
restringe_tipos_de_arquivo_img = fabrica_validador_de_tipos_de_arquivo(
TIPOS_IMG_PERMITIDOS, 'restringe_tipos_de_arquivo_img')

27
sessao/migrations/0016_auto_20160404_1409.py

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-04-04 17:09
from __future__ import unicode_literals
from django.db import migrations, models
import sapl.utils
import sessao.models
class Migration(migrations.Migration):
dependencies = [
('sessao', '0015_auto_20160307_0918'),
]
operations = [
migrations.AlterField(
model_name='sessaoplenaria',
name='upload_ata',
field=models.FileField(blank=True, null=True, upload_to=sessao.models.ata_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Ata da Sessão'),
),
migrations.AlterField(
model_name='sessaoplenaria',
name='upload_pauta',
field=models.FileField(blank=True, null=True, upload_to=sessao.models.pauta_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Pauta da Sessão'),
),
]

8
sessao/models.py

@ -5,7 +5,7 @@ from model_utils import Choices
from materia.models import MateriaLegislativa
from parlamentares.models import (CargoMesa, Legislatura, Parlamentar,
SessaoLegislativa)
from sapl.utils import YES_NO_CHOICES
from sapl.utils import YES_NO_CHOICES, restringe_tipos_de_arquivo_txt
class TipoSessaoPlenaria(models.Model):
@ -63,12 +63,14 @@ class SessaoPlenaria(models.Model):
blank=True,
null=True,
upload_to=pauta_upload_path,
verbose_name=_('Pauta da Sessão'))
verbose_name=_('Pauta da Sessão'),
validators=[restringe_tipos_de_arquivo_txt])
upload_ata = models.FileField(
blank=True,
null=True,
upload_to=ata_upload_path,
verbose_name=_('Ata da Sessão'))
verbose_name=_('Ata da Sessão'),
validators=[restringe_tipos_de_arquivo_txt])
iniciada = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
verbose_name=_('Sessão iniciada?'))

14
templates/materia/proposicao/proposicao_list.html

@ -3,16 +3,16 @@
{% load crispy_forms_tags %}
{% block actions %}<!-- Remvoer botões 'Editar' e 'Excluir' -->{% endblock %}
<!--
{% block sections_nav %}
<h2><b>Proposições</b></h2>
<br />
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'materia:adicionar_proposicao' %}" class="btn btn-default">Nova Proposição</a>
</div>
{% endblock %}
{% endblock %} -->
{% block detail_content %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'adicionar_proposicao' %}" class="btn btn-default">Nova Proposição</a>
</div>
<h2><b>Proposições</b></h2>
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr>

2
templates/sessao/sessao_list.html

@ -3,8 +3,8 @@
{% load crispy_forms_tags %}
{% block base_content %}
<h2><b>Sessões Plenárias</b></h2>
<div class="actions btn-group pull-right" role="group">
<h2>Sessões Plenárias</h2>
<a href="{% url 'sessao:sessao_cadastro' %}" class="btn btn-default">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar Sessão Plenária {% endblocktrans %}
</a>

Loading…
Cancel
Save