Browse Source

Verificação em forms contendo arquivos (#2534)

* WIP

* WIP 2

* WIP 3

* Adiciona file check em Audiencia e Parlamentar e mostra todos os erros

* adicionado o file check em mais forms

* adiciona verificacao de arquivo em partido form
pull/2460/head
Edward 6 years ago
committed by GitHub
parent
commit
708f5c769a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      sapl/audiencia/forms.py
  2. 61
      sapl/base/forms.py
  3. 5
      sapl/base/views.py
  4. 5
      sapl/comissoes/forms.py
  5. 10
      sapl/materia/forms.py
  6. 10
      sapl/norma/forms.py
  7. 3
      sapl/parlamentares/forms.py
  8. 13
      sapl/parlamentares/views.py
  9. 7
      sapl/protocoloadm/forms.py
  10. 5
      sapl/sessao/forms.py
  11. 34
      sapl/utils.py

4
sapl/audiencia/forms.py

@ -10,9 +10,9 @@ from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout
from sapl.crispy_layout_mixin import SaplFormHelper
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.utils import timezone
from sapl.utils import timezone, FileFieldCheckMixin
class AudienciaForm(forms.ModelForm):
class AudienciaForm(FileFieldCheckMixin, forms.ModelForm):
logger = logging.getLogger(__name__)
data_atual = timezone.now()

61
sapl/base/forms.py

@ -1,4 +1,5 @@
import logging
import os
from crispy_forms.bootstrap import FieldWithButtons, InlineRadios, StrictButton
from sapl.crispy_layout_mixin import SaplFormHelper
@ -28,7 +29,7 @@ from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
from sapl.materia.models import (
MateriaLegislativa, UnidadeTramitacao, StatusTramitacao)
from sapl.norma.models import (NormaJuridica, NormaEstatisticas)
from sapl.parlamentares.models import SessaoLegislativa
from sapl.parlamentares.models import SessaoLegislativa, Partido
from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MAX_IMAGE_UPLOAD_SIZE
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
@ -36,8 +37,7 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
RangeWidgetOverride, autor_label, autor_modal,
models_with_gr_for_model, qs_override_django_filter,
choice_anos_com_normas, choice_anos_com_materias,
FilterOverridesMetaMixin)
FilterOverridesMetaMixin, FileFieldCheckMixin)
from .models import AppConfig, CasaLegislativa
@ -198,7 +198,7 @@ class UsuarioEditForm(ModelForm):
return data
class SessaoLegislativaForm(ModelForm):
class SessaoLegislativaForm(FileFieldCheckMixin, ModelForm):
logger = logging.getLogger(__name__)
class Meta:
@ -1108,7 +1108,7 @@ class RelatorioMateriasPorAutorFilterSet(django_filters.FilterSet):
)
class CasaLegislativaForm(ModelForm):
class CasaLegislativaForm(FileFieldCheckMixin, ModelForm):
class Meta:
@ -1138,7 +1138,11 @@ class CasaLegislativaForm(ModelForm):
}
def clean_logotipo(self):
logotipo = self.cleaned_data.get('logotipo', False)
# chama __clean de FileFieldCheckMixin
# por estar em clean de campo
super(CasaLegislativaForm, self)._check()
logotipo = self.cleaned_data.get('logotipo')
if logotipo:
if logotipo.size > MAX_IMAGE_UPLOAD_SIZE:
raise ValidationError("Imagem muito grande. ( > 2MB )")
@ -1204,7 +1208,7 @@ class ConfiguracoesAppForm(ModelForm):
self.logger.error('Não há casa legislativa relacionada.')
raise ValidationError("Não há casa legislativa relacionada.")
if (not bool(casa.logotipo) and mostrar_brasao_painel):
if not casa.logotipo and mostrar_brasao_painel:
self.logger.error('Não há logitipo configurado para esta '
'CasaLegislativa ({}).'.format(casa))
raise ValidationError("Não há logitipo configurado para esta "
@ -1346,3 +1350,46 @@ class AlterarSenhaForm(Form):
"Nova senha não pode ser igual à senha anterior")
return self.cleaned_data
class PartidoForm(FileFieldCheckMixin, ModelForm):
class Meta:
model = Partido
exclude = []
def __init__(self, *args, **kwargs):
super(PartidoForm, self).__init__(*args, **kwargs)
# TODO Utilizar esses campos na issue #2161 de alteração de nomes de partidos
# if self.instance:
# if self.instance.nome:
# self.fields['nome'].widget.attrs['readonly'] = True
# self.fields['sigla'].widget.attrs['readonly'] = True
row1 = to_row(
[('sigla', 2),
('nome', 6),
('data_criacao', 2),
('data_extincao', 2),])
row2 = to_row([('observacao', 12)])
row3 = to_row([('logo_partido', 12)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
row1, row2, row3,
form_actions(label='Salvar'))
def clean(self):
cleaned_data = super(PartidoForm, self).clean()
if not self.is_valid():
return cleaned_data
if cleaned_data['data_criacao'] and cleaned_data['data_extincao']:
if cleaned_data['data_criacao'] > cleaned_data['data_extincao']:
raise ValidationError("Certifique-se de que a data de criação seja anterior à data de extinção.")
return cleaned_data

5
sapl/base/views.py

@ -9,7 +9,7 @@ from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.models import Group, User
from django.contrib.auth.tokens import default_token_generator
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied, ValidationError
from django.core.mail import send_mail
from django.core.urlresolvers import reverse, reverse_lazy
from django.db import connection
@ -1499,8 +1499,11 @@ class AppConfigCrud(CrudAux):
def gerar_hash(self, inst):
inst.save()
if inst.texto_original:
try:
inst.hash_code = gerar_hash_arquivo(
inst.texto_original.path, str(inst.pk))
except IOError:
raise ValidationError("Existem proposicoes com arquivos inexistentes.")
elif inst.texto_articulado.exists():
ta = inst.texto_articulado.first()
inst.hash_code = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(inst.pk)

5
sapl/comissoes/forms.py

@ -12,6 +12,7 @@ from sapl.base.models import Autor, TipoAutor
from sapl.comissoes.models import (Comissao, Composicao, DocumentoAcessorio,
Participacao, Reuniao, Periodo)
from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar
from sapl.utils import FileFieldCheckMixin
class ComposicaoForm(forms.ModelForm):
@ -382,7 +383,7 @@ class ReuniaoForm(ModelForm):
return self.cleaned_data
class DocumentoAcessorioCreateForm(forms.ModelForm):
class DocumentoAcessorioCreateForm(FileFieldCheckMixin, forms.ModelForm):
parent_pk = forms.CharField(required=False) # widget=forms.HiddenInput())
@ -404,7 +405,7 @@ class DocumentoAcessorioCreateForm(forms.ModelForm):
reuniao = Reuniao.objects.get(id=self.initial['parent_pk'])
class DocumentoAcessorioEditForm(forms.ModelForm):
class DocumentoAcessorioEditForm(FileFieldCheckMixin, forms.ModelForm):
parent_pk = forms.CharField(required=False) # widget=forms.HiddenInput())

10
sapl/materia/forms.py

@ -45,7 +45,7 @@ from sapl.utils import (YES_NO_CHOICES, SEPARADOR_HASH_PROPOSICAO,
MateriaPesquisaOrderingFilter, RangeWidgetOverride,
autor_label, autor_modal, gerar_hash_arquivo,
models_with_gr_for_model, qs_override_django_filter,
choice_anos_com_materias, FilterOverridesMetaMixin)
choice_anos_com_materias, FilterOverridesMetaMixin, FileFieldCheckMixin)
from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial,
DocumentoAcessorio, Numeracao, Proposicao, Relatoria,
@ -122,7 +122,7 @@ class ReceberProposicaoForm(Form):
super(ReceberProposicaoForm, self).__init__(*args, **kwargs)
class MateriaSimplificadaForm(ModelForm):
class MateriaSimplificadaForm(FileFieldCheckMixin, ModelForm):
logger = logging.getLogger(__name__)
@ -175,7 +175,7 @@ class MateriaSimplificadaForm(ModelForm):
return cleaned_data
class MateriaLegislativaForm(ModelForm):
class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm):
logger = logging.getLogger(__name__)
@ -355,7 +355,7 @@ class AcompanhamentoMateriaForm(ModelForm):
super(AcompanhamentoMateriaForm, self).__init__(*args, **kwargs)
class DocumentoAcessorioForm(ModelForm):
class DocumentoAcessorioForm(FileFieldCheckMixin, ModelForm):
data = forms.DateField(required=True)
class Meta:
@ -1350,7 +1350,7 @@ class TipoProposicaoSelect(Select):
return option
class ProposicaoForm(forms.ModelForm):
class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm):
logger = logging.getLogger(__name__)

