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. 25
      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. 29
      parlamentares/forms.py
  11. 22
      parlamentares/migrations/0016_auto_20160404_1409.py
  12. 5
      parlamentares/models.py
  13. 7
      parlamentares/test_parlamentares.py
  14. 20
      parlamentares/views.py
  15. 4
      requirements/requirements.txt
  16. 29
      sapl/settings.py
  17. 18
      sapl/test_general.py
  18. 119
      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. * 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 Instructions for Translators
============================ ============================

25
base/forms.py

@ -88,18 +88,19 @@ class CasaLegislativaTabelaAuxForm(ModelForm):
row3, row3,
row4, row4,
row5, row5,
HTML("""<div class="col-md-12"> HTML("""
{% if form.logotipo.value %} <div class="col-md-12">
<img class="img-responsive" width="225" height="300" {% if not form.fotografia.errors and form.fotografia.value %}
src="{{ MEDIA_URL }}{{ form.logotipo.value }}"> <img class="img-responsive" width="225" height="300"
<br /> src="{{ MEDIA_URL }}{{ form.logotipo.value }}">
<input type="submit" <br />
name="remover" <input type="submit"
id="remover" name="remover"
class="btn btn-warning" id="remover"
value="Remover Logo"/> class="btn btn-warning"
{% endif %} value="Remover Logo"/>
</div>"""), {% endif %}
</div>"""),
row6, row6,
row7, row7,
row8, row8,

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): class TextoArticulado(TimestampedMixin):
data = models.DateField(blank=True, null=True, verbose_name=_('Data')) data = models.DateField(blank=True, null=True, verbose_name=_('Data'))
ementa = models.TextField(verbose_name=_('Ementa')) ementa = models.TextField(verbose_name=_('Ementa'))
observacao = models.TextField( observacao = models.TextField(blank=True, verbose_name=_('Observação'))
blank=True, null=True, verbose_name=_('Observação'))
numero = models.PositiveIntegerField(verbose_name=_('Número')) numero = models.PositiveIntegerField(verbose_name=_('Número'))
ano = models.PositiveSmallIntegerField(verbose_name=_('Ano')) ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'))
tipo_ta = models.ForeignKey( tipo_ta = models.ForeignKey(

11
materia/forms.py

@ -70,6 +70,17 @@ class ProposicaoForm(ModelForm):
self.helper.layout = Layout( self.helper.layout = Layout(
Fieldset(_('Incluir Proposição'), Fieldset(_('Incluir Proposição'),
row1, row2, row3, row4, 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)) form_actions(more=more))
) )
super(ProposicaoForm, self).__init__( 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 comissoes.models import Comissao
from parlamentares.models import Parlamentar, Partido 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): class TipoMateriaLegislativa(models.Model):
@ -122,7 +123,8 @@ class MateriaLegislativa(models.Model):
blank=True, blank=True,
null=True, null=True,
upload_to=texto_upload_path, upload_to=texto_upload_path,
verbose_name=_('Texto Original (PDF)')) verbose_name=_('Texto Original (PDF)'),
validators=[restringe_tipos_de_arquivo_txt])
class Meta: class Meta:
verbose_name = _('Matéria Legislativa') verbose_name = _('Matéria Legislativa')
@ -457,7 +459,8 @@ class Proposicao(models.Model):
blank=True, blank=True,
null=True, null=True,
upload_to=texto_upload_path, upload_to=texto_upload_path,
verbose_name=_('Texto Original (PDF)')) verbose_name=_('Texto Original (PDF)'),
validators=[restringe_tipos_de_arquivo_txt])
class Meta: class Meta:
verbose_name = _('Proposição') verbose_name = _('Proposição')

1
materia/test_materia_urls.py

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

11
materia/views.py

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

29
parlamentares/forms.py

