diff --git a/base/forms.py b/base/forms.py index 798b40e11..23a7864e7 100644 --- a/base/forms.py +++ b/base/forms.py @@ -89,7 +89,7 @@ class CasaLegislativaTabelaAuxForm(ModelForm): row4, row5, HTML("""
- {% if form.logotipo.value %} + {% if not form.fotografia.errors and form.fotografia.value %}
diff --git a/materia/forms.py b/materia/forms.py index 47138fbea..c50dfad79 100644 --- a/materia/forms.py +++ b/materia/forms.py @@ -70,6 +70,17 @@ class ProposicaoForm(ModelForm): self.helper.layout = Layout( Fieldset(_('Incluir Proposição'), row1, row2, row3, row4, + HTML(""" +
+

+ +

+ """, ), form_actions(more=more)) ) super(ProposicaoForm, self).__init__( diff --git a/materia/models.py b/materia/models.py index 56b480162..bd007594d 100644 --- a/materia/models.py +++ b/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') diff --git a/materia/views.py b/materia/views.py index 9cee72ad5..14ad129db 100644 --- a/materia/views.py +++ b/materia/views.py @@ -1,3 +1,4 @@ +import os from datetime import datetime from random import choice from string import ascii_letters, digits @@ -1358,8 +1359,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 @@ -1379,6 +1382,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: diff --git a/parlamentares/forms.py b/parlamentares/forms.py index ff47bee33..43377bbe6 100644 --- a/parlamentares/forms.py +++ b/parlamentares/forms.py @@ -60,12 +60,12 @@ class ParlamentaresForm (ModelForm): 'cpf': forms.TextInput(attrs={'class': 'cpf'}), 'rg': forms.TextInput(attrs={'class': 'rg'}), 'titulo_eleitor': forms.TextInput(attrs={ - 'class': 'titulo_eleitor'}), + 'class': 'titulo_eleitor'}), 'telefone': forms.TextInput(attrs={'class': 'telefone'}), 'fax': forms.TextInput(attrs={'class': 'telefone'}), 'cep_residencia': forms.TextInput(attrs={'class': 'cep'}), 'telefone_residencia': forms.TextInput(attrs={ - 'class': 'telefone'}), + 'class': 'telefone'}), 'fax_residencia': forms.TextInput(attrs={'class': 'telefone'}), 'fotografia': forms.FileInput, 'biografia': forms.Textarea(attrs={'id': 'biografia-parlamentar'}) @@ -131,18 +131,19 @@ class ParlamentaresForm (ModelForm): row6, row7, row8, row9, row10, row11, row12, row13, HTML("""
- {% if form.fotografia.value %} - -
- - {% endif %} -
""", ), + {% if not form.fotografia.errors %} + {% if form.fotografia.value %} + +

+ + {% endif %} + {% endif %} +
""", ), row14, form_actions()) ) diff --git a/parlamentares/models.py b/parlamentares/models.py index c72762e0b..70fe89583 100644 --- a/parlamentares/models.py +++ b/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') diff --git a/parlamentares/views.py b/parlamentares/views.py index 1f2a888f5..eda0452ec 100644 --- a/parlamentares/views.py +++ b/parlamentares/views.py @@ -72,7 +72,7 @@ def validate(form, parlamentar, filiacao, request): break if (data_desfiliacao and - data_init < data_desfiliacao < data_fim): + data_init < data_desfiliacao < data_fim): error_msg = _("A data de filiação e \ desfiliação não podem estar no intervalo \ @@ -206,7 +206,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: @@ -227,7 +227,7 @@ class ParlamentaresDependentesView(CreateView): def get_context_data(self, **kwargs): context = super(ParlamentaresDependentesView, self).\ - get_context_data(**kwargs) + get_context_data(**kwargs) pk = self.kwargs['pk'] parlamentar = Parlamentar.objects.get(pk=pk) dependentes = Dependente.objects.filter( @@ -265,12 +265,12 @@ class ParlamentaresDependentesEditView(UpdateView): def get_context_data(self, **kwargs): context = super(ParlamentaresDependentesEditView, self).\ - get_context_data(**kwargs) + get_context_data(**kwargs) parlamentar = Parlamentar.objects.get(id=self.kwargs['pk']) context.update({ - 'object': parlamentar, - 'legislatura_id': parlamentar.mandato_set.last( - ).legislatura_id}) + 'object': parlamentar, + 'legislatura_id': parlamentar.mandato_set.last( + ).legislatura_id}) return context def form_valid(self, form): @@ -522,7 +522,7 @@ class MandatoEditView(UpdateView): context.update( {'object': parlamentar, 'legislatura_id': parlamentar.mandato_set.last( - ).legislatura_id}) + ).legislatura_id}) return context def form_valid(self, form): diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 3e2575f11..3e7e04641 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -18,3 +18,4 @@ pytz==2015.7 pyyaml==3.11 rtyaml==0.0.2 unipath==1.1 +python-magic==0.4.10 diff --git a/sapl/settings.py b/sapl/settings.py index 903a7a016..dcf35823a 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -9,15 +9,13 @@ 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 \ SUPRESS_CRISPY_FORM_WARNINGS_LOGGING -from decouple import config - -from dj_database_url import parse as db_url - BASE_DIR = Path(__file__).ancestor(2) diff --git a/sapl/utils.py b/sapl/utils.py index 77840dd76..71f640578 100644 --- a/sapl/utils.py +++ b/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,60 @@ 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): + + 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')) + return restringe_tipos_de_arquivo + +restringe_tipos_de_arquivo_txt = fabrica_validador_de_tipos_de_arquivo( + TIPOS_TEXTO_PERMITIDOS) +restringe_tipos_de_arquivo_img = fabrica_validador_de_tipos_de_arquivo( + TIPOS_IMG_PERMITIDOS) diff --git a/sessao/forms.py b/sessao/forms.py index a8b7fef88..dd9c1ab34 100644 --- a/sessao/forms.py +++ b/sessao/forms.py @@ -1,7 +1,6 @@ from crispy_forms.helper import FormHelper from crispy_forms.layout import Fieldset, Layout from django import forms -from django.core.exceptions import ValidationError from django.forms import ModelForm from django.utils.translation import ugettext_lazy as _ @@ -94,20 +93,6 @@ class SessaoForm(ModelForm): 'hora_fim': forms.TextInput(attrs={'class': 'hora'}), } - def clean_url_audio(self): - url_audio = self.cleaned_data.get('url_audio', False) - if url_audio: - if url_audio.size > MAX_DOC_UPLOAD_SIZE: - raise ValidationError("Arquivo muito grande. ( > 5mb )") - return url_audio - - def clean_url_video(self): - url_video = self.cleaned_data.get('url_video', False) - if url_video: - if url_video.size > MAX_DOC_UPLOAD_SIZE: - raise ValidationError("Arquivo muito grande. ( > 5mb )") - return url_video - def __init__(self, *args, **kwargs): row1 = crispy_layout_mixin.to_row( diff --git a/sessao/models.py b/sessao/models.py index e38e87f63..6e7e2e86f 100644 --- a/sessao/models.py +++ b/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?')) diff --git a/templates/materia/proposicao/proposicao_list.html b/templates/materia/proposicao/proposicao_list.html index d666badbe..cb04c5bf0 100644 --- a/templates/materia/proposicao/proposicao_list.html +++ b/templates/materia/proposicao/proposicao_list.html @@ -3,16 +3,16 @@ {% load crispy_forms_tags %} {% block actions %}{% endblock %} - + {% block detail_content %} +
+ Nova Proposição +
+

Proposições

diff --git a/templates/sessao/sessao_list.html b/templates/sessao/sessao_list.html index e005802a1..f85faa389 100644 --- a/templates/sessao/sessao_list.html +++ b/templates/sessao/sessao_list.html @@ -3,8 +3,8 @@ {% load crispy_forms_tags %} {% block base_content %} +

Sessões Plenárias

-

Sessões Plenárias

{% blocktrans with verbose_name=view.verbose_name %} Adicionar Sessão Plenária {% endblocktrans %}