10
sapl/norma/forms.py

@ -17,8 +17,8 @@ from sapl.crispy_layout_mixin import form_actions, to_row
from sapl.materia.forms import choice_anos_com_materias
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.settings import MAX_DOC_UPLOAD_SIZE
from sapl.utils import NormaPesquisaOrderingFilter, RangeWidgetOverride,\
choice_anos_com_normas, FilterOverridesMetaMixin
from sapl.utils import NormaPesquisaOrderingFilter, RangeWidgetOverride, \
choice_anos_com_normas, FilterOverridesMetaMixin, FileFieldCheckMixin
from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada,
TipoNormaJuridica, AutoriaNorma)
@ -88,7 +88,7 @@ class NormaFilterSet(django_filters.FilterSet):
return queryset.filter(q)
class NormaJuridicaForm(ModelForm):
class NormaJuridicaForm(FileFieldCheckMixin, ModelForm):
# Campos de MateriaLegislativa
tipo_materia = forms.ModelChoiceField(
@ -200,6 +200,8 @@ class NormaJuridicaForm(ModelForm):
return cleaned_data
def clean_texto_integral(self):
super(NormaJuridicaForm, self).clean()
texto_integral = self.cleaned_data.get('texto_integral', False)
if texto_integral and texto_integral.size > MAX_DOC_UPLOAD_SIZE:
max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024))
@ -269,7 +271,7 @@ class AutoriaNormaForm(ModelForm):
return cd
class AnexoNormaJuridicaForm(ModelForm):
class AnexoNormaJuridicaForm(FileFieldCheckMixin, ModelForm):
class Meta:
model = AnexoNormaJuridica
fields = ['norma', 'anexo_arquivo', 'assunto_anexo']