@ -60,12 +60,12 @@ class ParlamentaresForm (ModelForm):
'cpf': forms.TextInput(attrs={'class': 'cpf'}), 'cpf': forms.TextInput(attrs={'class': 'cpf'}),
'rg': forms.TextInput(attrs={'class': 'rg'}), 'rg': forms.TextInput(attrs={'class': 'rg'}),
'titulo_eleitor': forms.TextInput(attrs={ 'titulo_eleitor': forms.TextInput(attrs={
'class': 'titulo_eleitor'}), 'class': 'titulo_eleitor'}),
'telefone': forms.TextInput(attrs={'class': 'telefone'}), 'telefone': forms.TextInput(attrs={'class': 'telefone'}),
'fax': forms.TextInput(attrs={'class': 'telefone'}), 'fax': forms.TextInput(attrs={'class': 'telefone'}),
'cep_residencia': forms.TextInput(attrs={'class': 'cep'}), 'cep_residencia': forms.TextInput(attrs={'class': 'cep'}),
'telefone_residencia': forms.TextInput(attrs={ 'telefone_residencia': forms.TextInput(attrs={
'class': 'telefone'}), 'class': 'telefone'}),
'fax_residencia': forms.TextInput(attrs={'class': 'telefone'}), 'fax_residencia': forms.TextInput(attrs={'class': 'telefone'}),
'fotografia': forms.FileInput, 'fotografia': forms.FileInput,
'biografia': forms.Textarea(attrs={'id': 'biografia-parlamentar'}) 'biografia': forms.Textarea(attrs={'id': 'biografia-parlamentar'})
@ -131,18 +131,19 @@ class ParlamentaresForm (ModelForm):
row6, row7, row8, row9, row10, row6, row7, row8, row9, row10,
row11, row12, row13, row11, row12, row13,
HTML("""<div class="col-md-12"> HTML("""<div class="col-md-12">
{% if form.fotografia.value %} {% if not form.fotografia.errors %}
<img class="img-responsive" {% if form.fotografia.value %}
width="225" height="300" <img class="img-responsive" width="225" height="300"
src="{{MEDIA_URL}}{{form.fotografia.value}}"> src="{{ MEDIA_URL }}{{ form.fotografia.value }}">
<br /> <br /><br />
<input type="submit" <input type="submit"
name="remover" name="remover-foto"
id="remover" id="remover-foto"
class="btn btn-warning" class="btn btn-warning"
value="Remover Foto"/> value="Remover Foto"/>
{% endif %} {% endif %}
</div>""", ), {% endif %}
</div>""", ),
row14, row14,
form_actions()) 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 django.utils.translation import ugettext_lazy as _
from model_utils import Choices 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): class Legislatura(models.Model):
@ -244,7 +244,8 @@ class Parlamentar(models.Model):
blank=True, blank=True,
null=True, null=True,
upload_to=foto_upload_path, upload_to=foto_upload_path,
verbose_name=_('Fotografia')) verbose_name=_('Fotografia'),
validators=[restringe_tipos_de_arquivo_img])
class Meta: class Meta:
verbose_name = _('Parlamentar') verbose_name = _('Parlamentar')

7
parlamentares/test_parlamentares.py

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

20
parlamentares/views.py