3
sapl/parlamentares/forms.py

@ -15,6 +15,7 @@ from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from floppyforms.widgets import ClearableFileInput
from image_cropping.widgets import CropWidget, ImageCropWidget
from sapl.utils import FileFieldCheckMixin
from sapl.base.models import Autor, TipoAutor
from sapl.crispy_layout_mixin import form_actions, to_row
@ -196,7 +197,7 @@ class LegislaturaForm(ModelForm):
return data
class ParlamentarForm(ModelForm):
class ParlamentarForm(FileFieldCheckMixin, ModelForm):
class Meta:
model = Parlamentar

13
sapl/parlamentares/views.py

@ -19,7 +19,7 @@ from django.views.generic import FormView
from django.views.generic.edit import UpdateView
from image_cropping.utils import get_backend
from sapl.base.forms import SessaoLegislativaForm
from sapl.base.forms import SessaoLegislativaForm, PartidoForm
from sapl.base.models import Autor
from sapl.comissoes.models import Participacao
from sapl.crud.base import (RP_CHANGE, RP_DETAIL, RP_LIST, Crud, CrudAux,
@ -38,7 +38,6 @@ from .models import (CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa,
CargoMesaCrud = CrudAux.build(CargoMesa, 'cargo_mesa')
PartidoCrud = CrudAux.build(Partido, 'partidos')
TipoDependenteCrud = CrudAux.build(TipoDependente, 'tipo_dependente')
NivelInstrucaoCrud = CrudAux.build(NivelInstrucao, 'nivel_instrucao')
TipoAfastamentoCrud = CrudAux.build(TipoAfastamento, 'tipo_afastamento')
@ -58,6 +57,16 @@ class SessaoLegislativaCrud(CrudAux):
form_class = SessaoLegislativaForm
class PartidoCrud(CrudAux):
model = Partido
class CreateView(CrudAux.CreateView):
form_class = PartidoForm
class UpdateView(CrudAux.UpdateView):
form_class = PartidoForm
class VotanteView(MasterDetailCrud):
model = Votante
parent_field = 'parlamentar'

7
sapl/protocoloadm/forms.py

@ -23,7 +23,8 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter,
RangeWidgetOverride, autor_label, autor_modal,
choice_anos_com_protocolo, choice_force_optional,
choice_anos_com_documentoadministrativo,
FilterOverridesMetaMixin, choice_anos_com_materias)
FilterOverridesMetaMixin, choice_anos_com_materias,
FileFieldCheckMixin)
from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo,
DocumentoAdministrativo,
@ -626,7 +627,7 @@ class ProtocoloMateriaForm(ModelForm):
self.fields['data_hora_manual'].widget = forms.HiddenInput()
class DocumentoAcessorioAdministrativoForm(ModelForm):
class DocumentoAcessorioAdministrativoForm(FileFieldCheckMixin, ModelForm):
class Meta:
model = DocumentoAcessorioAdministrativo
@ -782,7 +783,7 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
return self.cleaned_data
class DocumentoAdministrativoForm(ModelForm):
class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm):
logger = logging.getLogger(__name__)

5
sapl/sessao/forms.py

@ -20,7 +20,8 @@ from sapl.materia.models import (MateriaLegislativa, StatusTramitacao,
from sapl.parlamentares.models import Parlamentar, Mandato
from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES,
MateriaPesquisaOrderingFilter, autor_label,
autor_modal, timezone, choice_anos_com_sessaoplenaria)
autor_modal, timezone, choice_anos_com_sessaoplenaria,
FileFieldCheckMixin)
from .models import (Bancada, Bloco, ExpedienteMateria, JustificativaAusencia,
Orador, OradorExpediente, OrdemDia, PresencaOrdemDia, SessaoPlenaria,
@ -45,7 +46,7 @@ ORDENACAO_RESUMO = [('cont_mult', 'Conteúdo Multimídia'),
('ocorr_sessao', 'Ocorrências da Sessão')]
class SessaoPlenariaForm(ModelForm):
class SessaoPlenariaForm(FileFieldCheckMixin, ModelForm):
class Meta:
model = SessaoPlenaria

34
sapl/utils.py

@ -6,6 +6,9 @@ import re
from unicodedata import normalize as unicodedata_normalize
import unicodedata
from django.core.files.uploadedfile import UploadedFile
from django.forms import BaseForm
from sapl.crispy_layout_mixin import SaplFormHelper
from crispy_forms.layout import HTML, Button
from django import forms
@ -574,6 +577,37 @@ class NormaPesquisaOrderingFilter(django_filters.OrderingFilter):
return super().filter(qs, _value)
class FileFieldCheckMixin(BaseForm):
def _check(self):
cleaned_data = super(FileFieldCheckMixin, self).clean()
errors = []
for name, campo in self.fields.items():
if isinstance(campo, forms.fields.FileField):
error = self.errors.get(name)
if error:
msgs = [e.replace('Certifique-se de que o arquivo',
"Certifique-se de que o nome do "
"arquivo no campo '{}'".format(
campo.label))
for e in error]
for msg in msgs:
errors.append(msg)
arquivo = self.cleaned_data.get(name)
if arquivo and not isinstance(arquivo, UploadedFile):
if not os.path.exists(arquivo.path):
errors.append("Arquivo referenciado no campo "
" '%s' inexistente! Marque a "
"opção Limpar e Salve." % campo.label)
if errors:
raise ValidationError(errors)
return cleaned_data
def clean(self):
""" Alias for _check() """
return self._check()
class AnoNumeroOrderingFilter(django_filters.OrderingFilter):
choices = (('DEC', 'Ordem Decrescente'),

Loading…
Cancel
Save