@ -72,7 +72,7 @@ def validate(form, parlamentar, filiacao, request):
break break
if (data_desfiliacao and if (data_desfiliacao and
data_init < data_desfiliacao < data_fim): data_init < data_desfiliacao < data_fim):
error_msg = _("A data de filiação e \ error_msg = _("A data de filiação e \
desfiliação não podem estar no intervalo \ desfiliação não podem estar no intervalo \
@ -186,10 +186,6 @@ class ParlamentaresCadastroView(CreateView):
def form_valid(self, form): def form_valid(self, form):
form.save() 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()) return redirect(self.get_success_url())
@ -206,7 +202,7 @@ class ParlamentaresEditarView(UpdateView):
elif 'excluir' in self.request.POST: elif 'excluir' in self.request.POST:
Mandato.objects.get(parlamentar=parlamentar).delete() Mandato.objects.get(parlamentar=parlamentar).delete()
parlamentar.delete() parlamentar.delete()
elif "remover" in self.request.POST: elif "remover-foto" in self.request.POST:
try: try:
os.unlink(parlamentar.fotografia.path) os.unlink(parlamentar.fotografia.path)
except OSError: except OSError:
@ -228,7 +224,7 @@ class ParlamentaresDependentesView(CreateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(ParlamentaresDependentesView, self).\ context = super(ParlamentaresDependentesView, self).\
get_context_data(**kwargs) get_context_data(**kwargs)
pk = self.kwargs['pk'] pk = self.kwargs['pk']
parlamentar = Parlamentar.objects.get(pk=pk) parlamentar = Parlamentar.objects.get(pk=pk)
dependentes = Dependente.objects.filter( dependentes = Dependente.objects.filter(
@ -267,12 +263,12 @@ class ParlamentaresDependentesEditView(UpdateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(ParlamentaresDependentesEditView, self).\ context = super(ParlamentaresDependentesEditView, self).\
get_context_data(**kwargs) get_context_data(**kwargs)
parlamentar = Parlamentar.objects.get(id=self.kwargs['pk']) parlamentar = Parlamentar.objects.get(id=self.kwargs['pk'])
context.update({ context.update({
'object': parlamentar, 'object': parlamentar,
'legislatura_id': parlamentar.mandato_set.last( 'legislatura_id': parlamentar.mandato_set.last(
).legislatura_id}) ).legislatura_id})
return context return context
def form_valid(self, form): def form_valid(self, form):
@ -528,7 +524,7 @@ class MandatoEditView(UpdateView):
context.update( context.update(
{'object': parlamentar, {'object': parlamentar,
'legislatura_id': parlamentar.mandato_set.last( 'legislatura_id': parlamentar.mandato_set.last(
).legislatura_id}) ).legislatura_id})
return context return context
def form_valid(self, form): def form_valid(self, form):

4
requirements/requirements.txt

@ -1,10 +1,11 @@
dj-database-url
django-admin-bootstrapped==2.5.7 django-admin-bootstrapped==2.5.7
django-bootstrap3==7.0.0 django-bootstrap3==7.0.0
django-bower==5.1.0 django-bower==5.1.0
django-braces==1.8.1 django-braces==1.8.1
django-compressor==2.0 django-compressor==2.0
django-crispy-forms==1.6.0 django-crispy-forms==1.6.0
python-decouple==3.0
django-extra-views==0.7.1 django-extra-views==0.7.1
django-model-utils==2.4 django-model-utils==2.4
django-sass-processor==0.3.4 django-sass-processor==0.3.4
@ -17,3 +18,4 @@ pytz==2015.7
pyyaml==3.11 pyyaml==3.11
rtyaml==0.0.2 rtyaml==0.0.2
unipath==1.1 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 For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/ 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 unipath import Path
from .temp_suppress_crispy_form_warnings import \ from .temp_suppress_crispy_form_warnings import \
@ -16,14 +18,15 @@ from .temp_suppress_crispy_form_warnings import \
BASE_DIR = Path(__file__).ancestor(2) BASE_DIR = Path(__file__).ancestor(2)
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! # 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! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ['*']
@ -105,21 +108,17 @@ WSGI_APPLICATION = 'sapl.wsgi.application'
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases # https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = { DATABASES = {
'default': { 'default': config(
'ENGINE': 'django.db.backends.postgresql_psycopg2', 'DATABASE_URL',
'NAME': 'sapl', cast=db_url,
'USER': 'sapl', )
'PASSWORD': 'sapl',
'HOST': 'localhost',
'PORT': '5432',
}
} }
EMAIL_USE_TLS = True EMAIL_USE_TLS = config('EMAIL_USE_TLS', cast=bool)
EMAIL_HOST = '' EMAIL_HOST = config('EMAIL_HOST', cast=str)
EMAIL_HOST_USER = '' EMAIL_HOST_USER = config('EMAIL_HOST_USER', cast=str)
EMAIL_HOST_PASSWORD = '' EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', cast=str)
EMAIL_PORT = 587 EMAIL_PORT = config('EMAIL_PORT', cast=int)
MAX_DOC_UPLOAD_SIZE = 5*1024*1024 # 5MB MAX_DOC_UPLOAD_SIZE = 5*1024*1024 # 5MB
MAX_IMAGE_UPLOAD_SIZE = 2*1024*1024 # 2MB MAX_IMAGE_UPLOAD_SIZE = 2*1024*1024 # 2MB

18
sapl/test_general.py

@ -1,16 +1,32 @@
import pytest import pytest
from django.apps import apps from django.apps import apps
from django.db.models import CharField, TextField
from model_mommy import mommy from model_mommy import mommy
from .settings import SAPL_APPS from .settings import SAPL_APPS
pytestmark = pytest.mark.django_db 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(): def test_str_sanity():
# this simply a sanity check # this simply a sanity check
# __str__ semantics is not considered and should be tested separetely # __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 app in sapl_appconfs:
for model in app.get_models(): for model in app.get_models():
obj = mommy.prepare(model) obj = mommy.prepare(model)

119
sapl/utils.py

@ -1,8 +1,10 @@
from datetime import date from datetime import date
from functools import wraps from functools import wraps
import magic
from django.apps import apps from django.apps import apps
from django.contrib import admin from django.contrib import admin
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -92,34 +94,93 @@ def listify(function):
return f return f
UF = [ UF = [
('AC', 'Acre'), ('AC', 'Acre'),
('AL', 'Alagoas'), ('AL', 'Alagoas'),
('AP', 'Amapá'), ('AP', 'Amapá'),
('AM', 'Amazonas'), ('AM', 'Amazonas'),
('BA', 'Bahia'), ('BA', 'Bahia'),
('CE', 'Ceará'), ('CE', 'Ceará'),
('DF', 'Distrito Federal'), ('DF', 'Distrito Federal'),
('ES', 'Espírito Santo'), ('ES', 'Espírito Santo'),
('GO', 'Goiás'), ('GO', 'Goiás'),
('MA', 'Maranhão'), ('MA', 'Maranhão'),
('MT', 'Mato Grosso'), ('MT', 'Mato Grosso'),
('MS', 'Mato Grosso do Sul'), ('MS', 'Mato Grosso do Sul'),
('MG', 'Minas Gerais'), ('MG', 'Minas Gerais'),
('PR', 'Paraná'), ('PR', 'Paraná'),
('PB', 'Paraíba'), ('PB', 'Paraíba'),
('PA', 'Pará'), ('PA', 'Pará'),
('PE', 'Pernambuco'), ('PE', 'Pernambuco'),
('PI', 'Piauí'), ('PI', 'Piauí'),
('RJ', 'Rio de Janeiro'), ('RJ', 'Rio de Janeiro'),
('RN', 'Rio Grande do Norte'), ('RN', 'Rio Grande do Norte'),
('RS', 'Rio Grande do Sul'), ('RS', 'Rio Grande do Sul'),
('RO', 'Rondônia'), ('RO', 'Rondônia'),
('RR', 'Roraima'), ('RR', 'Roraima'),
('SC', 'Santa Catarina'), ('SC', 'Santa Catarina'),
('SE', 'Sergipe'), ('SE', 'Sergipe'),
('SP', 'São Paulo'), ('SP', 'São Paulo'),
('TO', 'Tocantins'), ('TO', 'Tocantins'),
('EX', 'Exterior'), ('EX', 'Exterior'),
] ]
RANGE_ANOS = [(year, year) for year in range(date.today().year, 1889, -1)] 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 materia.models import MateriaLegislativa
from parlamentares.models import (CargoMesa, Legislatura, Parlamentar, from parlamentares.models import (CargoMesa, Legislatura, Parlamentar,
SessaoLegislativa) SessaoLegislativa)
from sapl.utils import YES_NO_CHOICES from sapl.utils import YES_NO_CHOICES, restringe_tipos_de_arquivo_txt
class TipoSessaoPlenaria(models.Model): class TipoSessaoPlenaria(models.Model):
@ -63,12 +63,14 @@ class SessaoPlenaria(models.Model):
blank=True, blank=True,
null=True, null=True,
upload_to=pauta_upload_path, 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( upload_ata = models.FileField(
blank=True, blank=True,
null=True, null=True,
upload_to=ata_upload_path, 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, iniciada = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES, choices=YES_NO_CHOICES,
verbose_name=_('Sessão iniciada?')) verbose_name=_('Sessão iniciada?'))

14
templates/materia/proposicao/proposicao_list.html

@ -3,16 +3,16 @@
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% block actions %}<!-- Remvoer botões 'Editar' e 'Excluir' -->{% endblock %} {% block actions %}<!-- Remvoer botões 'Editar' e 'Excluir' -->{% endblock %}
<!--
{% block sections_nav %} {% block sections_nav %}
<h2><b>Proposições</b></h2>
<br /> {% endblock %} -->
<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 %}
{% block detail_content %} {% 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"> <table class="table table-striped table-bordered">
<thead class="thead-default"> <thead class="thead-default">
<tr> <tr>

2
templates/sessao/sessao_list.html

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

Loading…
Cancel
Save