Browse Source

Merge branch '3.1.x' of https://github.com/interlegis/sapl into 2293-observacao-em-proposicao

pull/2295/head
Mariana Mendes 7 years ago
parent
commit
a35e6b8d0a
  1. 2
      .gitignore
  2. 8
      Dockerfile
  3. 6
      README.rst
  4. 4
      docker-compose.yml
  5. 7
      docs/logo_partidos.rst
  6. BIN
      docs/logo_partidos/dem.png
  7. BIN
      docs/logo_partidos/pdt.png
  8. BIN
      docs/logo_partidos/pfl.png
  9. BIN
      docs/logo_partidos/phs.png
  10. BIN
      docs/logo_partidos/pl.png
  11. BIN
      docs/logo_partidos/pmdb.png
  12. BIN
      docs/logo_partidos/pmn.png
  13. BIN
      docs/logo_partidos/pp.png
  14. BIN
      docs/logo_partidos/pps.png
  15. BIN
      docs/logo_partidos/prb.png
  16. BIN
      docs/logo_partidos/prona.png
  17. BIN
      docs/logo_partidos/prp.png
  18. BIN
      docs/logo_partidos/prtb.png
  19. BIN
      docs/logo_partidos/psb.png
  20. BIN
      docs/logo_partidos/psc.png
  21. BIN
      docs/logo_partidos/psdb.png
  22. BIN
      docs/logo_partidos/psdc.png
  23. BIN
      docs/logo_partidos/psl.png
  24. BIN
      docs/logo_partidos/psol.png
  25. BIN
      docs/logo_partidos/pt.png
  26. BIN
      docs/logo_partidos/ptb.png
  27. BIN
      docs/logo_partidos/ptc.png
  28. BIN
      docs/logo_partidos/ptdob.png
  29. BIN
      docs/logo_partidos/ptn.png
  30. BIN
      docs/logo_partidos/pv.png
  31. 2
      release.sh
  32. 2
      requirements/dev-requirements.txt
  33. 25
      requirements/requirements.txt
  34. 6
      sapl/api/forms.py
  35. 14
      sapl/api/views.py
  36. 44
      sapl/audiencia/forms.py
  37. 33
      sapl/audiencia/migrations/0007_anexoaudienciapublica.py
  38. 28
      sapl/audiencia/migrations/0008_auto_20181023_1051.py
  39. 19
      sapl/audiencia/migrations/0009_remove_anexoaudienciapublica_indexacao.py
  40. 46
      sapl/audiencia/models.py
  41. 5
      sapl/audiencia/urls.py
  42. 62
      sapl/audiencia/views.py
  43. 93
      sapl/base/forms.py
  44. 22
      sapl/base/templatetags/common_tags.py
  45. 8
      sapl/base/tests/teststub_urls.py
  46. 40
      sapl/base/views.py
  47. 46
      sapl/comissoes/forms.py
  48. 1
      sapl/comissoes/tests/test_comissoes.py
  49. 15
      sapl/comissoes/views.py
  50. 73
      sapl/compilacao/views.py
  51. 57
      sapl/crud/base.py
  52. 6
      sapl/legacy/management/commands/ressuscitar_deps.py
  53. 9
      sapl/legacy/migracao.py
  54. 32
      sapl/legacy/migracao_dados.py
  55. 7
      sapl/legacy/migracao_documentos.py
  56. 22
      sapl/legacy/scripts/ressuscita_dependencias.py
  57. 158
      sapl/materia/forms.py
  58. 21
      sapl/materia/migrations/0032_auto_20181022_1743.py
  59. 2
      sapl/materia/models.py
  60. 226
      sapl/materia/views.py
  61. 35
      sapl/norma/forms.py
  62. 14
      sapl/norma/views.py
  63. 53
      sapl/painel/views.py
  64. 66
      sapl/parlamentares/forms.py
  65. 90
      sapl/parlamentares/views.py
  66. 72
      sapl/protocoloadm/forms.py
  67. 83
      sapl/protocoloadm/views.py
  68. 140
      sapl/redireciona_urls/views.py
  69. 14
      sapl/relatorios/templates/pdf_pauta_sessao_gerar.py
  70. 10
      sapl/relatorios/views.py
  71. 27
      sapl/rules/apps.py
  72. 1
      sapl/rules/map_rules.py
  73. 2
      sapl/sessao/forms.py
  74. 66
      sapl/sessao/migrations/0026_auto_20181016_1944.py
  75. 25
      sapl/sessao/migrations/0027_auto_20181023_1239.py
  76. 30
      sapl/sessao/models.py
  77. 132
      sapl/sessao/tests/test_sessao.py
  78. 182
      sapl/sessao/views.py
  79. 72
      sapl/settings.py
  80. 1
      sapl/static/styles/app.scss
  81. 171
      sapl/templates/404.html
  82. 135
      sapl/templates/500.html
  83. 5
      sapl/templates/audiencia/layouts.yaml
  84. 5
      sapl/templates/audiencia/subnav.yaml
  85. 6
      sapl/templates/base.html
  86. 9
      sapl/templates/compilacao/dispositivo_form_search_fragment.html
  87. 10
      sapl/templates/compilacao/messages.html
  88. 16
      sapl/templates/crud/detail.html
  89. 10
      sapl/templates/materia/impressos/ficha_pdf.html
  90. 15
      sapl/templates/materia/materialegislativa_detail.html
  91. 17
      sapl/templates/materia/proposicao_detail.html
  92. 6
      sapl/templates/protocoloadm/protocolo_mostrar.html
  93. 2
      sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html
  94. 2
      sapl/test_urls.py
  95. 6
      sapl/urls.py
  96. 6
      sapl/utils.py
  97. 27
      setup.py

2
.gitignore

@ -87,7 +87,7 @@ target/
*.sublime-workspace
.ipynb_checkpoints/
*.ipynb
.vscode/*
# specific to this project
whoosh_index

8
Dockerfile

@ -1,8 +1,8 @@
FROM alpine:3.7
FROM alpine:3.8
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 poppler-utils antiword vim openssh-client
python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev \
nodejs npm py3-lxml py3-magic postgresql-client poppler-utils antiword vim openssh-client
RUN apk update --update-cache && apk upgrade
@ -40,7 +40,7 @@ COPY config/env_dockerfile /var/interlegis/sapl/sapl/.env
# compilescss - Precompile all occurrences of your SASS/SCSS files for the whole project into css files
RUN python3 manage.py bower_install -- --allow-root --no-input && \
RUN python3 manage.py bower_install --allow-root && \
python3 manage.py compilescss
RUN python3 manage.py collectstatic --noinput --clear

6
README.rst

@ -53,12 +53,6 @@ Orientações gerais sobre o GitHub
Logo dos Partidos
===================================
`Logo dos Partidos <https://github.com/interlegis/sapl/blob/master/docs/logo_partidos.rst>`_
Perguntas Frequentes
===================================
`Perguntas Frequentes <https://github.com/interlegis/sapl/wiki/Perguntas-Frequentes>`_

4
docker-compose.yml

@ -1,5 +1,5 @@
sapldb:
image: postgres:9.6.8-alpine
image: postgres:10.5-alpine
restart: always
environment:
POSTGRES_PASSWORD: sapl
@ -11,7 +11,7 @@ sapldb:
ports:
- "5432:5432"
sapl:
image: interlegis/sapl:3.1.124
image: interlegis/sapl:3.1.131
restart: always
environment:
ADMIN_PASSWORD: interlegis

7
docs/logo_partidos.rst

@ -1,7 +0,0 @@
========================
Logo Partidos Políticos
========================
Dentro da pasta docs/logo_partidos existem os logotipos dos Partidos Políticos em formato png, quem quiser pode usá-los no cadastro de partidos em tabelas auxiliares.

BIN
docs/logo_partidos/dem.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/logo_partidos/pdt.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/logo_partidos/pfl.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/logo_partidos/phs.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

BIN
docs/logo_partidos/pl.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

BIN
docs/logo_partidos/pmdb.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

BIN
docs/logo_partidos/pmn.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

BIN
docs/logo_partidos/pp.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/logo_partidos/pps.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

BIN
docs/logo_partidos/prb.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

BIN
docs/logo_partidos/prona.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/logo_partidos/prp.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/logo_partidos/prtb.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/logo_partidos/psb.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

BIN
docs/logo_partidos/psc.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/logo_partidos/psdb.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/logo_partidos/psdc.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/logo_partidos/psl.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/logo_partidos/psol.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

BIN
docs/logo_partidos/pt.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/logo_partidos/ptb.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

BIN
docs/logo_partidos/ptc.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/logo_partidos/ptdob.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

BIN
docs/logo_partidos/ptn.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/logo_partidos/pv.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

2
release.sh

@ -21,7 +21,7 @@ function bump_version {
function commit_and_push {
echo "committing..."
git add docker-compose.yml setup.py
git add docker-compose.yml setup.py sapl/templates/base.html
git commit -m "Release: $NEXT_VERSION"
git tag $NEXT_VERSION

2
requirements/dev-requirements.txt

@ -2,7 +2,7 @@
autopep8==1.2.4
beautifulsoup4==4.6.0
django-debug-toolbar==1.5
django-debug-toolbar==1.8
ipdb==0.10.1
pdbpp==0.9.2
pip-review==0.4

25
requirements/requirements.txt

@ -1,25 +1,22 @@
dj-database-url==0.4.1
django-haystack==2.6.0
django>=1.9,<1.10
# TODO O django-admin-bootstrapped 2.5.7 não inseriu a mudança que permite
# a compatibilidade com Django 1.9+. A linha abaixo será mudada quando uma
# nova versão do django-admin-bootstrapped for lançada
git+git://github.com/django-admin-bootstrapped/django-admin-bootstrapped.git
django>=1.10,<1.11
git+git://github.com/rubgombar1/django-admin-bootstrapped.git
django-bootstrap3==7.0.1
django-bower==5.1.0
django-bower==5.2.0
django-braces==1.9.0
django-compressor==2.0
django-crispy-forms==1.6.0
django-extensions==1.6.7
django-extra-views==0.8.0
django-crispy-forms==1.6.1
django-extensions==1.9.8
django-extra-views==0.11.0
django-filter==0.15.3
django-floppyforms==1.6.2
django-model-utils==2.5
django-sass-processor==0.5.4
django-model-utils==3.1.1
django-sass-processor==0.5.8
djangorestframework==3.4.0
drfdocs==0.0.11
easy-thumbnails==2.3
django-image-cropping==1.1.0
git+git://github.com/jasperlittle/django-rest-framework-docs
easy-thumbnails==2.5
django-image-cropping==1.2
git+git://github.com/interlegis/trml2pdf.git
libsass==0.11.1
psycopg2-binary==2.7.4

6
sapl/api/forms.py

@ -1,3 +1,5 @@
import logging
from django.db.models import Q
from django.forms.fields import CharField, MultiValueField
from django.forms.widgets import MultiWidget, TextInput
@ -124,6 +126,7 @@ class AutorSearchForFieldFilterSet(AutorChoiceFilterSet):
class AutoresPossiveisFilterSet(FilterSet):
logger = logging.getLogger(__name__)
data_relativa = DateFilter(method='filter_data_relativa')
tipo = MethodFilter()
@ -135,9 +138,12 @@ class AutoresPossiveisFilterSet(FilterSet):
return queryset
def filter_tipo(self, queryset, value):
try:
self.logger.debug("Tentando obter TipoAutor correspondente à pk {}.".format(value))
tipo = TipoAutor.objects.get(pk=value)
except:
self.logger.error("TipoAutor(pk={}) inexistente.".format(value))
raise serializers.ValidationError(_('Tipo de Autor inexistente.'))
qs = queryset.filter(tipo=tipo)

14
sapl/api/views.py

@ -1,4 +1,4 @@
import logging
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.http import Http404
@ -124,6 +124,7 @@ class AutorListView(ListAPIView):
qualquer atributo destes models podem ser passados
para busca
"""
logger = logging.getLogger(__name__)
TR_AUTOR_CHOICE_SERIALIZER = 1
TR_AUTOR_SERIALIZER = 3
@ -138,6 +139,7 @@ class AutorListView(ListAPIView):
@property
def tr(self):
username = self.request.user.username
try:
tr = int(self.request.GET.get
('tr', AutorListView.TR_AUTOR_CHOICE_SERIALIZER))
@ -145,7 +147,8 @@ class AutorListView(ListAPIView):
if tr not in (AutorListView.TR_AUTOR_CHOICE_SERIALIZER,
AutorListView.TR_AUTOR_SERIALIZER):
return AutorListView.TR_AUTOR_CHOICE_SERIALIZER
except:
except Exception as e:
self.logger.error('user=' + username + '. ' + str(e))
return AutorListView.TR_AUTOR_CHOICE_SERIALIZER
return tr
@ -161,6 +164,7 @@ class AutorListView(ListAPIView):
class AutoresProvaveisListView(ListAPIView):
logger = logging.getLogger(__name__)
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
@ -171,14 +175,16 @@ class AutoresProvaveisListView(ListAPIView):
serializer_class = ChoiceSerializer
def get_queryset(self):
params = {'content_type__isnull': False}
params = {'content_type__isnull': False}
username = self.request.user.username
tipo = ''
try:
tipo = int(self.request.GET.get('tipo', ''))
if tipo:
params['id'] = tipo
except:
except Exception as e:
self.logger.error('user= ' + username + '. ' + str(e))
pass
tipos = TipoAutor.objects.filter(**params)

44
sapl/audiencia/forms.py

@ -1,13 +1,19 @@
import logging
from django import forms
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import transaction
from django.utils.translation import ugettext_lazy as _
from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica
from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica, AnexoAudienciaPublica
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout
from crispy_forms.helper import FormHelper
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.utils import timezone
class AudienciaForm(forms.ModelForm):
logger = logging.getLogger(__name__)
data_atual = timezone.now()
tipo = forms.ModelChoiceField(required=True,
@ -58,6 +64,7 @@ class AudienciaForm(forms.ModelForm):
def clean(self):
cleaned_data = super(AudienciaForm, self).clean()
if not self.is_valid():
return cleaned_data
@ -68,6 +75,7 @@ class AudienciaForm(forms.ModelForm):
if materia and ano_materia and tipo_materia:
try:
self.logger.debug("Tentando obter MateriaLegislativa %s%s/%s." % (tipo_materia, materia, ano_materia))
materia = MateriaLegislativa.objects.get(
numero=materia,
ano=ano_materia,
@ -75,14 +83,19 @@ class AudienciaForm(forms.ModelForm):
except ObjectDoesNotExist:
msg = _('A matéria %s%s/%s não existe no cadastro'
' de matérias legislativas.' % (tipo_materia, materia, ano_materia))
self.logger.error('A MateriaLegislativa %s%s/%s não existe no cadastro'
' de matérias legislativas.' % (tipo_materia, materia, ano_materia))
raise ValidationError(msg)
else:
self.logger.info("MateriaLegislativa %s%s/%s obtida com sucesso." % (tipo_materia, materia, ano_materia))
cleaned_data['materia'] = materia
else:
campos = [materia, tipo_materia, ano_materia]
if campos.count(None) + campos.count('') < len(campos):
msg = _('Preencha todos os campos relacionados à Matéria Legislativa')
self.logger.error('Algum campo relacionado à MatériaLegislativa %s%s/%s \
não foi preenchido.' % (tipo_materia, materia, ano_materia))
raise ValidationError(msg)
if not cleaned_data['numero']:
@ -98,7 +111,32 @@ class AudienciaForm(forms.ModelForm):
if self.cleaned_data['hora_inicio'] and self.cleaned_data['hora_fim']:
if (self.cleaned_data['hora_fim'] <
self.cleaned_data['hora_inicio']):
msg = _('A hora de fim não pode ser anterior a hora de início')
msg = _('A hora de fim ({}) não pode ser anterior a hora '
'de início({})'.format(self.cleaned_data['hora_fim'], self.cleaned_data['hora_inicio']))
self.logger.error('Hora de fim anterior à hora de início.')
raise ValidationError(msg)
return cleaned_data
class AnexoAudienciaPublicaForm(forms.ModelForm):
class Meta:
model = AnexoAudienciaPublica
fields = ['arquivo',
'assunto']
def __init__(self, *args, **kwargs):
row1 = to_row(
[('arquivo', 4)])
row2 = to_row(
[('assunto', 12)])
self.helper = FormHelper()
self.helper.layout = SaplFormLayout(
Fieldset(_('Identificação Básica'),
row1, row2))
super(AnexoAudienciaPublicaForm, self).__init__(
*args, **kwargs)

33
sapl/audiencia/migrations/0007_anexoaudienciapublica.py

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-10-17 20:27
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import sapl.utils
class Migration(migrations.Migration):
dependencies = [
('audiencia', '0006_auto_20180808_0856'),
]
operations = [
migrations.CreateModel(
name='AnexoAudienciaPublica',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nome', models.CharField(max_length=30, verbose_name='Nome')),
('arquivo', models.FileField(blank=True, null=True, upload_to=sapl.utils.texto_upload_path, verbose_name='Arquivo')),
('data', models.DateField(blank=True, null=True, verbose_name='Data')),
('assunto', models.TextField(blank=True, verbose_name='Assunto')),
('indexacao', models.TextField(blank=True)),
('audiencia', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='audiencia.AudienciaPublica')),
],
options={
'verbose_name': 'Documento Acessório',
'verbose_name_plural': 'Documentos Acessórios',
},
),
]

28
sapl/audiencia/migrations/0008_auto_20181023_1051.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8 on 2018-10-23 13:51
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('audiencia', '0007_anexoaudienciapublica'),
]
operations = [
migrations.AlterModelOptions(
name='anexoaudienciapublica',
options={'verbose_name': 'Anexo de Documento Acessório', 'verbose_name_plural': 'Anexo de Documentos Acessórios'},
),
migrations.RemoveField(
model_name='anexoaudienciapublica',
name='nome',
),
migrations.AlterField(
model_name='anexoaudienciapublica',
name='data',
field=models.DateField(auto_now=True, null=True),
),
]

19
sapl/audiencia/migrations/0009_remove_anexoaudienciapublica_indexacao.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8 on 2018-10-23 13:55
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('audiencia', '0008_auto_20181023_1051'),
]
operations = [
migrations.RemoveField(
model_name='anexoaudienciapublica',
name='indexacao',
),
]

46
sapl/audiencia/models.py

@ -1,5 +1,6 @@
import reversion
from django.db import models
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
from sapl.materia.models import MateriaLegislativa
@ -147,3 +148,48 @@ class AudienciaPublica(models.Model):
force_update=force_update,
using=using,
update_fields=update_fields)
@reversion.register()
class AnexoAudienciaPublica(models.Model):
audiencia = models.ForeignKey(AudienciaPublica,
on_delete=models.PROTECT)
arquivo = models.FileField(
blank=True,
null=True,
upload_to=texto_upload_path,
verbose_name=_('Arquivo'))
data = models.DateField(auto_now=timezone.now,blank=True, null=True)
assunto = models.TextField(
blank=True, verbose_name=_('Assunto'))
class Meta:
verbose_name = _('Anexo de Documento Acessório')
verbose_name_plural = _('Anexo de Documentos Acessórios')
def __str__(self):
return self.assunto
def delete(self, using=None, keep_parents=False):
if self.arquivo:
self.arquivo.delete()
return models.Model.delete(
self, using=using, keep_parents=keep_parents)
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
if not self.pk and self.arquivo:
arquivo = self.arquivo
self.arquivo = None
models.Model.save(self, force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields)
self.arquivo = arquivo
return models.Model.save(self, force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields)

5
sapl/audiencia/urls.py

@ -1,10 +1,11 @@
from django.conf.urls import include, url
from sapl.audiencia.views import (index, AudienciaCrud)
from sapl.audiencia.views import (index, AudienciaCrud,AnexoAudienciaPublicaCrud)
from .apps import AppConfig
app_name = AppConfig.name
urlpatterns = [
url(r'^audiencia/', include(AudienciaCrud.get_urls())),
url(r'^audiencia/', include(AudienciaCrud.get_urls() +
AnexoAudienciaPublicaCrud.get_urls())),
]

62
sapl/audiencia/views.py

@ -1,10 +1,13 @@
import sapl
from django.http import HttpResponse
from django.core.urlresolvers import reverse
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.generic import UpdateView
from sapl.crud.base import RP_DETAIL, RP_LIST, Crud
from sapl.crud.base import RP_DETAIL, RP_LIST, Crud, MasterDetailCrud
from .forms import AudienciaForm
from .models import AudienciaPublica
from .forms import AudienciaForm, AnexoAudienciaPublicaForm
from .models import AudienciaPublica, AnexoAudienciaPublica
def index(request):
@ -23,6 +26,23 @@ class AudienciaCrud(Crud):
class ListView(Crud.ListView):
paginate_by = 10
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
audiencia_materia = {}
for o in context['object_list']:
# indexado pelo numero da audiencia
audiencia_materia[str(o.numero)] = o.materia
for row in context['rows']:
coluna_materia = row[3] # se mudar a ordem de listagem mudar aqui
if coluna_materia[0]:
materia = audiencia_materia[row[0][0]]
url_materia = reverse('sapl.materia:materialegislativa_detail',
kwargs={'pk': materia.id})
row[3] = (coluna_materia[0], url_materia)
return context
class CreateView(Crud.CreateView):
form_class = AudienciaForm
@ -52,3 +72,39 @@ class AudienciaCrud(Crud):
return super().get(request, *args, **kwargs)
class AudienciaPublicaMixin:
def has_permission(self):
app_config = sapl.base.models.AppConfig.objects.last()
if app_config and app_config.documentos_administrativos == 'O':
return True
return super().has_permission()
class AnexoAudienciaPublicaCrud(MasterDetailCrud):
model = AnexoAudienciaPublica
parent_field = 'audiencia'
help_topic = 'numeracao_docsacess'
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['assunto']
class CreateView(MasterDetailCrud.CreateView):
form_class = AnexoAudienciaPublicaForm
layout_key = None
class UpdateView(MasterDetailCrud.UpdateView):
form_class = AnexoAudienciaPublicaForm
class ListView(AudienciaPublicaMixin, MasterDetailCrud.ListView):
def get_queryset(self):
qs = super(MasterDetailCrud.ListView, self).get_queryset()
kwargs = {self.crud.parent_field: self.kwargs['pk']}
return qs.filter(**kwargs).order_by('-data', '-id')
class DetailView(AudienciaPublicaMixin,
MasterDetailCrud.DetailView):
pass

93
sapl/base/forms.py

@ -1,4 +1,6 @@
import django_filters
import logging
from crispy_forms.bootstrap import FieldWithButtons, InlineRadios, StrictButton
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Div, Field, Fieldset, Layout, Row
@ -53,7 +55,7 @@ def get_roles():
class UsuarioCreateForm(ModelForm):
logger = logging.getLogger(__name__)
username = forms.CharField(required=True, label="Nome de usuário",
max_length=30)
firstname = forms.CharField(required=True, label="Nome", max_length=30)
@ -81,6 +83,7 @@ class UsuarioCreateForm(ModelForm):
data = self.cleaned_data
if data['password1'] != data['password2']:
self.logger.error('Erro de validação. Senhas informadas ({}, {}) são diferentes.'.format(data['password1'], data['password2']))
raise ValidationError('Senhas informadas são diferentes')
return data
@ -113,8 +116,8 @@ class UsuarioCreateForm(ModelForm):
class UsuarioEditForm(ModelForm):
logger = logging.getLogger(__name__)
# ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')]
ROLES = []
password1 = forms.CharField(required=False, widget=forms.PasswordInput, label='Senha')
@ -155,17 +158,19 @@ class UsuarioEditForm(ModelForm):
data = self.cleaned_data
if data['password1'] and data['password1'] != data['password2']:
self.logger.error('Erro de validação. Senhas informadas ({}, {}) são diferentes.'.format(data['password1'], data['password2']))
raise ValidationError('Senhas informadas são diferentes')
return data
class SessaoLegislativaForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = SessaoLegislativa
exclude = []
def clean(self):
cleaned_data = super(SessaoLegislativaForm, self).clean()
if not self.is_valid():
@ -209,20 +214,29 @@ class SessaoLegislativaForm(ModelForm):
ult = 0
if numero <= ult and flag_edit:
self.logger.error('O número da SessaoLegislativa ({}) é menor ou igual '
'que o de Sessões Legislativas passadas ({})'.format(numero, ult))
raise ValidationError('O número da Sessão Legislativa não pode ser menor ou igual '
'que o de Sessões Legislativas passadas')
if data_inicio < data_inicio_leg or \
data_inicio > data_fim_leg:
self.logger.error('A data de início ({}) da SessaoLegislativa está compreendida '
'fora da data início ({}) e fim ({}) da Legislatura '
'selecionada'.format(data_inicio, data_inicio_leg, data_fim_leg))
raise ValidationError('A data de início da Sessão Legislativa deve estar compreendida '
'entre a data início e fim da Legislatura selecionada')
if data_fim > data_fim_leg or \
data_fim < data_inicio_leg:
self.logger.error('A data de fim ({}) da SessaoLegislativa está compreendida '
'fora da data início ({}) e fim ({}) da Legislatura '
'selecionada.'.format(data_fim, data_inicio_leg, data_fim_leg))
raise ValidationError('A data de fim da Sessão Legislativa deve estar compreendida '
'entre a data início e fim da Legislatura selecionada')
if data_inicio > data_fim:
self.logger.error('Data início ({}) superior à data fim ({}).'.format(data_inicio, data_fim))
raise ValidationError('Data início não pode ser superior à data fim')
data_inicio_intervalo = cleaned_data['data_inicio_intervalo']
@ -230,6 +244,8 @@ class SessaoLegislativaForm(ModelForm):
if data_inicio_intervalo and data_fim_intervalo and \
data_inicio_intervalo > data_fim_intervalo:
self.logger.error('Data início de intervalo ({}) superior à '
'data fim de intervalo ({}).'.format(data_inicio_intervalo, data_fim_intervalo))
raise ValidationError('Data início de intervalo não pode ser '
'superior à data fim de intervalo')
@ -238,6 +254,10 @@ class SessaoLegislativaForm(ModelForm):
data_inicio_intervalo < data_inicio_leg or \
data_inicio_intervalo > data_fim or \
data_inicio_intervalo > data_fim_leg:
self.logger.error('A data de início do intervalo ({}) não está compreendida entre '
'as datas de início ({}) e fim ({}) tanto da Legislatura quanto da '
'própria Sessão Legislativa ({} e {}).'
.format(data_inicio_intervalo, data_inicio_leg, data_fim_leg, data_inicio, data_fim))
raise ValidationError('A data de início do intervalo deve estar compreendida entre '
'as datas de início e fim tanto da Legislatura quanto da '
'própria Sessão Legislativa')
@ -246,6 +266,10 @@ class SessaoLegislativaForm(ModelForm):
data_fim_intervalo > data_fim_leg or \
data_fim_intervalo < data_inicio or \
data_fim_intervalo < data_inicio_leg:
self.logger.error('A data de fim do intervalo ({}) não está compreendida entre '
'as datas de início ({}) e fim ({}) tanto da Legislatura quanto da '
'própria Sessão Legislativa ({} e {}).'
.format(data_fim_intervalo, data_inicio_leg, data_fim_leg, data_inicio, data_fim))
raise ValidationError('A data de fim do intervalo deve estar compreendida entre '
'as datas de início e fim tanto da Legislatura quanto da '
'própria Sessão Legislativa')
@ -262,8 +286,36 @@ class TipoAutorForm(ModelForm):
super(TipoAutorForm, self).__init__(*args, **kwargs)
def clean(self):
super(TipoAutorForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cd = self.cleaned_data
lista = ['comissão',
'comis',
'parlamentar',
'bancada',
'bloco',
'comissao',
'vereador',
'órgão',
'orgao',
'deputado',
'senador',
'vereadora',
'frente']
for l in lista:
if l in cd['descricao'].lower():
raise ValidationError(_('A descrição colocada não pode ser usada '
'por ser equivalente a um tipo já existente'))
class AutorForm(ModelForm):
logger = logging.getLogger(__name__)
senha = forms.CharField(
max_length=20,
label=_('Senha'),
@ -411,6 +463,7 @@ class AutorForm(ModelForm):
def valida_igualdade(self, texto1, texto2, msg):
if texto1 != texto2:
self.logger.error('Textos diferentes. ("{}" e "{}")'.format(texto1, texto2))
raise ValidationError(msg)
return True
@ -424,6 +477,8 @@ class AutorForm(ModelForm):
cd = self.cleaned_data
if 'action_user' not in cd or not cd['action_user']:
self.logger.error('Não Informado se o Autor terá usuário '
'vinculado para acesso ao Sistema.')
raise ValidationError(_('Informe se o Autor terá usuário '
'vinculado para acesso ao Sistema.'))
@ -433,6 +488,10 @@ class AutorForm(ModelForm):
self.instance.user,
get_user_model().USERNAME_FIELD) != cd['username']:
if 'status_user' not in cd or not cd['status_user']:
self.logger.error('Foi trocado ou removido o usuário deste Autor ({}), '
'mas não foi informado como se deve proceder '
'com o usuário que está sendo desvinculado? ({})'
.format(cd['username'], get_user_model().USERNAME_FIELD))
raise ValidationError(
_('Foi trocado ou removido o usuário deste Autor, '
'mas não foi informado como se deve proceder '
@ -449,6 +508,7 @@ class AutorForm(ModelForm):
if cd['action_user'] == 'A':
param_username = {get_user_model().USERNAME_FIELD: cd['username']}
if not User.objects.filter(**param_username).exists():
self.logger.error('Não existe usuário com username "%s". ' % cd['username'])
raise ValidationError(
_('Não existe usuário com username "%s". '
'Para utilizar esse username você deve selecionar '
@ -457,11 +517,13 @@ class AutorForm(ModelForm):
if cd['action_user'] != 'N':
if 'username' not in cd or not cd['username']:
self.logger.error('Username não informado.')
raise ValidationError(_('O username deve ser informado.'))
param_username = {
'user__' + get_user_model().USERNAME_FIELD: cd['username']}
if qs_autor.filter(**param_username).exists():
self.logger.error('Já existe um Autor para este usuário ({}).'.format(cd['username']))
raise ValidationError(
_('Já existe um Autor para este usuário.'))
@ -471,6 +533,7 @@ class AutorForm(ModelForm):
ainda assim para renderizar um message.danger no topo do form.
"""
if 'tipo' not in cd or not cd['tipo']:
self.logger.error('Tipo do Autor não selecionado.')
raise ValidationError(
_('O Tipo do Autor deve ser selecionado.'))
@ -478,16 +541,21 @@ class AutorForm(ModelForm):
if not tipo.content_type:
if 'nome' not in cd or not cd['nome']:
self.logger.error('Nome do Autor não informado.')
raise ValidationError(
_('O Nome do Autor deve ser informado.'))
else:
if 'autor_related' not in cd or not cd['autor_related']:
self.logger.error('Registro de %s não escolhido para ser '
'vinculado ao cadastro de Autor' % tipo.descricao)
raise ValidationError(
_('Um registro de %s deve ser escolhido para ser '
'vinculado ao cadastro de Autor') % tipo.descricao)
if not tipo.content_type.model_class().objects.filter(
pk=cd['autor_related']).exists():
self.logger.error('O Registro definido (%s-%s) não está na base '
'de %s.' % (cd['autor_related'], cd['q'], tipo.descricao))
raise ValidationError(
_('O Registro definido (%s-%s) não está na base de %s.'
) % (cd['autor_related'], cd['q'], tipo.descricao))
@ -497,6 +565,8 @@ class AutorForm(ModelForm):
content_type_id=cd['tipo'].content_type_id)
if qs_autor_selected.exists():
autor = qs_autor_selected.first()
self.logger.error('Já existe um autor Cadastrado para '
'%s' % autor.autor_related)
raise ValidationError(
_('Já existe um autor Cadastrado para %s'
) % autor.autor_related)
@ -967,6 +1037,7 @@ class LoginForm(AuthenticationForm):
class ConfiguracoesAppForm(ModelForm):
logger = logging.getLogger(__name__)
mostrar_brasao_painel = forms.BooleanField(
help_text=_('Sugerimos fortemente que faça o upload de imagens com '
@ -1005,9 +1076,12 @@ class ConfiguracoesAppForm(ModelForm):
casa = CasaLegislativa.objects.first()
if not casa:
raise ValidationError("Não há casa legislativa relacionada")
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):
self.logger.error('Não há logitipo configurado para esta '
'CasaLegislativa ({}).'.format(casa))
raise ValidationError("Não há logitipo configurado para esta "
"Casa legislativa.")
@ -1016,6 +1090,8 @@ class ConfiguracoesAppForm(ModelForm):
class RecuperarSenhaForm(PasswordResetForm):
logger = logging.getLogger(__name__)
def __init__(self, *args, **kwargs):
row1 = to_row(
[('email', 12)])
@ -1039,6 +1115,8 @@ class RecuperarSenhaForm(PasswordResetForm):
if not email_existente:
msg = 'Não existe nenhum usuário cadastrado com este e-mail.'
self.logger.error('Não existe nenhum usuário cadastrado com este e-mail ({}).'
.format(self.data['email']))
raise ValidationError(msg)
return self.cleaned_data
@ -1061,6 +1139,7 @@ class NovaSenhaForm(SetPasswordForm):
class AlterarSenhaForm(Form):
logger = logging.getLogger(__name__)
username = forms.CharField(widget=forms.HiddenInput())
@ -1104,6 +1183,7 @@ class AlterarSenhaForm(Form):
new_password2 = data['new_password2']
if new_password1 != new_password2:
self.logger.error("'Nova Senha' ({}) diferente de 'Confirmar Senha' ({})".format(new_password1, new_password2))
raise ValidationError("'Nova Senha' diferente de 'Confirmar Senha'")
# TODO: colocar mais regras como: tamanho mínimo,
@ -1111,6 +1191,7 @@ class AlterarSenhaForm(Form):
# TODO: senha atual igual a senha anterior, etc
if len(new_password1) < 6:
self.logger.error('A senha informada ({}) não tem o mínimo de 6 caracteres.'.format(new_password1))
raise ValidationError("A senha informada deve ter no mínimo 6 caracteres")
username = data['username']
@ -1118,13 +1199,17 @@ class AlterarSenhaForm(Form):
user = User.objects.get(username=username)
if user.is_anonymous():
self.logger.error('Não é possível alterar senha de usuário anônimo ({}).'.format(username))
raise ValidationError("Não é possível alterar senha de usuário anônimo")
if not user.check_password(old_password):
self.logger.error('Senha atual informada ({}) não confere '
'com a senha armazenada.'.format(old_password))
raise ValidationError("Senha atual informada não confere "
"com a senha armazenada")
if user.check_password(new_password1):
self.logger.error('Nova senha ({}) igual à senha anterior.'.format(new_password1))
raise ValidationError("Nova senha não pode ser igual à senha anterior")
return self.cleaned_data

22
sapl/base/templatetags/common_tags.py

@ -6,7 +6,7 @@ from sapl.base.models import AppConfig
from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa, Proposicao
from sapl.norma.models import NormaJuridica
from sapl.parlamentares.models import Filiacao
from sapl.utils import filiacao_data
from sapl.utils import filiacao_data, SEPARADOR_HASH_PROPOSICAO
register = template.Library()
@ -96,7 +96,12 @@ def isinst(value, class_str):
@register.filter
@stringfilter
def strip_hash(value):
return value.split('/')[0][1:]
vet = value.split('/')
if len(vet) == 2:
return vet[0][1:]
else:
return value.split(SEPARADOR_HASH_PROPOSICAO)[0][1:]
@register.filter
@ -198,6 +203,19 @@ def url(value):
return True
return False
@register.filter
def audio_url(value):
return True if url(value) and value.endswith("mp3") else False
@register.filter
def video_url(value):
return True if url(value) and value.endswith("mp4") else False
@register.filter
def file_extension(value):
import pathlib
return pathlib.Path(value).suffix.replace('.', '')
@register.filter
def cronometro_to_seconds(value):

8
sapl/base/tests/teststub_urls.py

@ -1,11 +1,9 @@
from django.conf.urls import patterns, url
from django.conf.urls import url
from django.views.generic.base import TemplateView
from sapl.urls import urlpatterns as original_patterns
ptrn = patterns('',
url(r'^zzzz$',
ptrn = [url(r'^zzzz$',
TemplateView.as_view(
template_name='index.html'), name='zzzz'))
template_name='index.html'), name='zzzz')]
urlpatterns = original_patterns + ptrn

40
sapl/base/views.py

@ -1,4 +1,5 @@
import os
import logging
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import PermissionRequiredMixin
@ -146,6 +147,7 @@ class AutorCrud(CrudAux):
return CrudAux.DeleteView.delete(self, *args, **kwargs)
class UpdateView(CrudAux.UpdateView):
logger = logging.getLogger(__name__)
layout_key = None
form_class = AutorForm
@ -164,10 +166,13 @@ class AutorCrud(CrudAux):
return CrudAux.UpdateView.get(self, request, *args, **kwargs)
def get_success_url(self):
username = self.request.user.username
pk_autor = self.object.id
url_reverse = reverse('sapl.base:autor_detail',
kwargs={'pk': pk_autor})
try:
self.logger.debug('user=' + username + '. Enviando email na edição de Autores.')
kwargs = {}
user = self.object.user
@ -194,12 +199,13 @@ class AutorCrud(CrudAux):
destinatario = [user.email]
send_mail(assunto, mensagem, remetente, destinatario,
fail_silently=False)
except:
print(
_('Erro no envio de email na edição de Autores.'))
except Exception as e:
self.logger.error('user=' + username + '. Erro no envio de email na edição de Autores. ' + str(e))
return url_reverse
class CreateView(CrudAux.CreateView):
logger = logging.getLogger(__name__)
form_class = AutorForm
layout_key = None
@ -214,10 +220,14 @@ class AutorCrud(CrudAux):
return CrudAux.CreateView.get(self, request, *args, **kwargs)
def get_success_url(self):
username = self.request.user.username
pk_autor = self.object.id
url_reverse = reverse('sapl.base:autor_detail',
kwargs={'pk': pk_autor})
try:
self.logger.debug('user=' + username + '. Enviando email na criação de Autores.')
kwargs = {}
user = self.object.user
@ -244,9 +254,11 @@ class AutorCrud(CrudAux):
destinatario = [user.email]
send_mail(assunto, mensagem, remetente, destinatario,
fail_silently=False)
except:
except Exception as e:
print(
_('Erro no envio de email na criação de Autores.'))
self.logger.error('user=' + username + '. Erro no envio de email na criação de Autores. ' + str(e))
return url_reverse
@ -276,11 +288,13 @@ class RelatorioAtasView(FilterView):
class RelatorioPresencaSessaoView(FilterView):
logger = logging.getLogger(__name__)
model = SessaoPlenaria
filterset_class = RelatorioPresencaSessaoFilterSet
template_name = 'base/RelatorioPresencaSessao_filter.html'
def get_context_data(self, **kwargs):
context = super(RelatorioPresencaSessaoView,
self).get_context_data(**kwargs)
context['title'] = _('Presença dos parlamentares nas sessões')
@ -289,7 +303,6 @@ class RelatorioPresencaSessaoView(FilterView):
if not self.filterset.form.is_valid():
return context
# =====================================================================
# if 'salvar' not in self.request.GET:
where = context['object_list'].query.where
_range = where.children[0].rhs
@ -323,6 +336,8 @@ class RelatorioPresencaSessaoView(FilterView):
total_sessao = context['object_list'].count()
username = self.request.user.username
# Completa o dicionario as informacoes parlamentar/sessao/ordem
parlamentares_presencas = []
for i, p in enumerate(parlamentares_qs):
@ -332,12 +347,18 @@ class RelatorioPresencaSessaoView(FilterView):
'ordemdia_porc': 0
})
try:
self.logger.debug('user=' + username + '. Tentando obter presença do parlamentar (pk={}).'.format(p.id))
sessao_count = presenca_sessao.get(parlamentar_id=p.id)[1]
except ObjectDoesNotExist:
except ObjectDoesNotExist as e:
self.logger.error('user=' + username + '. Erro ao obter presença do parlamentar (pk={}). Definido como 0. '.format(p.id) + str(e))
sessao_count = 0
try:
# Presenças de cada Ordem do Dia
self.logger.info('user=' + username + '. Tentando obter PresencaOrdemDia para o parlamentar pk={}.'.format(p.id))
ordemdia_count = presenca_ordem.get(parlamentar_id=p.id)[1]
except ObjectDoesNotExist:
self.logger.error('user=' + username + '. Erro ao obter PresencaOrdemDia para o parlamentar pk={}. '
'Definido como 0.'.format(p.id))
ordemdia_count = 0
parlamentares_presencas[i].update({
@ -847,12 +868,17 @@ class CasaLegislativaCrud(CrudAux):
class HelpTopicView(TemplateView):
logger = logging.getLogger(__name__)
def get_template_names(self):
username = self.request.user.username
topico = self.kwargs['topic']
try:
self.logger.debug('user=' + username + '. Tentando obter template %s.html.' % topico)
get_template('ajuda/%s.html' % topico)
except TemplateDoesNotExist:
except TemplateDoesNotExist as e:
self.logger.error('user=' + username + '. Erro ao obter template {}.html. Template não existe. '.format(topico) + str(e))
raise Http404()
return ['ajuda/%s.html' % topico]

46
sapl/comissoes/forms.py

@ -1,3 +1,5 @@
import logging
from django import forms
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
@ -14,7 +16,7 @@ from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar
class ComposicaoForm(forms.ModelForm):
comissao = forms.CharField(required=False, label='Comissao', widget=forms.HiddenInput())
logger = logging.getLogger(__name__)
class Meta:
model = Composicao
exclude = []
@ -39,6 +41,9 @@ class ComposicaoForm(forms.ModelForm):
comissao_id=comissao_pk)
if intersecao_periodo:
self.logger.error('O período informado ({} a {})'
'choca com períodos já '
'cadastrados para esta comissão'.format(periodo.data_inicio, periodo.data_fim))
raise ValidationError('O período informado '
'choca com períodos já '
'cadastrados para esta comissão')
@ -48,6 +53,7 @@ class ComposicaoForm(forms.ModelForm):
class PeriodoForm(forms.ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = Periodo
exclude = []
@ -62,6 +68,8 @@ class PeriodoForm(forms.ModelForm):
data_fim = cleaned_data['data_fim']
if data_fim and data_fim < data_inicio:
self.logger.error('A Data Final ({}) é menor que '
'a Data Inicial({}).'.format(data_fim, data_inicio))
raise ValidationError('A Data Final não pode ser menor que '
'a Data Inicial')
@ -74,6 +82,9 @@ class PeriodoForm(forms.ModelForm):
)
if not legislatura:
self.logger.error('O período informado ({} a {})'
'não está contido em uma única '
'legislatura existente'.format(data_inicio, data_fim))
raise ValidationError('O período informado '
'deve estar contido em uma única '
'legislatura existente')
@ -85,6 +96,7 @@ class PeriodoForm(forms.ModelForm):
class ParticipacaoCreateForm(forms.ModelForm):
logger = logging.getLogger(__name__)
parent_pk = forms.CharField(required=False) # widget=forms.HiddenInput())
class Meta:
@ -136,6 +148,8 @@ class ParticipacaoCreateForm(forms.ModelForm):
if data_desligamento and \
data_designacao > data_desligamento:
self.logger.error('Data de designação ({}) superior '
'à data de desligamento ({})'.format(data_designacao, data_desligamento))
raise ValidationError(_('Data de designação não pode ser superior '
'à data de desligamento'))
@ -144,6 +158,7 @@ class ParticipacaoCreateForm(forms.ModelForm):
if cleaned_data['cargo'].nome in cargos_unicos:
msg = _('Este cargo é único para esta Comissão.')
self.logger.error('Este cargo ({}) é único para esta Comissão.'.format(cleaned_data['cargo'].nome))
raise ValidationError(msg)
return cleaned_data
@ -190,6 +205,7 @@ class ParticipacaoCreateForm(forms.ModelForm):
class ParticipacaoEditForm(forms.ModelForm):
logger = logging.getLogger(__name__)
parent_pk = forms.CharField(required=False) # widget=forms.HiddenInput())
nome_parlamentar = forms.CharField(required=False, label='Parlamentar')
@ -219,6 +235,8 @@ class ParticipacaoEditForm(forms.ModelForm):
if data_desligamento and \
data_designacao > data_desligamento:
self.logger.error('Data de designação ({}) superior '
'à data de desligamento ({})'.format(data_designacao, data_desligamento))
raise ValidationError(_('Data de designação não pode ser superior '
'à data de desligamento'))
@ -229,6 +247,8 @@ class ParticipacaoEditForm(forms.ModelForm):
if cleaned_data['cargo'].nome in cargos_unicos:
msg = _('Este cargo é único para esta Comissão.')
self.logger.error('Este cargo ({}) é único para esta Comissão (id={}).'
.format(cleaned_data['cargo'].nome, composicao_id))
raise ValidationError(msg)
return cleaned_data
@ -236,6 +256,7 @@ class ParticipacaoEditForm(forms.ModelForm):
class ComissaoForm(forms.ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = Comissao
fields = '__all__'
@ -260,37 +281,50 @@ class ComissaoForm(forms.ModelForm):
return self.cleaned_data
if len(self.cleaned_data['nome']) > 100:
msg = _('Nome da Comissão deve ter no máximo 50 caracteres.')
msg = _('Nome da Comissão informado ({}) tem mais de 50 caracteres.'.format(self.cleaned_data['nome']))
self.logger.error('Nome da Comissão deve ter no máximo 50 caracteres.')
raise ValidationError(msg)
if (self.cleaned_data['data_extincao'] and
self.cleaned_data['data_extincao'] <
self.cleaned_data['data_criacao']):
msg = _('Data de extinção não pode ser menor que a de criação')
self.logger.error('Data de extinção ({}) não pode ser menor que a de criação ({}).'
.format(self.cleaned_data['data_extincao'],self.cleaned_data['data_criacao']))
raise ValidationError(msg)
if (self.cleaned_data['data_final_prevista_temp'] and
self.cleaned_data['data_final_prevista_temp'] <
self.cleaned_data['data_criacao']):
msg = _('Data Prevista para Término não pode ser menor que a de criação')
self.logger.error('Data Prevista para Término ({}) não pode ser menor que a de criação ({}).'
.format(self.cleaned_data['data_final_prevista_temp'], self.cleaned_data['data_criacao']))
raise ValidationError(msg)
if (self.cleaned_data['data_prorrogada_temp'] and
self.cleaned_data['data_prorrogada_temp'] <
self.cleaned_data['data_criacao']):
msg = _('Data Novo Prazo não pode ser menor que a de criação')
self.logger.error('Data Novo Prazo ({}) não pode ser menor que a de criação ({}).'
.format(self.cleaned_data['data_prorrogada_temp'], self.cleaned_data['data_criacao']))
raise ValidationError(msg)
if (self.cleaned_data['data_instalacao_temp'] and
self.cleaned_data['data_instalacao_temp'] <
self.cleaned_data['data_criacao']):
msg = _('Data de Instalação não pode ser menor que a de criação')
self.logger.error('Data de Instalação ({}) não pode ser menor que a de criação ({}).'
.format(self.cleaned_data['data_instalacao_temp'], self.cleaned_data['data_criacao']))
raise ValidationError(msg)
if (self.cleaned_data['data_final_prevista_temp'] and self.cleaned_data['data_instalacao_temp'] and
self.cleaned_data['data_final_prevista_temp'] <
self.cleaned_data['data_instalacao_temp']):
msg = _('Data Prevista para Término não pode ser menor que a de Instalação')
msg = _('Data Prevista para Término não pode ser menor que a de Instalação.')
self.logger.error('Data Prevista para Término ({}) não pode ser menor que a de Instalação ({}).'
.format(self.cleaned_data['data_final_prevista_temp'], self.cleaned_data['data_instalacao_temp']))
raise ValidationError(msg)
if (self.cleaned_data['data_prorrogada_temp'] and self.cleaned_data['data_instalacao_temp'] and
self.cleaned_data['data_prorrogada_temp'] <
self.cleaned_data['data_instalacao_temp']):
msg = _('Data Novo Prazo não pode ser menor que a de Instalação')
msg = _('Data Novo Prazo não pode ser menor que a de Instalação.')
self.logger.error('Data Novo Prazo ({}) não pode ser menor que a de Instalação ({}).'
.format(self.cleaned_data['data_prorrogada_temp'], self.cleaned_data['data_instalacao_temp']))
raise ValidationError(msg)
return self.cleaned_data
@ -317,6 +351,7 @@ class ComissaoForm(forms.ModelForm):
class ReuniaoForm(ModelForm):
logger = logging.getLogger(__name__)
comissao = forms.ModelChoiceField(queryset=Comissao.objects.all(),
widget=forms.HiddenInput())
@ -327,6 +362,7 @@ class ReuniaoForm(ModelForm):
def clean(self):
super(ReuniaoForm, self).clean()
if not self.is_valid():
return self.cleaned_data
@ -334,6 +370,8 @@ class ReuniaoForm(ModelForm):
if (self.cleaned_data['hora_fim'] <
self.cleaned_data['hora_inicio']):
msg = _('A hora de término da reunião não pode ser menor que a de início')
self.logger.error("A hora de término da reunião ({}) não pode ser menor que a de início ({})."
.format(self.cleaned_data['hora_fim'], self.cleaned_data['hora_inicio']))
raise ValidationError(msg)
return self.cleaned_data

1
sapl/comissoes/tests/test_comissoes.py

@ -74,6 +74,7 @@ def test_incluir_comissao_submit(admin_client):
'nome': 'Comissão Teste',
'sigla': 'CT',
'data_criacao': '2016-03-22',
'unidade_deliberativa': True,
'salvar': 'salvar'},
follow=True)
assert response.status_code == 200

15
sapl/comissoes/views.py

@ -1,3 +1,4 @@
import logging
from django.core.urlresolvers import reverse
from django.db.models import F
@ -102,13 +103,18 @@ class ComposicaoCrud(MasterDetailCrud):
return {'comissao': comissao}
class ListView(MasterDetailCrud.ListView):
logger = logging.getLogger(__name__)
template_name = "comissoes/composicao_list.html"
paginate_by = None
def take_composicao_pk(self):
username = self.request.user.username
try:
self.logger.debug('user=' + username + '. Tentando obter pk da composição.')
return int(self.request.GET['pk'])
except:
except Exception as e:
self.logger.error('user=' + username + '. Erro ao obter pk da composição. Retornado 0. ' + str(e))
return 0
def get_context_data(self, **kwargs):
@ -193,12 +199,17 @@ class ReuniaoCrud(MasterDetailCrud):
list_field_names = ['data', 'nome', 'tema']
class ListView(MasterDetailCrud.ListView):
logger = logging.getLogger(__name__)
paginate_by = 10
def take_reuniao_pk(self):
username = self.request.user.username
try:
self.logger.debug('user=' + username + '. Tentando obter pk da reunião.')
return int(self.request.GET['pk'])
except:
except Exception as e:
self.logger.error('user=' + username + '. Erro ao obter pk da reunião. Retornado 0. ' + str(e))
return 0
def get_context_data(self, **kwargs):

73
sapl/compilacao/views.py

@ -1,6 +1,7 @@
from collections import OrderedDict
from datetime import timedelta
import sys
import logging
from braces.views import FormMessagesMixin
from django import forms
@ -650,6 +651,7 @@ class NotaMixin(DispositivoSuccessUrlMixin):
class NotasCreateView(NotaMixin, CreateView):
logger = logging.getLogger(__name__)
template_name = 'compilacao/ajax_form.html'
form_class = NotaForm
permission_required = 'compilacao.add_nota'
@ -662,6 +664,8 @@ class NotasCreateView(NotaMixin, CreateView):
return super(NotasCreateView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
username = request.user.username
self.object = None
try:
ta_id = kwargs.pop('ta_id')
@ -679,7 +683,9 @@ class NotasCreateView(NotaMixin, CreateView):
else:
return self.form_invalid(form)
except Exception as e:
self.logger.error("user=" + username + ". " + str(e))
print(e)
self.logger.error("user=" + username + ". Error post.")
return HttpResponse("error post")
@ -1469,6 +1475,8 @@ class ActionDragAndMoveDispositivoAlteradoMixin(ActionsCommonsMixin):
class ActionDeleteDispositivoMixin(ActionsCommonsMixin):
logger = logging.getLogger(__name__)
def json_delete_item_dispositivo(self, context):
return self.json_delete_bloco_dispositivo(context, bloco=False)
@ -1516,6 +1524,7 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin):
return data
def remover_dispositivo(self, base, bloco):
username = self.request.user.username
base_ordem = base.ordem
if base.dispositivo_subsequente or base.dispositivo_substituido:
p = base.dispositivo_substituido
@ -1541,6 +1550,7 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin):
p.dispositivos_filhos_set.add(d)
p.save()
except Exception as e:
self.logger.error("user=" + username + '. ' + str(e))
print(e)
base.delete()
else:
@ -1575,6 +1585,8 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin):
dispositivo_pai=base).first()
if not anterior:
self.logger.error("user=" + username + ". Não é possível excluir este Dispositivo (id={}) sem"
" excluir toda a sua estrutura!!!".format(base.ta_id))
raise Exception(
_('Não é possível excluir este Dispositivo sem'
' excluir toda a sua estrutura!!!'))
@ -1594,6 +1606,9 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin):
for candidato in parents:
if candidato == base:
self.logger.error("user=" + username + ". Não é possível excluir este "
"Dispositivo ({}) sem "
"excluir toda a sua estrutura!!!".format(candidato))
raise Exception(
_('Não é possível excluir este '
'Dispositivo sem '
@ -1629,7 +1644,9 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin):
d.rotulo = d.rotulo_padrao()
break
else:
self.logger.error("user=" + username + ". Não é possível excluir este "
"Dispositivo ({}) sem excluir toda "
"a sua estrutura!!!".format(candidato))
raise Exception(
_('Não é possível excluir este '
'Dispositivo sem '
@ -1675,7 +1692,8 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin):
profundidade=profundidade_base)
irmao.rotulo = irmao.rotulo_padrao()
irmao.save()
except:
except Exception as e:
self.logger.error("user=" + username + "." + str(e))
break
irmaos = pai_base.dispositivos_filhos_set.\
@ -1792,7 +1810,8 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin):
dr.rotulo = dr.rotulo_padrao()
try:
dr.save(clean=base != dr)
except:
except Exception as e:
self.logger.error("user=" + username + ". " + str(e))
break
# Pode não ser religavável
@ -1836,6 +1855,8 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin):
class ActionDispositivoCreateMixin(ActionsCommonsMixin):
logger = logging.getLogger(__name__)
def allowed_inserts(self, _base=None):
request = self.request
try:
@ -2090,6 +2111,8 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin):
return result
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
print(e)
return {}
@ -2097,7 +2120,6 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin):
def json_set_dvt(self, context):
# Dispositivo de Vigência do Texto Original e de Dpts Alterados
dvt = Dispositivo.objects.get(pk=self.kwargs['dispositivo_id'])
if dvt.auto_inserido:
dvt = dvt.dispositivo_pai
@ -2136,8 +2158,11 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin):
'com sucesso!!!'))
return data
except:
except Exception as e:
data = {}
username = self.request.user.username
self.logger.error("user=" + username + ". Ocorreu um erro ({}) na atualização do "
"Dispositivo de Vigência".format(str(e)))
self.set_message(data,
'success',
_('Ocorreu um erro na atualização do '
@ -2154,6 +2179,7 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin):
def json_add_next(
self,
context, local_add='json_add_next', create_auto_inserts=True):
try:
dp_auto_insert = None
@ -2425,6 +2451,8 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin):
return data
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
print(e)
return {}
@ -2432,6 +2460,7 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin):
class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
ActionDeleteDispositivoMixin,
ActionDispositivoCreateMixin):
logger = logging.getLogger(__name__)
def render_to_json_response(self, context, **response_kwargs):
@ -2698,6 +2727,8 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
_('Dispositivo de Revogação adicionado com sucesso.'))
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
print(e)
data.update({'pk': ndp.pk,
@ -2892,7 +2923,21 @@ class DispositivoSearchFragmentFormView(ListView):
itens.append(item)
return JsonResponse(itens, safe=False)
return ListView.get(self, request, *args, **kwargs)
response = ListView.get(self, request, *args, **kwargs)
if not self.object_list.exists():
messages.info(
request, _('Não foram encontrados resultados '
'com seus critérios de busca!'))
try:
r = response.render()
return response
except Exception as e:
messages.error(request, "Erro - %s" % e)
context = {}
self.template_name = 'compilacao/messages.html'
return self.render_to_response(context)
def get_queryset(self):
try:
@ -3080,7 +3125,7 @@ class DispositivoEdicaoBasicaView(CompMixin, FormMessagesMixin, UpdateView):
'as alterações no Dispositivo')
permission_required = 'compilacao.change_dispositivo_edicao_avancada'
logger = logging.getLogger(__name__)
@property
def cancel_url(self):
return reverse_lazy(
@ -3122,7 +3167,9 @@ class DispositivoEdicaoBasicaView(CompMixin, FormMessagesMixin, UpdateView):
d.set_numero_completo([d.dispositivo0, ] + numero)
d.rotulo = d.rotulo_padrao()
except:
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". Ocorreu erro ({}) na atualização do rótulo.".format(str(e)))
return True, JsonResponse({'message': str(
_('Ocorreu erro na atualização do rótulo'))}, safe=False)
return True, JsonResponse({
@ -3180,6 +3227,7 @@ class DispositivoDefinidorVigenciaView(CompMixin, FormMessagesMixin, FormView):
permission_required = ('compilacao.change_dispositivo_edicao_avancada',
'compilacao.change_dispositivo_de_vigencia_global')
logger = logging.getLogger(__name__)
def get_form_kwargs(self):
kwargs = FormView.get_form_kwargs(self)
@ -3224,7 +3272,9 @@ class DispositivoDefinidorVigenciaView(CompMixin, FormMessagesMixin, FormView):
d = Dispositivo.objects.get(pk=item)
self.object.dispositivos_vigencias_set.add(d)
return self.form_valid(form)
except:
except Exception as e:
username = request.user.username
self.logger.error("user=" + username + ". " + str(e))
return self.form_invalid(form)
else:
return self.form_invalid(form)
@ -3239,6 +3289,7 @@ class DispositivoEdicaoAlteracaoView(CompMixin, FormMessagesMixin, UpdateView):
'as alterações no Dispositivo')
permission_required = 'compilacao.change_dispositivo_registros_compilacao'
logger = logging.getLogger(__name__)
@property
def cancel_url(self):
@ -3262,7 +3313,9 @@ class DispositivoEdicaoAlteracaoView(CompMixin, FormMessagesMixin, UpdateView):
try:
with transaction.atomic():
return self.form_valid(form)
except:
except Exception as e:
username = request.user.username
self.logger.error("user=" + username + ". " + str(e))
return self.form_invalid(form)
else:
return self.form_invalid(form)

57
sapl/crud/base.py

@ -1,4 +1,4 @@
import logging
from braces.views import FormMessagesMixin
from compressor.utils.decorators import cached_property
from crispy_forms.bootstrap import FieldWithButtons, StrictButton
@ -102,6 +102,7 @@ variáveis do crud:
class SearchMixin(models.Model):
search = models.TextField(blank=True, default='')
logger = logging.getLogger(__name__)
class Meta:
abstract = True
@ -116,7 +117,9 @@ class SearchMixin(models.Model):
if len(fields) == 1:
try:
search += str(getattr(self, str_field)) + ' '
except:
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
pass
else:
_self = self
@ -379,6 +382,7 @@ class CrudBaseMixin(CrispyLayoutFormMixin):
class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
permission_required = (RP_LIST, )
logger = logging.getLogger(__name__)
@classmethod
def get_url_regex(cls):
@ -552,7 +556,9 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
fm = None
try:
fm = model._meta.get_field(fo)
except:
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
pass
if fm and hasattr(fm, 'related_model')\
@ -597,6 +603,7 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
class CrudCreateView(PermissionRequiredContainerCrudMixin,
FormMessagesMixin, CreateView):
permission_required = (RP_ADD, )
logger = logging.getLogger(__name__)
@classmethod
def get_url_regex(cls):
@ -621,7 +628,9 @@ class CrudCreateView(PermissionRequiredContainerCrudMixin,
try:
self.object.owner = self.request.user
self.object.modifier = self.request.user
except:
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
pass
if self.container_field:
@ -668,6 +677,7 @@ class CrudDetailView(PermissionRequiredContainerCrudMixin,
permission_required = (RP_DETAIL, )
no_entries_msg = _('Nenhum registro Associado.')
paginate_by = 10
logger = logging.getLogger(__name__)
@classmethod
def get_url_regex(cls):
@ -690,7 +700,9 @@ class CrudDetailView(PermissionRequiredContainerCrudMixin,
self.object, obj.model_set).model._meta.get_field(
fieldname).related_model._meta.verbose_name_plural)
for fieldname in self.list_field_names_set]
except:
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
obj = self.crud if hasattr(self, 'crud') else self
return [getattr(
self.object,
@ -717,7 +729,9 @@ class CrudDetailView(PermissionRequiredContainerCrudMixin,
self.resolve_model_set_url(ACTION_DETAIL, args=(obj.id,))
if i == 0 else None)
for i, name in enumerate(self.list_field_names_set)]
except:
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
return [(
getattr(obj, name),
self.resolve_model_set_url(ACTION_DETAIL, args=(obj.id,))
@ -732,7 +746,9 @@ class CrudDetailView(PermissionRequiredContainerCrudMixin,
def get(self, request, *args, **kwargs):
try:
self.object = self.model.objects.get(pk=kwargs.get('pk'))
except:
except Exception as e:
username = request.user.username
self.logger.error("user=" + username + ". " + str(e))
raise Http404
obj = self.crud if hasattr(self, 'crud') else self
if hasattr(obj, 'model_set') and obj.model_set:
@ -805,12 +821,16 @@ class CrudDetailView(PermissionRequiredContainerCrudMixin,
class CrudUpdateView(PermissionRequiredContainerCrudMixin,
FormMessagesMixin, UpdateView):
permission_required = (RP_CHANGE, )
logger = logging.getLogger(__name__)
def form_valid(self, form):
self.object = form.instance
try:
self.object.modifier = self.request.user
except:
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
pass
return super().form_valid(form)
@ -832,6 +852,7 @@ class CrudUpdateView(PermissionRequiredContainerCrudMixin,
class CrudDeleteView(PermissionRequiredContainerCrudMixin,
FormMessagesMixin, DeleteView):
permission_required = (RP_DELETE, )
logger = logging.getLogger(__name__)
@classmethod
def get_url_regex(cls):
@ -853,12 +874,20 @@ class CrudDeleteView(PermissionRequiredContainerCrudMixin,
error_msg = 'Registro não pode ser removido, pois\
é referenciado por outros registros:<br>\
<ul>'
error_msg2 = ''
for i in err.protected_objects:
error_msg += '<li>{} - {}</li>'.format(
i._meta.verbose_name, i
)
error_msg2 += '{} - {}, '.format(
i._meta.verbose_name, i
)
error_msg2 = error_msg2[:len(error_msg2)-2] + '.'
error_msg += '</ul>'
username = request.user.username
self.logger.error("user=" + username + ". Registro não pode ser removido, pois "
"é referenciado por outros registros: " + error_msg2)
messages.add_message(request,
messages.ERROR,
error_msg)
@ -1062,12 +1091,14 @@ class MasterDetailCrud(Crud):
class ListView(Crud.ListView):
permission_required = RP_LIST,
logger = logging.getLogger(__name__)
@classmethod
def get_url_regex(cls):
return r'^(?P<pk>\d+)/%s$' % cls.model._meta.model_name
def get_context_data(self, **kwargs):
obj = self.crud if hasattr(self, 'crud') else self
context = CrudListView.get_context_data(self, **kwargs)
@ -1098,7 +1129,9 @@ class MasterDetailCrud(Crud):
try:
parent_object = parent_model.objects.get(**params)
except:
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
raise Http404()
context[
@ -1119,6 +1152,7 @@ class MasterDetailCrud(Crud):
class CreateView(Crud.CreateView):
permission_required = RP_ADD,
logger = logging.getLogger(__name__)
def dispatch(self, request, *args, **kwargs):
return PermissionRequiredMixin.dispatch(
@ -1144,6 +1178,7 @@ class MasterDetailCrud(Crud):
return form
def get_context_data(self, **kwargs):
obj = self.crud if hasattr(self, 'crud') else self
context = Crud.CreateView.get_context_data(
self, **kwargs)
@ -1161,7 +1196,9 @@ class MasterDetailCrud(Crud):
try:
parent_object = parent_model.objects.get(**params)
except Exception:
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
raise Http404()
else:
parent_model = self.model

6
sapl/legacy/management/commands/ressucitar_deps.py → sapl/legacy/management/commands/ressuscitar_deps.py

@ -1,12 +1,12 @@
from django.core.management.base import BaseCommand
from sapl.legacy.scripts.ressucita_dependencias import adiciona_ressucitar
from sapl.legacy.scripts.ressuscita_dependencias import adiciona_ressuscitar
class Command(BaseCommand):
help = 'Ressucita dependências apagadas ' \
help = 'Ressuscita dependências apagadas ' \
'que são necessárias para migrar outros registros'
def handle(self, *args, **options):
adiciona_ressucitar()
adiciona_ressuscitar()

9
sapl/legacy/migracao.py

@ -70,12 +70,13 @@ def scrap_sde(url, usuario, senha=None):
{'__ac_name': usuario, '__ac_password': senha})
assert res.status_code == 200
url_proposicao = '{}/sapl_documentos/proposicao/{}/renderXML?xsl=__default__' # noqa
url_proposicao_tmpl = '{}/sapl_documentos/proposicao/{}/renderXML?xsl=__default__' # noqa
total = Proposicao.objects.count()
for num, proposicao in enumerate(Proposicao.objects.all()):
pk = proposicao.pk
res = session.get(url_proposicao.format(url, pk))
print("pk: {} status: {} (progresso: {:.2%})".format(
pk, res.status_code, num / total))
url_proposicao = url_proposicao_tmpl.format(url, pk)
res = session.get(url_proposicao)
print("pk: {} status: {} {} (progresso: {:.2%})".format(
pk, res.status_code, url_proposicao, num / total))
if res.status_code == 200:
salva_conteudo_do_sde(proposicao, res.content)

32
sapl/legacy/migracao_dados.py

@ -623,6 +623,36 @@ def corrige_unidades_tramitacao_destino_vazia_como_anterior():
'''.format(tabela_tramitacao))
def apaga_ref_a_mats_e_docs_inexistentes_em_proposicoes():
# as referencias a matérias e documentos apagados não aparecem no 3.1
# além do que, se ressuscitássemos essas matérias e docs,
# não seria possível apagá-los,
# pois é impossível para um usuário não autor acessar as proposicões
# para apagar a referências antes
exec_legado('''
update proposicao set cod_materia = NULL where cod_materia not in (
select cod_materia from materia_legislativa
where ind_excluido <> 1);
''')
props_sem_mats = list(primeira_coluna(exec_legado('''
select cod_proposicao from proposicao p inner join tipo_proposicao t
on p.tip_proposicao = t.tip_proposicao
where t.ind_mat_ou_doc = 'M' and cod_mat_ou_doc not in (
select cod_materia from materia_legislativa
where ind_excluido <> 1)
''')))
props_sem_docs = list(primeira_coluna(exec_legado('''
select cod_proposicao from proposicao p inner join tipo_proposicao t
on p.tip_proposicao = t.tip_proposicao
where t.ind_mat_ou_doc = 'D' and cod_mat_ou_doc not in (
select cod_documento from documento_acessorio
where ind_excluido <> 1);
''')))
exec_legado_em_subconjunto('''
update proposicao set cod_mat_ou_doc = NULL
where cod_proposicao in {}''', props_sem_mats + props_sem_docs)
def uniformiza_banco():
propaga_exclusoes(PROPAGACOES_DE_EXCLUSAO)
checa_registros_votacao_ambiguos_e_remove_nao_usados()
@ -722,6 +752,8 @@ sessao_plenaria_presenca | dat_sessao = NULL | dat_sessao = 0
select cod_materia from materia_legislativa
where ind_excluido <> 1);''')
apaga_ref_a_mats_e_docs_inexistentes_em_proposicoes()
class Record:
pass

7
sapl/legacy/migracao_documentos.py

@ -1,4 +1,5 @@
import os
import shutil
import re
from glob import glob
from os.path import join
@ -52,6 +53,12 @@ def mover_documento(repo, origem, destino, ignora_origem_ausente=False):
if ignora_origem_ausente and not os.path.exists(origem):
print('Origem ignorada ao mover documento: {}'.format(origem))
return
# apaga destino, se houver, e renomeia origem para destino
if os.path.exists(destino):
if os.path.isdir(destino):
shutil.rmtree(destino)
else:
os.remove(destino)
os.makedirs(os.path.dirname(destino), exist_ok=True)
os.rename(origem, destino)

22
sapl/legacy/scripts/ressucita_dependencias.py → sapl/legacy/scripts/ressuscita_dependencias.py

@ -70,6 +70,7 @@ tipo_dependente /sistema/parlamentar/tipo-dependente
origem /sistema/materia/origem
documento_acessorio /materia/documentoacessorio
tipo_fim_relatoria /sistema/materia/tipo-fim-relatoria
tipo_situacao_militar /sistema/parlamentar/tipo-militar
'''
urls = dict(stripsplit(urls))
@ -194,7 +195,7 @@ Para facilitar sua conferência, seguem os links para as proposições envolvida
'''.format(table.draw(), links, sqls)
def get_dependencias_a_ressucitar(slug):
def get_dependencias_a_ressuscitar(slug):
ocorrencias = yaml.load(
Path(DIR_REPO.child('ocorrencias.yaml').read_file()))
fks_faltando = ocorrencias.get('fk')
@ -265,7 +266,7 @@ SQLS_CRIACAO = [
('unidade_tramitacao', '''
insert into unidade_tramitacao (
cod_unid_tramitacao, cod_comissao, cod_orgao, cod_parlamentar, ind_excluido)
values ({}, NULL, NULL, NULL, 0);
values ({}, NULL, NULL, 0, 0);
'''),
('autor', SQL_INSERT_TIPO_AUTOR.format(0) + '''
insert into autor (
@ -307,6 +308,9 @@ SQLS_CRIACAO = [
insert into parlamentar (cod_parlamentar, nom_completo, nom_parlamentar, sex_parlamentar, cod_casa, ind_ativo, ind_unid_deliberativa, ind_excluido)
values ({}, "DESCONHECIDO", "DESCONHECIDO", "M", 0, 0, 0, 0);
'''),
('tipo_sessao_plenaria', '''
insert into tipo_sessao_plenaria (tip_sessao, nom_sessao, ind_excluido, num_minimo) values ({}, "DESCONHECIDO", 0, 0);
'''),
]
SQLS_CRIACAO = {k: (dedent(sql.strip()), extras)
for k, sql, *extras in SQLS_CRIACAO}
@ -349,8 +353,8 @@ def get_sql_criar(tabela_alvo, campo, valor, slug):
return sql, links
TEMPLATE_RESSUCITADOS = '''{}
/* RESSUCITADOS
TEMPLATE_RESSUSCITADOS = '''{}
/* RESSUSCITADOS
SOBRE REGISTROS QUE ESTAVAM APAGADOS E FORAM RESTAURADOS
@ -397,11 +401,11 @@ def get_sqls_desexcluir_criar(preambulo, desexcluir, criar, slug):
links = sem_repeticoes_mantendo_ordem(links)
sqls, links = ['\n'.join(sorted(s)) for s in [sqls, links]]
return TEMPLATE_RESSUCITADOS.format(preambulo, links, sqls)
return TEMPLATE_RESSUSCITADOS.format(preambulo, links, sqls)
def get_ressucitar(slug):
preambulo, desexcluir, criar = get_dependencias_a_ressucitar(slug)
def get_ressuscitar(slug):
preambulo, desexcluir, criar = get_dependencias_a_ressuscitar(slug)
return get_sqls_desexcluir_criar(preambulo, desexcluir, criar, slug)
@ -413,8 +417,8 @@ def get_slug():
return siglas_para_slugs[sigla]
def adiciona_ressucitar():
sqls = get_ressucitar(get_slug())
def adiciona_ressuscitar():
sqls = get_ressuscitar(get_slug())
if sqls.strip():
arq_ajustes_pre_migracao = get_arquivo_ajustes_pre_migracao()
conteudo = arq_ajustes_pre_migracao.read_file()

158
sapl/materia/forms.py

@ -1,6 +1,6 @@
import os
import logging
import django_filters
from crispy_forms.bootstrap import Alert, FormActions, InlineRadios
from crispy_forms.helper import FormHelper
@ -39,7 +39,7 @@ from sapl.norma.models import (LegislacaoCitada, NormaJuridica,
from sapl.parlamentares.models import Legislatura
from sapl.protocoloadm.models import Protocolo, DocumentoAdministrativo
from sapl.settings import MAX_DOC_UPLOAD_SIZE
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, SEPARADOR_HASH_PROPOSICAO,
ChoiceWithoutValidationField,
MateriaPesquisaOrderingFilter, RangeWidgetOverride,
autor_label, autor_modal, gerar_hash_arquivo,
@ -119,6 +119,8 @@ class ReceberProposicaoForm(Form):
class MateriaSimplificadaForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = MateriaLegislativa
fields = ['tipo', 'numero', 'ano', 'data_apresentacao',
@ -156,6 +158,8 @@ class MateriaSimplificadaForm(ModelForm):
ano = cleaned_data['ano']
if data_apresentacao.year != ano:
self.logger.error("O ano da matéria ({}) é diferente"
" do ano na data de apresentação ({}).".format(ano, data_apresentacao.year))
raise ValidationError("O ano da matéria não pode ser "
"diferente do ano na data de apresentação")
@ -164,6 +168,8 @@ class MateriaSimplificadaForm(ModelForm):
class MateriaLegislativaForm(ModelForm):
logger = logging.getLogger(__name__)
tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
required=False,
queryset=TipoAutor.objects.all(),
@ -204,6 +210,8 @@ class MateriaLegislativaForm(ModelForm):
if protocolo:
if not Protocolo.objects.filter(numero=protocolo,ano=ano).exists():
self.logger.error("Protocolo %s/%s não"
" existe" % (protocolo, ano))
raise ValidationError(_('Protocolo %s/%s não'
' existe' % (protocolo, ano)))
@ -217,15 +225,23 @@ class MateriaLegislativaForm(ModelForm):
ano=ano).exists()
if exist_materia or exist_doc:
self.logger.error("Protocolo %s/%s ja possui"
" documento vinculado"
% (protocolo, ano))
raise ValidationError(_('Protocolo %s/%s ja possui'
' documento vinculado'
% (protocolo, ano)))
p = Protocolo.objects.get(numero=protocolo,ano=ano)
if p.tipo_materia != cleaned_data['tipo']:
self.logger.error("Tipo do Protocolo ({}) deve ser o mesmo do Tipo Matéria ({})."
.format(cleaned_data['tipo'], p.tipo_materia))
raise ValidationError(_('Tipo do Protocolo deve ser o mesmo do Tipo Matéria'))
if data_apresentacao.year != ano:
self.logger.error("O ano da matéria ({}) é diferente "
"do ano na data de apresentação ({})."
.format(ano, data_apresentacao.year))
raise ValidationError(_("O ano da matéria não pode ser "
"diferente do ano na data de apresentação"))
@ -234,6 +250,9 @@ class MateriaLegislativaForm(ModelForm):
if ano_origem_externa and data_origem_externa and \
ano_origem_externa != data_origem_externa.year:
self.logger.error("O ano de origem externa da matéria ({}) é "
" diferente do ano na data de origem externa ({})."
.format(ano_origem_externa, data_origem_externa))
raise ValidationError(_("O ano de origem externa da matéria não "
"pode ser diferente do ano na data de "
"origem externa"))
@ -260,6 +279,8 @@ class MateriaLegislativaForm(ModelForm):
class UnidadeTramitacaoForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = UnidadeTramitacao
fields = ['comissao', 'orgao', 'parlamentar']
@ -278,6 +299,7 @@ class UnidadeTramitacaoForm(ModelForm):
if len(cleaned_data) != 1:
msg = _('Somente um campo deve ser preenchido!')
self.logger.error("Somente um campo deve ser preenchido!")
raise ValidationError(msg)
return cleaned_data
@ -329,6 +351,8 @@ class DocumentoAcessorioForm(ModelForm):
class RelatoriaForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = Relatoria
fields = ['data_designacao_relator', 'comissao', 'parlamentar',
@ -348,8 +372,12 @@ class RelatoriaForm(ModelForm):
cleaned_data = self.cleaned_data
try:
self.logger.debug("Tentando obter objeto Comissao.")
comissao = Comissao.objects.get(id=self.initial['comissao'])
except ObjectDoesNotExist:
except ObjectDoesNotExist as e:
self.logger.error("Objeto Comissao não encontrado com id={} "
".A localização atual deve ser uma comissão. "
.format(self.initial['comissao']) + str(e))
msg = _('A localização atual deve ser uma comissão.')
raise ValidationError(msg)
else:
@ -365,6 +393,8 @@ class TramitacaoForm(ModelForm):
initial=False,
label=_("Urgente?"))
logger = logging.getLogger(__name__)
class Meta:
model = Tramitacao
fields = ['data_tramitacao',
@ -407,11 +437,16 @@ class TramitacaoForm(ModelForm):
if ultima_tramitacao:
destino = ultima_tramitacao.unidade_tramitacao_destino
if (destino != self.cleaned_data['unidade_tramitacao_local']):
self.logger.error("A origem da nova tramitação ({}) não é igual ao "
"destino da última adicionada ({})!"
.format(self.cleaned_data['unidade_tramitacao_local'], destino))
msg = _('A origem da nova tramitação deve ser igual ao '
'destino da última adicionada!')
raise ValidationError(msg)
if cleaned_data['data_tramitacao'] > timezone.now().date():
self.logger.error('A data de tramitação informada ({}) não é ' +
'menor ou igual a data de hoje!'.format(cleaned_data['data_tramitacao']))
msg = _(
'A data de tramitação deve ser ' +
'menor ou igual a data de hoje!')
@ -421,18 +456,27 @@ class TramitacaoForm(ModelForm):
data_tram_form < ultima_tramitacao.data_tramitacao):
msg = _('A data da nova tramitação deve ser ' +
'maior que a data da última tramitação!')
self.logger.error("A data da nova tramitação ({}) deve ser "
"maior que a data da última tramitação ({})!"
.format(data_tram_form, ultima_tramitacao.data_tramitacao))
raise ValidationError(msg)
if data_enc_form:
if data_enc_form < data_tram_form:
msg = _('A data de encaminhamento deve ser ' +
'maior que a data de tramitação!')
self.logger.error("A data de encaminhamento ({}) deve ser "
"maior que a data de tramitação! ({})"
.format(data_enc_form, data_tram_form))
raise ValidationError(msg)
if data_prazo_form:
if data_prazo_form < data_tram_form:
msg = _('A data fim de prazo deve ser ' +
'maior que a data de tramitação!')
self.logger.error("A data fim de prazo ({}) deve ser " +
"maior que a data de tramitação ({})!"
.format(data_prazo_form, data_tram_form))
raise ValidationError(msg)
return cleaned_data
@ -445,6 +489,8 @@ class TramitacaoUpdateForm(TramitacaoForm):
data_tramitacao = forms.DateField(widget=forms.HiddenInput())
logger = logging.getLogger(__name__)
class Meta:
model = Tramitacao
fields = ['data_tramitacao',
@ -479,6 +525,11 @@ class TramitacaoUpdateForm(TramitacaoForm):
if ultima_tramitacao != self.instance:
if self.cleaned_data['unidade_tramitacao_destino'] != \
self.instance.unidade_tramitacao_destino:
self.logger.error("Você não pode mudar a Unidade de Destino desta "
"tramitação para {}, pois irá conflitar com a Unidade "
"Local da tramitação seguinte ({})."
.format(self.cleaned_data['unidade_tramitacao_destino'],
self.instance.unidade_tramitacao_destino))
raise ValidationError(
'Você não pode mudar a Unidade de Destino desta '
'tramitação, pois irá conflitar com a Unidade '
@ -505,6 +556,8 @@ class LegislacaoCitadaForm(ModelForm):
ano = forms.CharField(label='Ano', required=True)
logger = logging.getLogger(__name__)
class Meta:
model = LegislacaoCitada
fields = ['tipo',
@ -532,11 +585,16 @@ class LegislacaoCitadaForm(ModelForm):
cleaned_data = self.cleaned_data
try:
self.logger.debug("Tentando obter objeto NormalJuridica (numero={}, ano={}, tipo={})."
.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
norma = NormaJuridica.objects.get(
numero=cleaned_data['numero'],
ano=cleaned_data['ano'],
tipo=cleaned_data['tipo'])
except ObjectDoesNotExist:
self.logger.error("A norma a ser inclusa (numero={}, ano={}, tipo={}) "
"não existe no cadastro de Normas."
.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
msg = _('A norma a ser inclusa não existe no cadastro'
' de Normas.')
raise ValidationError(msg)
@ -562,10 +620,12 @@ class LegislacaoCitadaForm(ModelForm):
if not self.instance.id:
if filtro_base.exists():
msg = _('Essa Legislação já foi cadastrada.')
self.logger.error("Essa Legislação já foi cadastrada.")
raise ValidationError(msg)
else:
if filtro_base.exclude(id=self.instance.id).exists():
msg = _('Essa Legislação já foi cadastrada.')
self.logger.error("Essa Legislação já foi cadastrada.")
raise ValidationError(msg)
return cleaned_data
@ -579,6 +639,7 @@ class LegislacaoCitadaForm(ModelForm):
class NumeracaoForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = Numeracao
fields = ['tipo_materia',
@ -593,6 +654,9 @@ class NumeracaoForm(ModelForm):
return self.cleaned_data
try:
self.logger.info("Tentando obter objeto MateriaLegislativa (numero={}, ano={}. tipo={})."
.format(self.cleaned_data['numero_materia'],
self.cleaned_data['ano_materia'], self.cleaned_data['tipo_materia']))
MateriaLegislativa.objects.get(
numero=self.cleaned_data['numero_materia'],
ano=self.cleaned_data['ano_materia'],
@ -600,6 +664,9 @@ class NumeracaoForm(ModelForm):
except ObjectDoesNotExist:
msg = _('A matéria a ser inclusa não existe no cadastro'
' de matérias legislativas.')
self.logger.error("A MateriaLegislativa a ser inclusa (numero={}, ano={}. tipo={}) não existe no cadastro de matérias legislativas."
.format(self.cleaned_data['numero_materia'],
self.cleaned_data['ano_materia'], self.cleaned_data['tipo_materia']))
raise ValidationError(msg)
if Numeracao.objects.filter(
@ -609,6 +676,9 @@ class NumeracaoForm(ModelForm):
numero_materia=self.cleaned_data['numero_materia']
).exists():
msg = _('Essa numeração já foi cadastrada.')
self.logger.error("Essa numeração (materia={}, tipo_materia={}, ano_materia={}, numero_materia={}) "
"já foi cadastrada.".format(self.instance.materia, self.cleaned_data['tipo_materia'],
self.cleaned_data['ano_materia'], self.cleaned_data['numero_materia']))
raise ValidationError(msg)
return self.cleaned_data
@ -616,6 +686,8 @@ class NumeracaoForm(ModelForm):
class AnexadaForm(ModelForm):
logger = logging.getLogger(__name__)
tipo = forms.ModelChoiceField(
label='Tipo',
required=True,
@ -640,24 +712,30 @@ class AnexadaForm(ModelForm):
cleaned_data = self.cleaned_data
try:
self.logger.info("Tentando obter objeto MateriaLegislativa (numero={}, ano={}, tipo={})."
.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
materia_anexada = MateriaLegislativa.objects.get(
numero=cleaned_data['numero'],
ano=cleaned_data['ano'],
tipo=cleaned_data['tipo'])
except ObjectDoesNotExist:
msg = _('A matéria a ser anexada não existe no cadastro'
' de matérias legislativas.')
msg = _('A MateriaLegislativa a ser anexada (numero={}, ano={}, tipo={}) não existe no cadastro'
' de matérias legislativas.'.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
self.logger.error("A matéria a ser anexada não existe no cadastro"
" de matérias legislativas.")
raise ValidationError(msg)
materia_principal = self.instance.materia_principal
if materia_principal == materia_anexada:
self.logger.error("Matéria não pode ser anexada a si mesma.")
raise ValidationError(_('Matéria não pode ser anexada a si mesma'))
is_anexada = Anexada.objects.filter(materia_principal=materia_principal,
materia_anexada=materia_anexada
).exists()
if is_anexada:
raise ValidationError(_('Materia já se encontra anexada'))
self.logger.error("Matéria já se encontra anexada.")
raise ValidationError(_('Matéria já se encontra anexada'))
cleaned_data['materia_anexada'] = materia_anexada
@ -679,7 +757,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'label': '%s (%s)' % (f.verbose_name, _('Inicial Final')),
'widget': RangeWidgetOverride}
}}
@ -858,6 +936,8 @@ class AutoriaForm(ModelForm):
data_relativa = forms.DateField(
widget=forms.HiddenInput(), required=False)
logger = logging.getLogger(__name__)
def __init__(self, *args, **kwargs):
super(AutoriaForm, self).__init__(*args, **kwargs)
@ -889,6 +969,7 @@ class AutoriaForm(ModelForm):
if ((not pk and autorias.exists()) or
(pk and autorias.exclude(pk=pk).exists())):
self.logger.error("Esse Autor (pk={}) já foi cadastrado.".format(pk))
raise ValidationError(_('Esse Autor já foi cadastrado.'))
return cd
@ -896,6 +977,8 @@ class AutoriaForm(ModelForm):
class AutoriaMultiCreateForm(Form):
logger = logging.getLogger(__name__)
tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
required=False,
queryset=TipoAutor.objects.all(),
@ -937,6 +1020,7 @@ class AutoriaMultiCreateForm(Form):
del self.errors['autores']
if 'autor' not in cd or not cd['autor'].exists():
self.logger.error("Ao menos um autor deve ser selecionado para inclusão")
raise ValidationError(
_('Ao menos um autor deve ser selecionado para inclusão'))
@ -1049,6 +1133,8 @@ class TramitacaoEmLoteFilterSet(django_filters.FilterSet):
class TipoProposicaoForm(ModelForm):
logger = logging.getLogger(__name__)
content_type = forms.ModelChoiceField(
queryset=ContentType.objects.all(),
label=TipoProposicao._meta.get_field('content_type').verbose_name,
@ -1112,11 +1198,14 @@ class TipoProposicaoForm(ModelForm):
if 'tipo_conteudo_related' not in cd or not cd[
'tipo_conteudo_related']:
self.logger.error("Seleção de Tipo não definida.")
raise ValidationError(
_('Seleção de Tipo não definida'))
_('Seleção de Tipo não definida.'))
if not content_type.model_class().objects.filter(
pk=cd['tipo_conteudo_related']).exists():
self.logger.error("O Registro definido (%s) não está na base de %s."
% (cd['tipo_conteudo_related'], content_type))
raise ValidationError(
_('O Registro definido (%s) não está na base de %s.'
) % (cd['tipo_conteudo_related'], content_type))
@ -1180,7 +1269,7 @@ class TipoProposicaoSelect(Select):
str(data_has_perfil),
force_text(option_label))
def render_options(self, choices, selected_choices):
def render_options(self, selected_choices):
# Normalize to strings.
selected_choices = set(force_text(v) for v in selected_choices)
output = []
@ -1200,6 +1289,8 @@ class TipoProposicaoSelect(Select):
class ProposicaoForm(forms.ModelForm):
logger = logging.getLogger(__name__)
TIPO_TEXTO_CHOICE = [
('D', _('Arquivo Digital')),
('T', _('Texto Articulado'))
@ -1320,6 +1411,7 @@ class ProposicaoForm(forms.ModelForm):
texto_original = self.cleaned_data.get('texto_original', False)
if texto_original and texto_original.size > MAX_DOC_UPLOAD_SIZE:
max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024))
self.logger.error("- Arquivo muito grande. ( > {0}MB )".format(max_size))
raise ValidationError(
"Arquivo muito grande. ( > {0}MB )".format(max_size))
return texto_original
@ -1335,8 +1427,7 @@ class ProposicaoForm(forms.ModelForm):
inst.texto_original.path, str(inst.pk))
elif inst.texto_articulado.exists():
ta = inst.texto_articulado.first()
# FIXME hash para textos articulados
inst.hash_code = 'P' + ta.hash() + '/' + str(inst.pk)
inst.hash_code = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(inst.pk)
def clean(self):
super(ProposicaoForm, self).clean()
@ -1352,14 +1443,20 @@ class ProposicaoForm(forms.ModelForm):
if tm and am and nm:
try:
self.logger.debug("Tentando obter objeto MateriaLegislativa (tipo_id={}, ano={}, numero={})."
.format(tm, am, nm))
materia_de_vinculo = MateriaLegislativa.objects.get(
tipo_id=tm,
ano=am,
numero=nm
)
except ObjectDoesNotExist:
self.logger.error("Objeto MateriaLegislativa vinculada (tipo_id={}, ano={}, numero={}) não existe!"
.format(tm, am, nm))
raise ValidationError(_('Matéria Vinculada não existe!'))
else:
self.logger.info("MateriaLegislativa vinculada (tipo_id={}, ano={}, numero={}) com sucesso."
.format(tm, am, nm))
cd['materia_de_vinculo'] = materia_de_vinculo
return cd
@ -1406,6 +1503,8 @@ class DevolverProposicaoForm(forms.ModelForm):
justificativa_devolucao = forms.CharField(
required=False, widget=widgets.Textarea(attrs={'rows': 5}))
logger = logging.getLogger(__name__)
class Meta:
model = Proposicao
fields = [
@ -1446,6 +1545,7 @@ class DevolverProposicaoForm(forms.ModelForm):
if 'justificativa_devolucao' not in cd or\
not cd['justificativa_devolucao']:
# TODO Implementar notificação ao autor por email
self.logger.error("Adicione uma Justificativa para devolução.")
raise ValidationError(
_('Adicione uma Justificativa para devolução.'))
return cd
@ -1538,6 +1638,7 @@ class ConfirmarProposicaoForm(ProposicaoForm):
self.instance = kwargs.get('instance', None)
if not self.instance:
self.logger.error("Erro na Busca por proposição a incorporar")
raise ValueError(_('Erro na Busca por proposição a incorporar'))
if self.instance.tipo.content_type.model_class() == TipoDocumento:
@ -1631,6 +1732,9 @@ class ConfirmarProposicaoForm(ProposicaoForm):
numeracao = sapl.base.models.AppConfig.attr('sequencia_numeracao')
if not numeracao:
self.logger.error("A sequência de numeração (por ano ou geral)"
" não foi configurada para a aplicação em "
"tabelas auxiliares")
raise ValidationError("A sequência de numeração (por ano ou geral)"
" não foi configurada para a aplicação em "
"tabelas auxiliares")
@ -1641,12 +1745,14 @@ class ConfirmarProposicaoForm(ProposicaoForm):
TipoMateriaLegislativa:
if 'regime_tramitacao' not in cd or\
not cd['regime_tramitacao']:
self.logger.error("Regime de Tramitação deve ser informado.")
raise ValidationError(
_('Regime de Tramitação deve ser informado.'))
elif self.instance.tipo.content_type.model_class(
) == TipoDocumento and not cd['materia_de_vinculo']:
self.logger.error("Documentos não podem ser incorporados sem definir "
"para qual Matéria Legislativa ele se destina.")
raise ValidationError(
_('Documentos não podem ser incorporados sem definir '
'para qual Matéria Legislativa ele se destina.'))
@ -1698,9 +1804,11 @@ class ConfirmarProposicaoForm(ProposicaoForm):
numeracao = None
try:
self.logger.debug("Tentando obter modelo de sequência de numeração.")
numeracao = sapl.base.models.AppConfig.objects.last(
).sequencia_numeracao
except AttributeError:
except AttributeError as e:
self.logger.error("Erro ao obter modelo. " + str(e))
pass
tipo = self.instance.tipo.tipo_conteudo_related
@ -1911,6 +2019,9 @@ class MateriaAssuntoForm(ModelForm):
class EtiquetaPesquisaForm(forms.Form):
logger = logging.getLogger(__name__)
tipo_materia = forms.ModelChoiceField(
label=TipoMateriaLegislativa._meta.verbose_name,
queryset=TipoMateriaLegislativa.objects.all(),
@ -1972,12 +2083,16 @@ class EtiquetaPesquisaForm(forms.Form):
# preencheu o Final, ou vice-versa
if (not cleaned_data['data_inicial'] or
not cleaned_data['data_final']):
self.logger.error("Caso pesquise por data, os campos de Data Incial e "
"Data Final devem ser preenchidos obrigatoriamente")
raise ValidationError(_(
'Caso pesquise por data, os campos de Data Incial e ' +
'Data Final devem ser preenchidos obrigatoriamente'))
# Caso tenha preenchido, verifica se a data final é maior que
# a inicial
elif cleaned_data['data_final'] < cleaned_data['data_inicial']:
self.logger.error("A Data Final ({}) não pode ser menor que a Data Inicial({})."
.format(cleaned_data['data_final'], cleaned_data['data_inicial']))
raise ValidationError(_(
'A Data Final não pode ser menor que a Data Inicial'))
@ -1986,12 +2101,17 @@ class EtiquetaPesquisaForm(forms.Form):
cleaned_data['processo_final']):
if (not cleaned_data['processo_inicial'] or
not cleaned_data['processo_final']):
self.logger.error("Caso pesquise por número de processo, os campos de "
"Processo Inicial e Processo Final "
"devem ser preenchidos obrigatoriamente")
raise ValidationError(_(
'Caso pesquise por número de processo, os campos de ' +
'Processo Inicial e Processo Final ' +
'devem ser preenchidos obrigatoriamente'))
elif (cleaned_data['processo_final'] <
cleaned_data['processo_inicial']):
self.logger.error("O processo final ({}) não pode ser menor que o inicial ({})."
.format(cleaned_data['processo_final'], cleaned_data['processo_inicial']))
raise ValidationError(_(
'O processo final não pode ser menor que o inicial'))
@ -1999,6 +2119,9 @@ class EtiquetaPesquisaForm(forms.Form):
class FichaPesquisaForm(forms.Form):
logger = logging.getLogger(__name__)
tipo_materia = forms.ModelChoiceField(
label=TipoMateriaLegislativa._meta.verbose_name,
queryset=TipoMateriaLegislativa.objects.all(),
@ -2043,6 +2166,8 @@ class FichaPesquisaForm(forms.Form):
return cleaned_data
if cleaned_data['data_final'] < cleaned_data['data_inicial']:
self.logger.error("A Data Final ({}) não pode ser menor que a Data Inicial ({})."
.format(cleaned_data['data_final'], cleaned_data['data_inicial']))
raise ValidationError(_(
'A Data Final não pode ser menor que a Data Inicial'))
@ -2073,6 +2198,8 @@ class FichaSelecionaForm(forms.Form):
class ExcluirTramitacaoEmLote(forms.Form):
logger = logging.getLogger(__name__)
data_tramitacao = forms.DateField(required=True,
label=_('Data da Tramitação'))
@ -2109,6 +2236,11 @@ class ExcluirTramitacaoEmLote(forms.Form):
unidade_tramitacao_destino=unidade_tramitacao_destino,
status=status)
if not tramitacao_set.exists():
self.logger.error("Não existem tramitações com os dados informados "
" (data_tramitacao={}, unidade_tramitacao_local={})."
"unidade_tramitacao_destino={}, status={})."
.format(data_tramitacao, unidade_tramitacao_local,
unidade_tramitacao_destino, status))
raise forms.ValidationError(
_("Não existem tramitações com os dados informados."))

21
sapl/materia/migrations/0032_auto_20181022_1743.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-10-22 20:43
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('materia', '0031_auto_20180924_1724'),
]
operations = [
migrations.AlterField(
model_name='autoria',
name='autor',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='base.Autor', verbose_name='Autor'),
),
]

2
sapl/materia/models.py

@ -308,7 +308,7 @@ class MateriaLegislativa(models.Model):
class Autoria(models.Model):
autor = models.ForeignKey(Autor,
verbose_name=_('Autor'),
on_delete=models.CASCADE)
on_delete=models.PROTECT)
materia = models.ForeignKey(
MateriaLegislativa, on_delete=models.CASCADE,
verbose_name=_('Matéria Legislativa'))

226
sapl/materia/views.py

@ -7,7 +7,7 @@ from crispy_forms.layout import HTML
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.core.urlresolvers import reverse
from django.db.models import Max
from django.http import HttpResponse, JsonResponse
@ -21,6 +21,7 @@ from django.views.generic.base import RedirectView
from django.views.generic.edit import FormView
from django_filters.views import FilterView
import weasyprint
import logging
import sapl
from sapl.base.models import Autor, CasaLegislativa
@ -41,7 +42,7 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm,
from sapl.norma.models import LegislacaoCitada
from sapl.parlamentares.models import Legislatura
from sapl.protocoloadm.models import Protocolo
from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal,
from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH_PROPOSICAO,
gerar_hash_arquivo, get_base_url,
get_mime_type_from_file_extension, montar_row_autor,
show_results_filter_set)
@ -92,11 +93,16 @@ def autores_ja_adicionados(materia_pk):
def proposicao_texto(request, pk):
logger = logging.getLogger(__name__)
username = request.user.username.replace("'","")
logger.debug('user=' + username + '. Tentando obter objeto Proposicao com pk = {}.'.format(pk))
proposicao = Proposicao.objects.get(pk=pk)
if proposicao.texto_original:
if (not proposicao.data_recebimento and
proposicao.autor.user_id != request.user.id):
logger.error("user=" + username + ". Usuário ({}) não tem permissão para acessar o texto original."
.format(request.user.id))
messages.error(request, _(
'Você não tem permissão para acessar o texto original.'))
return redirect(reverse('sapl.materia:proposicao_detail',
@ -113,6 +119,7 @@ def proposicao_texto(request, pk):
response['Content-Disposition'] = (
'inline; filename="%s"' % arquivo.name.split('/')[-1])
return response
logger.error('user=' + username + '. Objeto Proposicao com pk={} não encontrado.'.format(pk))
raise Http404
@ -165,6 +172,7 @@ class CriarProtocoloMateriaView(CreateView):
template_name = "crud/form.html"
form_class = MateriaSimplificadaForm
form_valid_message = _('Matéria cadastrada com sucesso!')
logger = logging.getLogger(__name__)
def get_success_url(self, materia):
return reverse('sapl.materia:materialegislativa_detail', kwargs={
@ -173,19 +181,25 @@ class CriarProtocoloMateriaView(CreateView):
def get_context_data(self, **kwargs):
context = super(
CriarProtocoloMateriaView, self).get_context_data(**kwargs)
username = self.request.user.username.replace("'","")
try:
self.logger.debug("user=" + username + ". Tentando obter objeto Protocolo.")
protocolo = Protocolo.objects.get(pk=self.kwargs['pk'])
except ObjectDoesNotExist:
except ObjectDoesNotExist as e:
self.logger.error("user=" + username + ". Objeto Protocolo com pk={} não encontrado. ".format(self.kwargs['pk']) + str(e))
raise Http404()
numero = 1
try:
self.logger.debug("user=" + username + ". Tentando obter materias do último ano.")
materias_ano = MateriaLegislativa.objects.filter(
ano=protocolo.ano,
tipo=protocolo.tipo_materia).latest('numero')
numero = materias_ano.numero + 1
except ObjectDoesNotExist:
self.logger.error("user=" + username + ". Não foram encontradas matérias no último ano ({}). "
"Definido 1 como padrão.".format(protocolo.ano))
pass # numero ficou com o valor padrão 1 acima
context['form'].fields['tipo'].initial = protocolo.tipo_materia
@ -199,10 +213,13 @@ class CriarProtocoloMateriaView(CreateView):
def form_valid(self, form):
materia = form.save()
username = self.request.user.username.replace("'","")
try:
self.logger.info("user=" + username + ". Tentando obter objeto Procolo com pk={}.".format(self.kwargs['pk']))
protocolo = Protocolo.objects.get(pk=self.kwargs['pk'])
except ObjectDoesNotExist:
self.logger.error('user=' + username + '. Objeto Protocolo com pk={} não encontrado.'.format(self.kwargs['pk']))
raise Http404()
if protocolo.autor:
@ -286,14 +303,18 @@ class ProposicaoTaView(IntegracaoTaView):
@permission_required('materia.detail_materialegislativa')
def recuperar_materia(request):
logger = logging.getLogger(__name__)
username = request.user.username.replace("'","")
tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo'])
ano = request.GET.get('ano', '')
numeracao = None
try:
logger.debug("user=" + username + ". Tentando obter numeração da matéria.")
numeracao = sapl.base.models.AppConfig.objects.last(
).sequencia_numeracao
except AttributeError:
except AttributeError as e:
logger.error("user=" + username + ". " + str(e) + " Numeracao da matéria definida como None.")
pass
if tipo.sequencia_numeracao:
@ -481,27 +502,36 @@ class ReceberProposicao(PermissionRequiredForAppCrudMixin, FormView):
form = ReceberProposicaoForm(request.POST)
if form.is_valid():
proposicoes = Proposicao.objects.filter(
data_envio__isnull=False, data_recebimento__isnull=True)
try:
# A ultima parte do código deve ser a pk da Proposicao
cod_hash = form.cleaned_data["cod_hash"]. \
replace('/', SEPARADOR_HASH_PROPOSICAO)
id = cod_hash.split(SEPARADOR_HASH_PROPOSICAO)[1]
proposicao = Proposicao.objects.get(id=id,
data_envio__isnull=False,
data_recebimento__isnull=True)
for proposicao in proposicoes:
if proposicao.texto_articulado.exists():
ta = proposicao.texto_articulado.first()
# FIXME hash para textos articulados
hasher = 'P' + ta.hash() + '/' + str(proposicao.id)
hasher = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(proposicao.id)
else:
hasher = gerar_hash_arquivo(
proposicao.texto_original.path,
str(proposicao.pk)) \
str(proposicao.id)) \
if proposicao.texto_original else None
if hasher == form.cleaned_data['cod_hash']:
if hasher == cod_hash:
return HttpResponseRedirect(
reverse('sapl.materia:proposicao-confirmar',
kwargs={
'hash': hasher.split('/')[0][1:],
'hash': hasher.split(SEPARADOR_HASH_PROPOSICAO)[0][1:],
'pk': proposicao.pk}))
except ObjectDoesNotExist:
messages.error(request, _('Proposição não encontrada!'))
except IndexError:
messages.error(request, _('Código de recibo mal formado!'))
except IOError:
messages.error(request, _('Erro abrindo texto original de proposição'))
return self.form_invalid(form)
def get_success_url(self):
@ -519,15 +549,19 @@ class RetornarProposicao(UpdateView):
model = Proposicao
fields = ['data_envio', 'descricao' ]
permission_required = ('materia.detail_proposicao_enviada', )
logger = logging.getLogger(__name__)
def dispatch(self, request, *args, **kwargs):
username = request.user.username.replace("'","")
try:
self.logger.info("user=" + username + ". Tentando obter objeto Proposicao com id={}.".format(kwargs['pk']))
p = Proposicao.objects.get(id=kwargs['pk'])
except:
self.logger.error("user=" + username + ". Objeto Proposicao com id={} não encontrado.".format(kwargs['pk']))
raise Http404()
if p.autor.user != request.user:
self.logger.error("user=" + username + ". Usuário ({}) sem acesso a esta opção.".format(request.user))
messages.error(
request,
'Usuário sem acesso a esta opção.' %
@ -543,6 +577,7 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView):
template_name = "materia/confirmar_proposicao.html"
model = Proposicao
form_class = ConfirmarProposicaoForm, DevolverProposicaoForm
logger = logging.getLogger(__name__)
def get_success_url(self):
msgs = self.object.results['messages']
@ -554,12 +589,15 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView):
return self.object.results['url']
def get_object(self, queryset=None):
username = self.request.user.username.replace("'","")
try:
"""
Não deve haver acesso na rotina de confirmação a proposições:
recebidas -> data_recebimento != None
não enviadas -> data_envio == None
"""
self.logger.debug("user=" + username + ". Tentando obter objeto Proposicao.")
proposicao = Proposicao.objects.get(pk=self.kwargs['pk'],
data_envio__isnull=False,
data_recebimento__isnull=True)
@ -567,18 +605,21 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView):
if proposicao.texto_articulado.exists():
ta = proposicao.texto_articulado.first()
hasher = 'P' + ta.hash() + '/' + str(proposicao.id)
hasher = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(proposicao.id)
else:
hasher = gerar_hash_arquivo(
proposicao.texto_original.path,
str(proposicao.pk)) if proposicao.texto_original else None
if hasher == 'P%s/%s' % (self.kwargs['hash'], proposicao.pk):
if hasher == 'P%s%s%s' % (self.kwargs['hash'], SEPARADOR_HASH_PROPOSICAO, proposicao.pk):
self.object = proposicao
except:
except Exception as e:
self.logger.error("user=" + username + ". Objeto Proposicao com atributos (pk={}, data_envio=Not Null, "
"data_recebimento=Null) não encontrado. ".format(self.kwargs['pk']) + str(e))
raise Http404()
if not self.object:
self.logger.error("user=" + username + ". Objeto vazio.")
raise Http404()
return self.object
@ -694,6 +735,7 @@ class ProposicaoCrud(Crud):
'materia.detail_proposicao_devolvida',
'materia.detail_proposicao_incorporada')
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['subnav_template_name'] = ''
@ -704,7 +746,9 @@ class ProposicaoCrud(Crud):
return context
def get(self, request, *args, **kwargs):
action = request.GET.get('action', '')
username = request.user.username.replace("'","")
if not action:
return Crud.DetailView.get(self, request, *args, **kwargs)
@ -736,23 +780,32 @@ class ProposicaoCrud(Crud):
messages.success(request, _(
'Proposição enviada com sucesso.'))
try:
self.logger.debug("user=" + username + ". Tentando obter número do objeto MateriaLegislativa com "
"atributos tipo={} e ano={}."
.format(p.tipo.tipo_conteudo_related, p.ano))
numero = MateriaLegislativa.objects.filter(tipo=p.tipo.tipo_conteudo_related,
ano=p.ano).last().numero + 1
messages.success(request, _(
'%s : nº %s de %s <br>Atenção! Este número é apenas um provável '
'número que pode não corresponder com a realidade'
% (p.tipo, numero, p.ano)))
except ValueError:
except ValueError as e:
self.logger.error("user=" + username + "." + str(e))
pass
except AttributeError:
except AttributeError as e:
self.logger.error("user=" + username + "." + str(e))
pass
except TypeError:
except TypeError as e:
self.logger.error("user=" + username + "." + str(e))
pass
elif action == 'return':
if not p.data_envio:
self.logger.error("user=" + username + ". Proposição (numero={}) ainda não foi enviada.".format(p.numero_proposicao))
msg_error = _('Proposição ainda não foi enviada.')
elif p.data_recebimento:
self.logger.error("user=" + username + ". Proposição (numero={}) já foi recebida, não é "
"possível retorná-la.".format(p.numero_proposicao))
msg_error = _('Proposição já foi recebida, não é '
'possível retorná-la.')
else:
@ -763,6 +816,7 @@ class ProposicaoCrud(Crud):
ta.privacidade = STATUS_TA_PRIVATE
ta.editing_locked = False
ta.save()
self.logger.info("user=" + username + ". Proposição (numero={}) Retornada com sucesso.".format(p.numero_proposicao))
messages.success(request, _(
'Proposição Retornada com sucesso.'))
@ -774,10 +828,12 @@ class ProposicaoCrud(Crud):
kwargs={'pk': kwargs['pk']}))
def dispatch(self, request, *args, **kwargs):
username = request.user.username.replace("'","")
try:
self.logger.debug("user=" + username + ". Tentando obter objeto Proposicao com pk={}".format(kwargs['pk']))
p = Proposicao.objects.get(id=kwargs['pk'])
except:
except Exception as e:
self.logger.error("user=" + username + ". Erro ao obter proposicao com pk={}. Retornando 404. ".format(kwargs['pk']) + str(e))
raise Http404()
if not self.has_permission():
@ -806,16 +862,25 @@ class ProposicaoCrud(Crud):
class DeleteView(BaseLocalMixin, Crud.DeleteView):
logger = logging.getLogger(__name__)
def _action_is_valid(self, request, *args, **kwargs):
proposicao = Proposicao.objects.filter(
id=kwargs['pk']).values_list(
'data_envio', 'data_recebimento')
username = request.user.username.replace("'","")
if proposicao:
if proposicao[0][0] and proposicao[0][1]:
self.logger.error("user=" + username + ". Proposição (id={}) já foi enviada e recebida."
"Não pode mais ser excluida.".format(kwargs['pk']))
msg = _('Proposição já foi enviada e recebida.'
'Não pode mais ser excluida.')
elif proposicao[0][0] and not proposicao[0][1]:
self.logger.error("user=" + username + ". Proposição (id={}) já foi enviada mas ainda não recebida "
"pelo protocolo. Use a opção Recuperar Proposição "
"para depois excluí-la.".format(kwargs['pk']))
msg = _('Proposição já foi enviada mas ainda não recebida '
'pelo protocolo. Use a opção Recuperar Proposição '
'para depois excluí-la.')
@ -827,17 +892,26 @@ class ProposicaoCrud(Crud):
class UpdateView(BaseLocalMixin, Crud.UpdateView):
logger = logging.getLogger(__name__)
def _action_is_valid(self, request, *args, **kwargs):
proposicao = Proposicao.objects.filter(
id=kwargs['pk']).values_list(
'data_envio', 'data_recebimento')
username = request.user.username.replace("'","")
if proposicao:
if proposicao[0][0] and proposicao[0][1]:
self.logger.error('user=' + username + '. Proposição (id={}) já foi enviada e recebida.'
'Não pode mais ser editada'.format(kwargs['pk']))
msg = _('Proposição já foi enviada e recebida.'
'Não pode mais ser editada')
elif proposicao[0][0] and not proposicao[0][1]:
self.logger.error('user=' + username + '. Proposição (id={}) já foi enviada mas ainda não recebida '
'pelo protocolo. Use a opção Recuperar Proposição '
'para voltar para edição.'.format(kwargs['pk']))
msg = _('Proposição já foi enviada mas ainda não recebida '
'pelo protocolo. Use a opção Recuperar Proposição '
'para voltar para edição.')
@ -850,6 +924,7 @@ class ProposicaoCrud(Crud):
def get_success_url(self):
tipo_texto = self.request.POST.get('tipo_texto', '')
username = self.request.user.username.replace("'","")
if tipo_texto == 'T':
messages.info(self.request,
@ -857,12 +932,17 @@ class ProposicaoCrud(Crud):
'alterada e a opção "Texto Articulado " for '
'marcada, você será redirecionado para a '
'edição do Texto Eletrônico.'))
self.logger.debug('user=' + username + '. Sempre que uma Proposição é inclusa ou '
'alterada e a opção "Texto Articulado " for '
'marcada, você será redirecionado para a '
'edição do Texto Eletrônico.')
return reverse('sapl.materia:proposicao_ta',
kwargs={'pk': self.object.pk})
else:
return Crud.UpdateView.get_success_url(self)
class CreateView(Crud.CreateView):
logger = logging.getLogger(__name__)
form_class = ProposicaoForm
layout_key = None
@ -874,6 +954,7 @@ class ProposicaoCrud(Crud):
def get_success_url(self):
tipo_texto = self.request.POST.get('tipo_texto', '')
username = self.request.user.username.replace("'","")
if tipo_texto == 'T':
messages.info(self.request,
@ -882,6 +963,11 @@ class ProposicaoCrud(Crud):
'marcada, você será redirecionado para o '
'Texto Eletrônico. Use a opção "Editar Texto" '
'para construir seu texto.'))
self.logger.debug('user=' + username + '. Sempre que uma Proposição é inclusa ou '
'alterada e a opção "Texto Articulado " for '
'marcada, você será redirecionado para o '
'Texto Eletrônico. Use a opção "Editar Texto" '
'para construir seu texto.')
return reverse('sapl.materia:proposicao_ta',
kwargs={'pk': self.object.pk})
else:
@ -913,6 +999,7 @@ class ProposicaoCrud(Crud):
class ReciboProposicaoView(TemplateView):
logger = logging.getLogger(__name__)
template_name = "materia/recibo_proposicao.html"
permission_required = ('materia.detail_proposicao', )
@ -950,14 +1037,18 @@ class ReciboProposicaoView(TemplateView):
def get(self, request, *args, **kwargs):
proposicao = Proposicao.objects.get(pk=self.kwargs['pk'])
username = request.user.username.replace("'","")
if proposicao.data_envio:
return TemplateView.get(self, request, *args, **kwargs)
if not proposicao.data_envio and not proposicao.data_devolucao:
self.logger.error('user=' + username + '. Não é possível gerar recibo para uma '
'Proposição (pk={}) ainda não enviada.'.format(self.kwargs['pk']))
messages.error(request, _('Não é possível gerar recibo para uma '
'Proposição ainda não enviada.'))
elif proposicao.data_devolucao:
self.logger.error("user=" + username + ". Não é possível gerar recibo para proposicao de pk={}.".format(self.kwargs['pk']))
messages.error(request, _('Não é possível gerar recibo.'))
return redirect(reverse('sapl.materia:proposicao_detail',
@ -972,17 +1063,22 @@ class RelatoriaCrud(MasterDetailCrud):
class CreateView(MasterDetailCrud.CreateView):
form_class = RelatoriaForm
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
username = self.request.user.username.replace("'","")
try:
self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format(context['form'].initial['comissao']))
comissao = Comissao.objects.get(
pk=context['form'].initial['comissao'])
except:
self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format(context['form'].initial['comissao']))
pass
else:
self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(context['form'].initial['comissao']))
composicao = comissao.composicao_set.order_by(
'-periodo__data_inicio').first()
participacao = Participacao.objects.filter(
@ -1018,15 +1114,22 @@ class RelatoriaCrud(MasterDetailCrud):
class UpdateView(MasterDetailCrud.UpdateView):
form_class = RelatoriaForm
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
username = self.request.user.username.replace("'","")
try:
self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format(context['form'].initial['comissao']))
comissao = Comissao.objects.get(
pk=context['form'].initial['comissao'])
except ObjectDoesNotExist:
self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format(context['form'].initial['comissao']))
pass
else:
self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(context['form'].initial['comissao']))
composicao = comissao.composicao_set.order_by(
'-periodo__data_inicio').first()
participacao = Participacao.objects.filter(
@ -1054,6 +1157,7 @@ class TramitacaoCrud(MasterDetailCrud):
class CreateView(MasterDetailCrud.CreateView):
form_class = TramitacaoForm
logger = logging.getLogger(__name__)
def get_success_url(self):
return reverse('sapl.materia:tramitacao_list', kwargs={
@ -1076,6 +1180,7 @@ class TramitacaoCrud(MasterDetailCrud):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
username = self.request.user.username.replace("'","")
ultima_tramitacao = Tramitacao.objects.filter(
materia_id=self.kwargs['pk']).order_by(
@ -1090,6 +1195,8 @@ class TramitacaoCrud(MasterDetailCrud):
(ultima_tramitacao.unidade_tramitacao_destino.pk,
ultima_tramitacao.unidade_tramitacao_destino)]
else:
self.logger.error('user=' + username + '. Unidade de tramitação destino '
'da última tramitação não pode ser vazia!')
msg = _('Unidade de tramitação destino '
' da última tramitação não pode ser vazia!')
messages.add_message(self.request, messages.ERROR, msg)
@ -1097,7 +1204,9 @@ class TramitacaoCrud(MasterDetailCrud):
return context
def form_valid(self, form):
self.object = form.save()
username = self.request.user.username.replace("'","")
if form.instance.status.indicador == 'F':
form.instance.materia.em_tramitacao = False
@ -1106,25 +1215,32 @@ class TramitacaoCrud(MasterDetailCrud):
form.instance.materia.save()
try:
self.logger.debug("user=" + username + ". Tentando enviar Tramitacao (sender={}, post={}, request={})."
.format(Tramitacao, self.object, self.request))
tramitacao_signal.send(sender=Tramitacao,
post=self.object,
request=self.request)
except Exception:
except Exception as e:
# TODO log error
msg = _('Tramitação criada, mas e-mail de acompanhamento '
'de matéria não enviado. Há problemas na configuração '
'do e-mail.')
self.logger.warning('user=' + username + '. Tramitação criada, mas e-mail de acompanhamento '
'de matéria não enviado. Há problemas na configuração '
'do e-mail. ' + str(e))
messages.add_message(self.request, messages.WARNING, msg)
return HttpResponseRedirect(self.get_success_url())
return super().form_valid(form)
class UpdateView(MasterDetailCrud.UpdateView):
form_class = TramitacaoUpdateForm
logger = logging.getLogger(__name__)
layout_key = 'TramitacaoUpdate'
def form_valid(self, form):
self.object = form.save()
username = self.request.user.username.replace("'","")
if form.instance.status.indicador == 'F':
form.instance.materia.em_tramitacao = False
@ -1133,6 +1249,8 @@ class TramitacaoCrud(MasterDetailCrud):
form.instance.materia.save()
try:
self.logger.debug("user=" + username + ". Tentando enviar Tramitacao (sender={}, post={}, request={}"
.format(Tramitacao, self.object, self.request))
tramitacao_signal.send(sender=Tramitacao,
post=self.object,
request=self.request)
@ -1141,6 +1259,9 @@ class TramitacaoCrud(MasterDetailCrud):
msg = _('Tramitação atualizada, mas e-mail de acompanhamento '
'de matéria não enviado. Há problemas na configuração '
'do e-mail.')
self.logger.warning('user=' + username + '. Tramitação atualizada, mas e-mail de acompanhamento '
'de matéria não enviado. Há problemas na configuração '
'do e-mail.')
messages.add_message(self.request, messages.WARNING, msg)
return HttpResponseRedirect(self.get_success_url())
return super().form_valid(form)
@ -1156,6 +1277,8 @@ class TramitacaoCrud(MasterDetailCrud):
class DeleteView(MasterDetailCrud.DeleteView):
logger = logging.getLogger(__name__)
def delete(self, request, *args, **kwargs):
tramitacao = Tramitacao.objects.get(id=self.kwargs['pk'])
materia = MateriaLegislativa.objects.get(id=tramitacao.materia.id)
@ -1167,7 +1290,12 @@ class TramitacaoCrud(MasterDetailCrud):
'-timestamp',
'-id').first()
username = request.user.username.replace("'","")
if tramitacao.pk != ultima_tramitacao.pk:
self.logger.error("user=" + username + ". Não é possível deletar a tramitação de pk={}. "
"Somente a última tramitação (pk={}) pode ser deletada!."
.format(tramitacao.pk, ultima_tramitacao.pk))
msg = _('Somente a última tramitação pode ser deletada!')
messages.add_message(request, messages.ERROR, msg)
return HttpResponseRedirect(url)
@ -1508,7 +1636,11 @@ class DocumentoAcessorioView(PermissionRequiredMixin, CreateView):
class AcompanhamentoConfirmarView(TemplateView):
logger = logging.getLogger(__name__)
def get_redirect_url(self, email):
username = self.request.user.username.replace("'","")
self.logger.debug('user=' + username + '. Esta matéria está sendo acompanhada pelo e-mail: %s' % (email))
msg = _('Esta matéria está sendo acompanhada pelo e-mail: %s') % (
email)
messages.add_message(self.request, messages.SUCCESS, msg)
@ -1518,18 +1650,24 @@ class AcompanhamentoConfirmarView(TemplateView):
def get(self, request, *args, **kwargs):
materia_id = kwargs['pk']
hash_txt = request.GET.get('hash_txt', '')
username = self.request.user.username.replace("'","")
try:
self.logger.info("user=" + username + ". Tentando obter objeto AcompanhamentoMateria (materia_id={}, hash={})."
.format(materia_id, hash_txt))
acompanhar = AcompanhamentoMateria.objects.get(
materia_id=materia_id,
hash=hash_txt)
except ObjectDoesNotExist:
self.logger.error("user=" + username + ". Objeto AcompanhamentoMateria(materia_id={}, hash={}) não encontrado."
.format(materia_id, hash_txt))
raise Http404()
# except MultipleObjectsReturned:
except MultipleObjectsReturned as e:
# A melhor solução deve ser permitir que a exceção
# (MultipleObjectsReturned) seja lançada e vá para o log,
# pois só poderá ser causada por um erro de desenvolvimente
self.logger.error('user=' + username + '.' + str(e))
pass
acompanhar.confirmado = True
acompanhar.save()
@ -1538,7 +1676,11 @@ class AcompanhamentoConfirmarView(TemplateView):
class AcompanhamentoExcluirView(TemplateView):
logger = logging.getLogger(__name__)
def get_success_url(self):
username = self.request.user.username.replace("'","")
self.logger.debug("user=" + username + ". Você parou de acompanhar esta matéria.")
msg = _('Você parou de acompanhar esta matéria.')
messages.add_message(self.request, messages.INFO, msg)
return reverse('sapl.materia:materialegislativa_detail',
@ -1547,11 +1689,16 @@ class AcompanhamentoExcluirView(TemplateView):
def get(self, request, *args, **kwargs):
materia_id = kwargs['pk']
hash_txt = request.GET.get('hash_txt', '')
username = self.request.user.username.replace("'","")
try:
self.logger.info("user=" + username + ". Tentando deletar objeto AcompanhamentoMateria (materia_id={}, hash={})."
.format(materia_id, hash_txt))
AcompanhamentoMateria.objects.get(materia_id=materia_id,
hash=hash_txt).delete()
except ObjectDoesNotExist:
self.logger.error("user=" + username + ". Objeto AcompanhamentoMateria (materia_id={}, hash={}) não encontrado."
.format(materia_id, hash_txt))
pass
return HttpResponseRedirect(self.get_success_url())
@ -1635,6 +1782,7 @@ class MateriaLegislativaPesquisaView(FilterView):
class AcompanhamentoMateriaView(CreateView):
logger = logging.getLogger(__name__)
template_name = "materia/acompanhamento_materia.html"
def get_random_chars(self):
@ -1686,7 +1834,9 @@ class AcompanhamentoMateriaView(CreateView):
"materia",
materia,
destinatario)
self.logger.debug('user=' + usuario.username + '. Foi enviado um e-mail de confirmação. Confira sua caixa \
de mensagens e clique no link que nós enviamos para \
confirmar o acompanhamento desta matéria.')
msg = _('Foi enviado um e-mail de confirmação. Confira sua caixa \
de mensagens e clique no link que nós enviamos para \
confirmar o acompanhamento desta matéria.')
@ -1695,6 +1845,7 @@ class AcompanhamentoMateriaView(CreateView):
# Caso esse Acompanhamento já exista
# avisa ao usuário que essa matéria já está sendo acompanhada
else:
self.logger.debug("user=" + usuario.username + ". Este e-mail já está acompanhando essa matéria.")
msg = _('Este e-mail já está acompanhando essa matéria.')
messages.add_message(request, messages.INFO, msg)
@ -1773,6 +1924,8 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
primeira_tramitacao = True
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs):
context = super(PrimeiraTramitacaoEmLoteView,
self).get_context_data(**kwargs)
@ -1815,10 +1968,13 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
def post(self, request, *args, **kwargs):
marcadas = request.POST.getlist('materia_id')
tz = timezone.get_current_timezone()
username = request.user.username.replace("'","")
if len(marcadas) == 0:
msg = _('Nenhuma máteria foi selecionada.')
messages.add_message(request, messages.ERROR, msg)
@ -1870,10 +2026,15 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
)
t.save()
try:
self.logger.debug("user=" + username + ". Tentando enviar tramitação.")
tramitacao_signal.send(sender=Tramitacao,
post=t,
request=self.request)
except Exception:
except Exception as e:
self.logger.error('user=' + username + '. Tramitação criada , mas e-mail de acompanhamento '
'de matéria não enviado. Há problemas na configuração '
'do e-mail. ' + str(e))
flag_error = True
if flag_error:
msg = _('Tramitação criada, mas e-mail de acompanhamento '
@ -1891,6 +2052,7 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
materia.save()
msg = _('Tramitação completa.')
self.logger.info('user=' + username + '. Tramitação completa.')
messages.add_message(request, messages.SUCCESS, msg)
return self.get(request, self.kwargs)
@ -1996,6 +2158,7 @@ class FichaPesquisaView(PermissionRequiredMixin, FormView):
class FichaSelecionaView(PermissionRequiredMixin, FormView):
logger = logging.getLogger(__name__)
form_class = FichaSelecionaForm
template_name = 'materia/impressos/ficha_seleciona.html'
permission_required = ('materia.can_access_impressos', )
@ -2025,7 +2188,15 @@ class FichaSelecionaView(PermissionRequiredMixin, FormView):
context['form'].fields['materia'].choices = [
(m.id, str(m)) for m in materia_list]
username = self.request.user.username.replace("'","")
if context['quantidade'] > 100:
self.logger.info('user=' + username + '. Sua pesquisa (tipo={}, data_inicial={}, data_final={}) retornou mais do que '
'100 impressos. Por questões de '
'performance, foram retornados '
'apenas os 100 primeiros. Caso '
'queira outros, tente fazer uma '
'pesquisa mais específica'.format(tipo, data_inicial, data_final))
messages.info(self.request, _('Sua pesquisa retornou mais do que '
'100 impressos. Por questões de '
'performance, foram retornados '
@ -2037,11 +2208,14 @@ class FichaSelecionaView(PermissionRequiredMixin, FormView):
def form_valid(self, form):
context = {}
username = self.request.user.username.replace("'","")
try:
self.logger.debug("user=" + username + ". Tentando obter objeto MateriaLegislativa com id={}".format(form.data['materia']))
materia = MateriaLegislativa.objects.get(
id=form.data['materia'])
except ObjectDoesNotExist:
self.logger.error("user=" + username + ". Esta MáteriaLegislativa não existe (id={}).".format(form.data['materia']))
mensagem = _('Esta Máteria não existe!')
self.messages.add_message(self.request, messages.INFO, mensagem)

35
sapl/norma/forms.py

@ -1,5 +1,6 @@
import django_filters
import logging
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Fieldset, Layout
from django import forms
@ -105,6 +106,8 @@ class NormaJuridicaForm(ModelForm):
widget=forms.Select(attrs={'autocomplete': 'off'})
)
logger = logging.getLogger(__name__)
class Meta:
model = NormaJuridica
fields = ['tipo',
@ -129,6 +132,7 @@ class NormaJuridicaForm(ModelForm):
def clean(self):
cleaned_data = super(NormaJuridicaForm, self).clean()
if not self.is_valid():
@ -137,6 +141,7 @@ class NormaJuridicaForm(ModelForm):
import re
has_digits = re.sub('[^0-9]', '', cleaned_data['numero'])
if not has_digits:
self.logger.error("Número de norma ({}) não pode conter somente letras.".format(cleaned_data['numero']))
raise ValidationError('Número de norma não pode conter somente letras')
if self.instance.numero != cleaned_data['numero']:
@ -144,24 +149,35 @@ class NormaJuridicaForm(ModelForm):
numero=cleaned_data['numero'],
tipo=cleaned_data['tipo']).exists()
if norma:
self.logger.error("Já existe uma norma de mesmo Tipo ({}), Ano ({}) "
"e Número ({}) no sistema."
.format(cleaned_data['tipo'], cleaned_data['ano'], cleaned_data['numero']))
raise ValidationError("Já existe uma norma de mesmo Tipo, Ano "
"e Número no sistema")
if (cleaned_data['tipo_materia'] and
cleaned_data['numero_materia'] and
cleaned_data['ano_materia']):
try:
self.logger.debug("Tentando obter objeto MateriaLegislativa com tipo={}, numero={}, ano={}."
.format(cleaned_data['tipo_materia'], cleaned_data['numero_materia'], cleaned_data['ano_materia']))
materia = MateriaLegislativa.objects.get(
tipo_id=cleaned_data['tipo_materia'],
numero=cleaned_data['numero_materia'],
ano=cleaned_data['ano_materia'])
except ObjectDoesNotExist:
self.logger.error("Matéria Legislativa %s/%s (%s) é inexistente." % (
self.cleaned_data['numero_materia'],
self.cleaned_data['ano_materia'],
cleaned_data['tipo_materia'].descricao))
raise forms.ValidationError(
_("Matéria Legislativa %s/%s (%s) é inexistente." % (
self.cleaned_data['numero_materia'],
self.cleaned_data['ano_materia'],
cleaned_data['tipo_materia'].descricao)))
else:
self.logger.info("MateriaLegislativa com tipo={}, numero={}, ano={} obtida com sucesso."
.format(cleaned_data['tipo_materia'], cleaned_data['numero_materia'], cleaned_data['ano_materia']))
cleaned_data['materia'] = materia
else:
@ -171,6 +187,8 @@ class NormaJuridicaForm(ModelForm):
data = cleaned_data['data']
if data.year != ano:
self.logger.error("O ano da norma ({}) é diferente "
"do ano no campo data ({}).".format(ano, data.year))
raise ValidationError("O ano da norma não pode ser "
"diferente do ano no campo data")
return cleaned_data
@ -179,6 +197,8 @@ class NormaJuridicaForm(ModelForm):
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))
tam_fornecido = str( texto_integral.size / (1024*1024) )
self.logger.error("Arquivo muito grande ({}MB). ( Tamanho máximo permitido: {}MB )".format(tam_fornecido, max_size))
raise ValidationError(
"Arquivo muito grande. ( > {0}MB )".format(max_size))
return texto_integral
@ -202,6 +222,8 @@ class AutoriaNormaForm(ModelForm):
data_relativa = forms.DateField(
widget=forms.HiddenInput(), required=False)
logger = logging.getLogger(__name__)
def __init__(self, *args, **kwargs):
super(AutoriaNormaForm, self).__init__(*args, **kwargs)
@ -233,6 +255,7 @@ class AutoriaNormaForm(ModelForm):
if ((not pk and autorias.exists()) or
(pk and autorias.exclude(pk=pk).exists())):
self.logger.error("Autor ({}) já foi cadastrado.".format(cd['autor']))
raise ValidationError(_('Esse Autor já foi cadastrado.'))
return cd
@ -245,6 +268,7 @@ class AnexoNormaJuridicaForm(ModelForm):
'norma': forms.HiddenInput(),
}
logger = logging.getLogger(__name__)
def clean(self):
cleaned_data = super(AnexoNormaJuridicaForm, self).clean()
if not self.is_valid():
@ -252,6 +276,8 @@ class AnexoNormaJuridicaForm(ModelForm):
anexo_arquivo = self.cleaned_data.get('anexo_arquivo', False)
if anexo_arquivo and anexo_arquivo.size > MAX_DOC_UPLOAD_SIZE:
max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024))
tam_fornecido = str( anexo_arquivo.size / (1024*1024) )
self.logger.error("Arquivo muito grande ({}MB). ( Tamanho máximo permitido: {}MB )".format(tam_fornecido, max_size))
raise ValidationError(
"Arquivo muito grande. ( > {0}MB )".format(max_size))
return cleaned_data
@ -282,6 +308,7 @@ class NormaRelacionadaForm(ModelForm):
required=False,
widget=forms.Textarea(attrs={'disabled': 'disabled'}))
logger = logging.getLogger(__name__)
class Meta:
model = NormaRelacionada
fields = ['tipo', 'numero', 'ano', 'ementa', 'tipo_vinculo']
@ -297,14 +324,17 @@ class NormaRelacionadaForm(ModelForm):
cleaned_data = self.cleaned_data
try:
self.logger.debug("Tentando obter objeto NormaJuridica com numero={}, ano={}, tipo={}.".format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
norma_relacionada = NormaJuridica.objects.get(
numero=cleaned_data['numero'],
ano=cleaned_data['ano'],
tipo=cleaned_data['tipo'])
except ObjectDoesNotExist:
self.logger.info("NormaJuridica com numero={}, ano={}, tipo={} não existe.".format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
msg = _('A norma a ser relacionada não existe.')
raise ValidationError(msg)
else:
self.logger.info("NormaJuridica com numero={}, ano={}, tipo={} obtida com sucesso.".format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
cleaned_data['norma_relacionada'] = norma_relacionada
return cleaned_data
@ -340,6 +370,8 @@ class NormaPesquisaSimplesForm(forms.Form):
required=False,
max_length=150)
logger = logging.getLogger(__name__)
def __init__(self, *args, **kwargs):
super(NormaPesquisaSimplesForm, self).__init__(*args, **kwargs)
@ -373,12 +405,15 @@ class NormaPesquisaSimplesForm(forms.Form):
if (data_inicial and data_final and
data_inicial > data_final):
self.logger.error("Data Final ({}) menor que a Data Inicial ({}).".format(data_final, data_inicial))
raise ValidationError(_(
'A Data Final não pode ser menor que a Data Inicial'))
else:
condicao1 = data_inicial and not data_final
condicao2 = not data_inicial and data_final
if condicao1 or condicao2:
self.logger.error("Caso pesquise por data, os campos de Data Inicial e "
"Data Final devem ser preenchidos obrigatoriamente")
raise ValidationError(_('Caso pesquise por data, os campos de Data Inicial e ' +
'Data Final devem ser preenchidos obrigatoriamente'))

14
sapl/norma/views.py

@ -1,5 +1,6 @@
import re
import logging
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist
@ -199,16 +200,22 @@ class NormaCrud(Crud):
class CreateView(Crud.CreateView):
form_class = NormaJuridicaForm
logger = logging.getLogger(__name__)
@property
def cancel_url(self):
return self.search_url
def get_initial(self):
username = self.request.user.username
try:
self.logger.debug('user=' + username + '. Tentando obter objeto de modelo da esfera da federação.')
esfera = sapl.base.models.AppConfig.objects.last(
).esfera_federacao
self.initial['esfera_federacao'] = esfera
except:
self.logger.error('user=' + username + '. Erro ao obter objeto de modelo da esfera da federação.')
pass
self.initial['complemento'] = False
return self.initial
@ -241,17 +248,24 @@ class NormaCrud(Crud):
def recuperar_norma(request):
logger = logging.getLogger(__name__)
username = request.user.username
tipo = TipoNormaJuridica.objects.get(pk=request.GET['tipo'])
numero = request.GET['numero']
ano = request.GET['ano']
try:
logger.info('user=' + username + '. Tentando obter NormaJuridica (tipo={}, ano={}, numero={}).'
.format(tipo, ano, numero))
norma = NormaJuridica.objects.get(tipo=tipo,
ano=ano,
numero=numero)
response = JsonResponse({'ementa': norma.ementa,
'id': norma.id})
except ObjectDoesNotExist:
logger.error('user=' + username + '. NormaJuridica buscada (tipo={}, ano={}, numero={}) não existe. '
'Definida com ementa vazia e id 0.'.format(tipo, ano, numero))
response = JsonResponse({'ementa': '', 'id': 0})
return response

53
sapl/painel/views.py

@ -1,5 +1,6 @@
import html
import json
import logging
from django.contrib import messages
from django.contrib.auth.decorators import user_passes_test
@ -42,6 +43,9 @@ def votacao_aberta(request):
nenhuma. É utilizada como uma função auxiliar para a view
votante_view.
'''
logger = logging.getLogger(__name__)
username = request.user.username
votacoes_abertas = SessaoPlenaria.objects.filter(
Q(ordemdia__votacao_aberta=True) |
Q(expedientemateria__votacao_aberta=True)).distinct()
@ -53,7 +57,9 @@ def votacao_aberta(request):
reverse('sapl.sessao:sessaoplenaria_detail',
kwargs={'pk': v.id}),
v.__str__()))
logger.info('user=' + username + '. Existe mais de uma votações aberta. Elas se encontram '
'nas seguintes Sessões: ' + ', '.join(msg_abertas) + '. '
'Para votar, peça para que o Operador feche-as.')
msg = _('Existe mais de uma votações aberta. Elas se encontram '
'nas seguintes Sessões: ' + ', '.join(msg_abertas) + '. '
'Para votar, peça para que o Operador feche-as.')
@ -70,6 +76,11 @@ def votacao_aberta(request):
numero_materias_abertas = len(ordens) + len(expedientes)
if numero_materias_abertas > 1:
logger.info('user=' + username + '. Existe mais de uma votação aberta na Sessão: ' +
('''<li><a href="%s">%s</a></li>''' % (
reverse('sapl.sessao:sessaoplenaria_detail',
kwargs={'pk': votacoes_abertas.first().id}),
votacoes_abertas.first().__str__())))
msg = _('Existe mais de uma votação aberta na Sessão: ' +
('''<li><a href="%s">%s</a></li>''' % (
reverse('sapl.sessao:sessaoplenaria_detail',
@ -83,7 +94,7 @@ def votacao_aberta(request):
def votacao(context,context_vars):
logger = logging.getLogger(__name__)
parlamentar = context_vars['votante'].parlamentar
parlamentar_presente = False
if parlamentar.id in context_vars['presentes']:
@ -105,13 +116,17 @@ def votacao(context,context_vars):
if voto:
try:
logger.debug("Tentando obter objeto VotoParlamentar com parlamentar={}.".format(context_vars['parlamentar']))
voto = voto.get(parlamentar=context_vars['parlamentar'])
context.update({'voto_parlamentar': voto.voto})
except ObjectDoesNotExist:
logger.error("Voto do parlamentar {} não computado.".format(context_vars['parlamentar']))
context.update(
{'voto_parlamentar': 'Voto não '
'computado.'})
else:
logger.error("Parlamentar com id={} não está presente na "
"Ordem do Dia/Expediente em votação.".format(parlamentar.id))
context.update({'error_message':
'Você não está presente na '
'Ordem do Dia/Expediente em votação.'})
@ -185,14 +200,20 @@ def can_vote(context, context_vars, request):
def votante_view(request):
logger = logging.getLogger(__name__)
username = request.user.username
# Pega o votante relacionado ao usuário
template_name = 'painel/voto_nominal.html'
context = {}
context_vars = {}
try:
logger.debug('user=' + username + '. Tentando obter objeto Votante com user={}.'.format(request.user))
votante = Votante.objects.get(user=request.user)
except ObjectDoesNotExist:
logger.error("user=" + username + ". Usuário (user={}) não cadastrado como votante na tela de parlamentares. "
"Contate a administração de sua Casa Legislativa!".format(request.user))
msg = _("Usuário não cadastrado como votante na tela de parlamentares. Contate a administração de sua Casa Legislativa!")
context.update({
'error_message':msg
@ -205,8 +226,9 @@ def votante_view(request):
# Verifica se usuário possui permissão para votar
if 'parlamentares.can_vote' in request.user.get_all_permissions():
context, context_vars = can_vote(context, context_vars, request)
logger.debug("user=" + username + ". Verificando se usuário {} possui permissão para votar.".format(request.user))
else:
logger.error("user=" + username + ". Usuário {} sem permissão para votar.".format(request.user))
context.update({'permissao': False,
'error_message': 'Usuário sem permissão para votar.'})
@ -214,10 +236,14 @@ def votante_view(request):
if request.method == 'POST':
if context_vars['ordem_dia']:
try:
logger.info("user=" + username + ". Tentando obter objeto VotoParlamentar para parlamentar={} e ordem={}."
.format(context_vars['parlamentar'], context_vars['ordem_dia']))
voto = VotoParlamentar.objects.get(
parlamentar=context_vars['parlamentar'],
ordem=context_vars['ordem_dia'])
except ObjectDoesNotExist:
logger.error("user=" + username + ". Erro ao obter VotoParlamentar para parlamentar={} e ordem={}. Criando objeto."
.format(context_vars['parlamentar'], context_vars['ordem_dia']))
voto = VotoParlamentar.objects.create(
parlamentar=context_vars['parlamentar'],
voto=request.POST['voto'],
@ -225,6 +251,8 @@ def votante_view(request):
ip=get_client_ip(request),
ordem=context_vars['ordem_dia'])
else:
logger.info("user=" + username + ". VotoParlamentar para parlamentar={} e ordem={} obtido com sucesso."
.format(context_vars['parlamentar'], context_vars['ordem_dia']))
voto.voto = request.POST['voto']
voto.ip = get_client_ip(request)
voto.user = request.user
@ -232,10 +260,14 @@ def votante_view(request):
elif context_vars['expediente']:
try:
logger.info("user=" + username + ". Tentando obter objeto VotoParlamentar para parlamentar={} e expediente={}."
.format(context_vars['parlamentar'], context_vars['expediente']))
voto = VotoParlamentar.objects.get(
parlamentar=context_vars['parlamentar'],
expediente=context_vars['expediente'])
except ObjectDoesNotExist:
logger.error("user=" + username + ". Erro ao obter VotoParlamentar para parlamentar={} e expediente={}. Criando objeto."
.format(context_vars['parlamentar'], context_vars['expediente']))
voto = VotoParlamentar.objects.create(
parlamentar=context_vars['parlamentar'],
voto=request.POST['voto'],
@ -243,6 +275,8 @@ def votante_view(request):
ip=get_client_ip(request),
expediente=context_vars['expediente'])
else:
logger.info("user=" + username + ". VotoParlamentar para parlamentar={} e expediente={} obtido com sucesso."
.format(context_vars['parlamentar'], context_vars['expediente']))
voto.voto = request.POST['voto']
voto.ip = get_client_ip(request)
voto.user = request.user
@ -304,9 +338,14 @@ def cronometro_painel(request):
def get_cronometro_status(request, name):
logger = logging.getLogger(__name__)
username = request.user.username
try:
logger.debug("user=" + username + ". Tentando obter cronometro.")
cronometro = request.session[name]
except KeyError:
except KeyError as e:
logger.error("user=" + username + ". Erro ao obter cronometro. Retornado como vazio. " + str(e))
cronometro = ''
return cronometro
@ -402,6 +441,7 @@ def response_nenhuma_materia(response):
def get_votos(response, materia):
logger = logging.getLogger(__name__)
if type(materia) == OrdemDia:
registro = RegistroVotacao.objects.filter(
ordem=materia, materia=materia.materia).last()
@ -433,9 +473,12 @@ def get_votos(response, materia):
for i, p in enumerate(response['presentes']):
try:
logger.info("Tentando obter votos do parlamentar (id={}).".format(p['parlamentar_id']))
if votos_parlamentares.get(parlamentar_id=p['parlamentar_id']).voto:
response['presentes'][i]['voto'] = 'Voto Informado'
except ObjectDoesNotExist:
logger.error("Votos do parlamentar (id={}) não encontrados. Retornado vazio."
.format(p['parlamentar_id']))
response['presentes'][i]['voto'] = ''
else:
@ -450,9 +493,11 @@ def get_votos(response, materia):
for i, p in enumerate(response['presentes']):
try:
logger.debug("Tentando obter votos do parlamentar (id={}).".format(p['parlamentar_id']))
response['presentes'][i]['voto'] = votos_parlamentares.get(
parlamentar_id=p['parlamentar_id']).voto
except ObjectDoesNotExist:
logger.error("Votos do parlamentar (id={}) não encontrados. Retornado None.".format(p['parlamentar_id']))
response['presentes'][i]['voto'] = None
response.update({

66
sapl/parlamentares/forms.py

@ -1,3 +1,5 @@
import logging
from datetime import timedelta
from crispy_forms.helper import FormHelper
@ -40,9 +42,12 @@ class CustomImageCropWidget(ImageCropWidget):
def validar_datas_legislatura(eleicao, inicio, fim, pk=None):
logger = logging.getLogger(__name__)
# Verifica se data de eleição < inicio < fim
if inicio >= fim or eleicao >= inicio:
logger.error('A data início ({}) deve ser menor que a ' +
'data fim ({}) e a data eleição ({}) deve ser ' +
'menor que a data início ({})'.format(inicio, fim, eleicao, inicio))
msg_error = _('A data início deve ser menor que a ' +
'data fim e a data eleição deve ser ' +
'menor que a data início')
@ -53,12 +58,15 @@ def validar_datas_legislatura(eleicao, inicio, fim, pk=None):
data_inicio__lte=fim, data_fim__gte=inicio
).exclude(pk=pk).exists()
if intersecao_legislatura:
logger.error("Já existe uma legislatura neste intervalo de datas (data_inicio<={} e data_fim>={})."
.format(fim, inicio))
msg_error = _('Já existe uma legislatura neste intervalo de datas')
return (False, msg_error)
# Verifica se há alguma outra data de eleição cadastrada
if Legislatura.objects.filter(
data_eleicao=eleicao).exclude(pk=pk).exists():
logger.error("Esta data de eleição ({}) já foi cadastrada.".format(eleicao))
msg_error = _('Esta data de eleição já foi cadastrada')
return (False, msg_error)
@ -66,7 +74,7 @@ def validar_datas_legislatura(eleicao, inicio, fim, pk=None):
class MandatoForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = Mandato
fields = ['legislatura', 'coligacao', 'votos_recebidos',
@ -89,6 +97,9 @@ class MandatoForm(ModelForm):
if data_inicio_mandato:
if (data_inicio_mandato < legislatura.data_inicio or
data_inicio_mandato > legislatura.data_fim):
self.logger.error("Data início mandato ({}) fora do intervalo"
" de legislatura informada ({} a {})."
.format(data_inicio_mandato, legislatura.data_inicio, legislatura.data_fim))
raise ValidationError(_("Data início mandato fora do intervalo"
" de legislatura informada"))
@ -96,17 +107,27 @@ class MandatoForm(ModelForm):
if data_fim_mandato:
if (data_fim_mandato < legislatura.data_inicio or
data_fim_mandato > legislatura.data_fim):
self.logger.error("Data fim mandato ({}) fora do intervalo"
" de legislatura informada ({} a {})."
.format(data_fim_mandato, legislatura.data_inicio, legislatura.data_fim))
raise ValidationError(_("Data fim mandato fora do intervalo de"
" legislatura informada"))
data_expedicao_diploma = data['data_expedicao_diploma']
if (data_expedicao_diploma and
data_expedicao_diploma > data_inicio_mandato):
self.logger.error("A data da expedição do diploma ({}) deve ser anterior "
"a data de início do mandato ({}).".format(data_expedicao_diploma, data_inicio_mandato))
raise ValidationError(_("A data da expedição do diploma deve ser anterior "
"a data de início do mandato"))
coligacao = data['coligacao']
if coligacao and not coligacao.legislatura == legislatura:
self.logger.error("A coligação selecionada ({}) não está cadastrada "
"na mesma legislatura ({}) que o presente mandato ({}), "
"favor verificar a coligação ou fazer o cadastro "
"de uma nova coligação na legislatura correspondente"
.format(coligacao, coligacao.legislatura, legislatura))
raise ValidationError(_("A coligação selecionada não está cadastrada "
"na mesma legislatura que o presente mandato, "
"favor verificar a coligação ou fazer o cadastro "
@ -116,6 +137,8 @@ class MandatoForm(ModelForm):
parlamentar=data['parlamentar'],
legislatura=data['legislatura']).exists()
if existe_mandato:
self.logger.error("Mandato nesta legislatura (parlamentar={}, legislatura={}) já existe."
.format(data['parlamentar'], data['legislatura']))
raise ValidationError(_('Mandato nesta legislatura já existe.'))
return self.cleaned_data
@ -123,6 +146,8 @@ class MandatoForm(ModelForm):
class LegislaturaForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = Legislatura
exclude = []
@ -148,8 +173,13 @@ class LegislaturaForm(ModelForm):
).order_by('data_fim').first()
if ultima_legislatura and ultima_legislatura.numero >= numero:
self.logger.error("Número ({}) deve ser maior que o da legislatura anterior ({})."
.format(numero, ultima_legislatura.numero))
raise ValidationError(_("Número deve ser maior que o da legislatura anterior"))
elif proxima_legislatura and proxima_legislatura.numero <= numero:
self.logger.error("O Número ({}) deve ser menor que {}, pois existe uma "
"legislatura afrente cronologicamente desta que está sendo criada!"
.format(numero, proxima_legislatura.numero))
msg_erro = "O Número deve ser menor que {}, pois existe uma " \
"legislatura afrente cronologicamente desta que está sendo criada!"
msg_erro = msg_erro.format(proxima_legislatura.numero)
@ -222,8 +252,13 @@ class ParlamentarCreateForm(ParlamentarForm):
def validar_datas(data_filiacao, data_desfiliacao, parlamentar, filiacao):
logger = logging.getLogger(__name__)
# Verifica se data de desfiliacao é anterior a data de filiacao
if data_desfiliacao and data_desfiliacao < data_filiacao:
logger.error("A data de desfiliação ({}) é anterior à data de filiação ({})."
.format(data_desfiliacao, data_filiacao))
error_msg = _("A data de desfiliação não pode anterior \
à data de filiação")
return [False, error_msg]
@ -249,6 +284,8 @@ def validar_datas(data_filiacao, data_desfiliacao, parlamentar, filiacao):
# filiação em edição não é a última e está sem data de desfiliação
if not data_desfiliacao and filiacao_em_edicao_id and\
filiacao_em_edicao_id != filiacoes.last().pk:
logger.error("Data de desfiliação do parlamentar não pode ser "
"ausente, se existirem datas de filiação posteriores.")
error_msg = _("Data de desfiliação do parlamentar não pode ser\
ausente, se existirem datas de filiação posteriores.")
@ -256,6 +293,8 @@ def validar_datas(data_filiacao, data_desfiliacao, parlamentar, filiacao):
# já existe outra sem data de desfiliação
elif not data_desfiliacao and not filiacao_em_edicao_id and\
not filiacoes.last().data_desfiliacao:
logger.error("O parlamentar não pode se filiar a novo partido sem"
" antes se desfiliar do partido anterior.")
error_msg = _("O parlamentar não pode se filiar a novo partido sem\
antes se desfiliar do partido anterior.")
@ -266,14 +305,20 @@ def validar_datas(data_filiacao, data_desfiliacao, parlamentar, filiacao):
# testa a intercessão de intervalo com outra filiação
if filiacoes.filter(range_livre_exigido).exists():
error_msg = _("A data de filiação e desfiliação não podem estar\
no intervalo de outro período de filiação.")
logger.error("A data de filiação e desfiliação não podem estar"
" no intervalo de outro período de filiação.")
error_msg = _("A data de filiação e desfiliação (intervalo de {} a {}) "
"não podem estar no intervalo de outro período de filiação."
.format(data_filiacao, df_desfiliacao, ))
if not error_msg:
# passou pelo teste de intervalo mas a data de filiação é maior que
# a ultima que está em aberto
if filiacoes.filter(data_desfiliacao__isnull=True,
data__lte=data_filiacao).exists():
logger.error("Não pode haver um registro de filiação com data de "
"filiação igual ou superior a data de filiação em aberto ({})."
.format(data_filiacao))
error_msg = _("Não pode haver um registro de filiação com data de \
filiação igual ou superior a data de filiação em aberto.")
@ -313,6 +358,8 @@ class FiliacaoForm(ModelForm):
class ComposicaoColigacaoForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = ComposicaoColigacao
fields = ['partido']
@ -328,6 +375,8 @@ class ComposicaoColigacaoForm(ModelForm):
if (ComposicaoColigacao.objects.filter(
coligacao_id=pk,
partido=cleaned_data.get('partido')).exists()):
self.logger.error("Esse partido (coligacao_id={} e partido={}) já foi cadastrado "
"nesta coligação.".format(pk, cleaned_data.get('partido')))
msg = _('Esse partido já foi cadastrado nesta coligação.')
raise ValidationError(msg)
@ -335,7 +384,7 @@ class ComposicaoColigacaoForm(ModelForm):
class FrenteForm(ModelForm):
logger = logging.getLogger(__name__)
def __init__(self, *args, **kwargs):
super(FrenteForm, self).__init__(*args, **kwargs)
self.fields['parlamentares'].queryset = Parlamentar.objects.filter(
@ -354,6 +403,8 @@ class FrenteForm(ModelForm):
return self.cleaned_data
if cd['data_extincao'] and cd['data_criacao'] >= cd['data_extincao']:
self.logger.error("Data Dissolução ({}) não pode ser anterior a Data Criação ({})."
.format(cd['data_extincao'],cd['data_criacao']))
raise ValidationError(_("Data Dissolução não pode ser anterior a Data Criação"))
return cd
@ -383,6 +434,8 @@ class VotanteForm(ModelForm):
required=True,
max_length=30)
logger = logging.getLogger(__name__)
class Meta:
model = Votante
fields = ['username']
@ -413,12 +466,15 @@ class VotanteForm(ModelForm):
username = cd['username']
user = get_user_model().objects.filter(username=username)
if not user.exists():
self.logger.error("Não foi possível vincular usuário. Usuário {} não existe.".format(username))
raise ValidationError(_(
"{} [{}] {}".format(
'Não foi possível vincular usuário. Usuário',
username,
'não existe')))
if Votante.objects.filter(user=user[0].pk).exists():
self.logger.error("Não foi possível vincular usuário. Usuário {} já está "
"vinculado à outro parlamentar.".format(username))
raise ValidationError(_(
"{} [{}] {}".format(
'Não foi possível vincular usuário. Usuário',

90
sapl/parlamentares/views.py

@ -1,4 +1,5 @@
import json
import logging
from datetime import datetime
from django.contrib import messages
@ -272,11 +273,16 @@ def parlamentares_frente_selected(request):
"""
:return: Lista com o id dos parlamentares em uma frente
"""
logger = logging.getLogger(__name__)
username = request.user.username
try:
logger.info("user=" + username + ". Tentando objet objeto Frente com id={}.".format(request.GET['frente_id']))
frente = Frente.objects.get(id=int(request.GET['frente_id']))
except ObjectDoesNotExist:
logger.error("user=" + username + ". Frente buscada (id={}) não existe. Retornada lista vazia.".format(request.GET['frente_id']))
lista_parlamentar_id = []
else:
logger.info("user=" + username + ". Frente (id={}) encontrada com sucesso.".format(request.GET['frente_id']))
lista_parlamentar_id = frente.parlamentares.all().values_list(
'id', flat=True)
return JsonResponse({'id_list': list(lista_parlamentar_id)})
@ -354,17 +360,22 @@ class ComposicaoColigacaoCrud(MasterDetailCrud):
class LegislaturaCrud(CrudAux):
model = Legislatura
help_topic = 'legislatura'
class CreateView(CrudAux.CreateView):
logger = logging.getLogger(__name__)
form_class = LegislaturaForm
def get_initial(self):
username = self.request.user.username
try:
self.logger.error("user=" + username + ". Tentando obter última Legislatura.")
ultima_legislatura = Legislatura.objects.latest('numero')
numero = ultima_legislatura.numero + 1
except Legislatura.DoesNotExist:
self.logger.error("user=" + username + ". Legislatura não encontrada. Número definido como 1.")
numero = 1
return {'numero': numero}
@ -456,15 +467,19 @@ class ParlamentarCrud(Crud):
class ListView(Crud.ListView):
template_name = "parlamentares/parlamentares_list.html"
paginate_by = None
logger = logging.getLogger(__name__)
@xframe_options_exempt
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
def take_legislatura_id(self):
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter id da legislatura.")
return int(self.request.GET['pk'])
except:
self.logger.error("user=" + username + ". Legislatura não possui ID. Buscando em todas as entradas.")
legislaturas = Legislatura.objects.all()
for l in legislaturas:
if l.atual():
@ -474,21 +489,26 @@ class ParlamentarCrud(Crud):
return -1
def get_queryset(self):
self.logger = logging.getLogger(__name__)
queryset = super().get_queryset()
legislatura_id = self.take_legislatura_id()
# Pelo menos uma casa legislativa criou uma
# legislatura de numero zero, o que é um absurdo
username = self.request.user.username
if legislatura_id >= 0:
return queryset.filter(
mandato__legislatura_id=legislatura_id).annotate(
mandato_titular=F('mandato__titular'))
else:
try:
self.logger.debug("user=" + username + ". Tentando obter o mais recente registro do objeto Legislatura.")
l = Legislatura.objects.all().order_by(
'-data_inicio').first()
except ObjectDoesNotExist:
self.logger.error("user=" + username + ". Objeto não encontrado. Retornando todos os registros.")
return Legislatura.objects.all()
else:
self.logger.info("user=" + username + ". Objeto encontrado com sucesso.")
if l is None:
return Legislatura.objects.all()
return queryset.filter(mandato__legislatura_id=l).annotate(
@ -500,6 +520,7 @@ class ParlamentarCrud(Crud):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
username = self.request.user.username
# Adiciona legislatura para filtrar parlamentares
legislaturas = Legislatura.objects.all().order_by('-numero')
@ -525,6 +546,9 @@ class ParlamentarCrud(Crud):
# da legislatura e data de desfiliação deve nula, ou maior,
# ou igual a data de fim da legislatura
try:
self.logger.debug("user=" + username + ". Tentando obter filiação do parlamentar com (data<={} e data_desfiliacao>={}) "
"ou (data<={} e data_desfiliacao=Null))."
.format(legislatura.data_fim, legislatura.data_fim, legislatura.data_fim))
filiacao = parlamentar.filiacao_set.get(Q(
data__lte=legislatura.data_fim,
data_desfiliacao__gte=legislatura.data_fim) | Q(
@ -533,17 +557,24 @@ class ParlamentarCrud(Crud):
# Caso não exista filiação com essas condições
except ObjectDoesNotExist:
self.logger.error("user=" + username + ". Parlamentar com (data<={} e data_desfiliacao>={}) "
"ou (data<={} e data_desfiliacao=Null)) não possui filiação."
.format(legislatura.data_fim, legislatura.data_fim, legislatura.data_fim))
row[1] = ('Não possui filiação', None, None)
# Caso exista mais de uma filiação nesse intervalo
# Entretanto, NÃO DEVE OCORRER
except MultipleObjectsReturned:
self.logger.error("user=" + username + ". O Parlamentar com (data<={} e data_desfiliacao>={}) "
"ou (data<={} e data_desfiliacao=Null)) possui duas filiações conflitantes"
.format(legislatura.data_fim, legislatura.data_fim, legislatura.data_fim))
row[1] = (
'O Parlamentar possui duas filiações conflitantes',
None)
# Caso encontre UMA filiação nessas condições
else:
self.logger.info("user=" + username + ". Filiação encontrada com sucesso.")
row[1] = (filiacao.partido.sigla, None, None)
return context
@ -552,6 +583,7 @@ class ParlamentarCrud(Crud):
class ParlamentarMateriasView(FormView):
template_name = "parlamentares/materias.html"
success_url = reverse_lazy('sapl.parlamentares:parlamentar_materia')
logger = logging.getLogger(__name__)
def get_autoria(self, resultset):
autoria = {}
@ -572,13 +604,15 @@ class ParlamentarMateriasView(FormView):
@xframe_options_exempt
def get(self, request, *args, **kwargs):
parlamentar_pk = kwargs['pk']
username = request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter Autor (object_id={}).".format(parlamentar_pk))
autor = Autor.objects.get(
content_type=ContentType.objects.get_for_model(Parlamentar),
object_id=parlamentar_pk)
except ObjectDoesNotExist:
mensagem = _('Este Parlamentar não é autor de matéria.')
mensagem = _('Este Parlamentar (pk={}) não é Autor de matéria.'.format(parlamentar_pk))
self.logger.error("user=" + username + ". Este Parlamentar (pk={}) não é Autor de matéria.".format(parlamentar_pk))
messages.add_message(request, messages.ERROR, mensagem)
return HttpResponseRedirect(
reverse(
@ -620,6 +654,7 @@ class ParlamentarMateriasView(FormView):
class MesaDiretoraView(FormView):
template_name = 'parlamentares/composicaomesa_form.html'
success_url = reverse_lazy('sapl.parlamentares:mesa_diretora')
logger = logging.getLogger(__name__)
def get_template_names(self):
if self.request.user.has_perm('parlamentares.change_composicaomesa'):
@ -633,6 +668,10 @@ class MesaDiretoraView(FormView):
# Essa função avisa quando se pode compor uma Mesa Legislativa
def validation(self, request):
username = request.user.username
self.logger.info('user=' + username + '. Não há nenhuma Sessão Legislativa cadastrada. ' +
'Só é possível compor uma Mesa Diretora quando ' +
'há uma Sessão Legislativa cadastrada.')
mensagem = _('Não há nenhuma Sessão Legislativa cadastrada. ' +
'Só é possível compor uma Mesa Diretora quando ' +
'há uma Sessão Legislativa cadastrada.')
@ -698,9 +737,11 @@ def altera_field_mesa(request):
operação (Legislatura/Sessão/Inclusão/Remoção),
atualizando os campos após cada alteração
"""
logger = logging.getLogger(__name__)
legislatura = request.GET['legislatura']
sessoes = SessaoLegislativa.objects.filter(
legislatura=legislatura).order_by('-data_inicio')
username = request.user.username
if not sessoes:
return JsonResponse({'msg': ('Nenhuma sessão encontrada!', 0)})
@ -715,8 +756,11 @@ def altera_field_mesa(request):
else:
year = timezone.now().year
try:
logger.debug("user=" + username + ". Tentando obter id de sessoes com data_inicio.ano={}.".format(year))
sessao_selecionada = sessoes.get(data_inicio__year=year).id
except ObjectDoesNotExist:
logger.error("user=" + username + ". Id de sessoes com data_inicio.ano={} não encontrado. "
"Selecionado o ID da primeira sessão.".format(year))
sessao_selecionada = sessoes.first().id
# Atualiza os componentes da view após a mudança
@ -756,7 +800,8 @@ def insere_parlamentar_composicao(request):
Essa função lida com qualquer operação de inserção
na composição da Mesa Diretora
"""
logger = logging.getLogger(__name__)
username = request.user.username
if request.user.has_perm(
'%s.add_%s' % (
AppConfig.label, ComposicaoMesa._meta.model_name)):
@ -764,19 +809,24 @@ def insere_parlamentar_composicao(request):
composicao = ComposicaoMesa()
try:
logger.debug("user=" + username + ". Tentando obter SessaoLegislativa com id={}.".format(request.POST['sessao']))
composicao.sessao_legislativa = SessaoLegislativa.objects.get(
id=int(request.POST['sessao']))
except MultiValueDictKeyError:
logger.error("user=" + username + ". 'MultiValueDictKeyError', nenhuma sessão foi inserida!")
return JsonResponse({'msg': ('Nenhuma sessão foi inserida!', 0)})
try:
logger.debug("user=" + username + ". Tentando obter Parlamentar com id={}.".format(request.POST['parlamentar']))
composicao.parlamentar = Parlamentar.objects.get(
id=int(request.POST['parlamentar']))
except MultiValueDictKeyError:
logger.error("user=" + username + ". 'MultiValueDictKeyError', nenhum parlamentar foi inserido!")
return JsonResponse({
'msg': ('Nenhum parlamentar foi inserido!', 0)})
try:
logger.info("user=" + username + ". Tentando obter CargoMesa com id={}.".format(request.POST['cargo']))
composicao.cargo = CargoMesa.objects.get(
id=int(request.POST['cargo']))
parlamentar_ja_inserido = ComposicaoMesa.objects.filter(
@ -789,11 +839,14 @@ def insere_parlamentar_composicao(request):
composicao.save()
except MultiValueDictKeyError:
logger.error("user=" + username + ". 'MultiValueDictKeyError', nenhum cargo foi inserido!")
return JsonResponse({'msg': ('Nenhum cargo foi inserido!', 0)})
logger.info("user=" + username + ". Parlamentar inserido com sucesso!")
return JsonResponse({'msg': ('Parlamentar inserido com sucesso!', 1)})
else:
logger.error("user=" + username + " não tem permissão para esta operação!")
return JsonResponse(
{'msg': ('Você não tem permissão para esta operação!', 0)})
@ -803,26 +856,32 @@ def remove_parlamentar_composicao(request):
Essa função lida com qualquer operação de remoção
na composição da Mesa Diretora
"""
logger = logging.getLogger(__name__)
username = request.user.username
if request.POST and request.user.has_perm(
'%s.delete_%s' % (
AppConfig.label, ComposicaoMesa._meta.model_name)):
if 'composicao_mesa' in request.POST:
try:
logger.debug("user=" + username + ". Tentando obter ComposicaoMesa com id={}.".format(request.POST['composicao_mesa']))
composicao = ComposicaoMesa.objects.get(
id=request.POST['composicao_mesa'])
except ObjectDoesNotExist:
logger.error("user=" + username + ". ComposicaoMesa com id={} não encontrada, portanto não pode ser removida."
.format(request.POST['composicao_mesa']))
return JsonResponse(
{'msg': (
'Composição da Mesa não pôde ser removida!', 0)})
composicao.delete()
logger.info("user=" + username + ". ComposicaoMesa com id={} excluido com sucesso!".format(request.POST['composicao_mesa']))
return JsonResponse(
{'msg': (
'Parlamentar excluido com sucesso!', 1)})
else:
logger.info("user=" + username + ". Nenhum parlamentar escolhido para ser excluído.")
return JsonResponse(
{'msg': (
'Selecione algum parlamentar para ser excluido!', 0)})
@ -838,7 +897,13 @@ def partido_parlamentar_sessao_legislativa(sessao, parlamentar):
# A data de filiacao deve ser menor que a data de fim
# da sessao legislativa e data de desfiliação deve nula, ou maior,
# ou igual a data de fim da sessao
logger = logging.getLogger(__name__)
try:
logger.debug("Tentando obter filiação do parlamentar com (data<={} e data_desfiliacao>={}) "
"ou (data<={} e data_desfiliacao=Null))."
.format(sessao.data_fim, sessao.data_fim, sessao.data_fim))
logger.info("Tentando obter filiação correspondente.")
filiacao = parlamentar.filiacao_set.get(Q(
data__lte=sessao.data_fim,
data_desfiliacao__gte=sessao.data_fim) | Q(
@ -847,15 +912,24 @@ def partido_parlamentar_sessao_legislativa(sessao, parlamentar):
# Caso não exista filiação com essas condições
except ObjectDoesNotExist:
logger.error("Filiação do parlamentar com (data<={} e data_desfiliacao>={}) "
"ou (data<={} e data_desfiliacao=Null não encontrada. Retornando vazio."
.format(sessao.data_fim, sessao.data_fim, sessao.data_fim))
return ''
# Caso exista mais de uma filiação nesse intervalo
# Entretanto, NÃO DEVE OCORRER
except MultipleObjectsReturned:
logger.error("O Parlamentar com (data<={} e data_desfiliacao>={}) "
"ou (data<={} e data_desfiliacao=Null possui duas filiações conflitantes."
.format(sessao.data_fim, sessao.data_fim, sessao.data_fim))
return 'O Parlamentar possui duas filiações conflitantes'
# Caso encontre UMA filiação nessas condições
else:
logger.info("Filiação do parlamentar com (data<={} e data_desfiliacao>={}) "
"ou (data<={} e data_desfiliacao=Null encontrada com sucesso."
.format(sessao.data_fim, sessao.data_fim, sessao.data_fim))
return filiacao.partido.sigla
@ -865,7 +939,8 @@ def altera_field_mesa_public_view(request):
da Mesa Diretora para usuários anônimos,
atualizando os campos após cada alteração
"""
logger = logging.getLogger(__name__)
username = request.user.username
legislatura = request.GET['legislatura']
sessoes = SessaoLegislativa.objects.filter(
legislatura=legislatura).order_by('-data_inicio')
@ -882,8 +957,11 @@ def altera_field_mesa_public_view(request):
else:
try:
year = timezone.now().year
logger.info("user=" + username + ". Tentando obter sessões com data_inicio.ano = {}.".format(year))
sessao_selecionada = sessoes.get(data_inicio__year=year).id
except ObjectDoesNotExist as e:
except ObjectDoesNotExist:
logger.error("user=" + username + ". Sessões não encontradas com com data_inicio.ano = {}. "
"Selecionado o id da primeira sessão.".format(year))
sessao_selecionada = sessoes.first().id
# Atualiza os componentes da view após a mudança

72
sapl/protocoloadm/forms.py

@ -1,5 +1,6 @@
import django_filters
import logging
from crispy_forms.bootstrap import InlineRadios
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout
@ -65,7 +66,7 @@ class AcompanhamentoDocumentoForm(ModelForm):
class ProtocoloFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
filter_overrides = {models.DateTimeField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': 'Data (%s)' % (_('Inicial - Final')),
@ -101,7 +102,7 @@ class ProtocoloFilterSet(django_filters.FilterSet):
model = Protocolo
fields = ['numero',
'tipo_documento',
'data',
'timestamp',
'tipo_materia',
]
@ -114,7 +115,7 @@ class ProtocoloFilterSet(django_filters.FilterSet):
row1 = to_row(
[('numero', 4),
('ano', 4),
('data', 4)])
('timestamp', 4)])
row2 = to_row(
[('tipo_documento', 4),
@ -226,6 +227,8 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
class AnularProcoloAdmForm(ModelForm):
logger = logging.getLogger(__name__)
numero = forms.CharField(required=True,
label=Protocolo._meta.
get_field('numero').verbose_name
@ -252,12 +255,15 @@ class AnularProcoloAdmForm(ModelForm):
ano = cleaned_data['ano']
try:
self.logger.debug("Tentando obter Protocolo com numero={} e ano={}.".format(numero, ano))
protocolo = Protocolo.objects.get(numero=numero, ano=ano)
if protocolo.anulado:
self.logger.error("Protocolo %s/%s já encontra-se anulado" % (numero, ano))
raise forms.ValidationError(
_("Protocolo %s/%s já encontra-se anulado")
% (numero, ano))
except ObjectDoesNotExist:
self.logger.error("Protocolo %s/%s não existe" % (numero, ano))
raise forms.ValidationError(
_("Protocolo %s/%s não existe" % (numero, ano)))
@ -270,6 +276,8 @@ class AnularProcoloAdmForm(ModelForm):
).order_by('-ano', '-numero').exists()
if exists:
self.logger.error("Protocolo %s/%s não pode ser removido pois existem "
"documentos vinculados a ele." % (numero, ano))
raise forms.ValidationError(
_("Protocolo %s/%s não pode ser removido pois existem "
"documentos vinculados a ele." % (numero, ano)))
@ -386,6 +394,9 @@ class ProtocoloDocumentForm(ModelForm):
class ProtocoloMateriaForm(ModelForm):
logger = logging.getLogger(__name__)
autor = forms.ModelChoiceField(required=True,
empty_label='------',
queryset=Autor.objects.all()
@ -441,10 +452,13 @@ class ProtocoloMateriaForm(ModelForm):
def clean_autor(self):
autor_field = self.cleaned_data['autor']
try:
self.logger.debug("Tentando obter Autor com id={}.".format(autor_field.id))
autor = Autor.objects.get(id=autor_field.id)
except ObjectDoesNotExist:
self.logger.error("Autor com id={} não encontrado. Definido como None.".format(autor_field.id))
autor_field = None
else:
self.logger.info("Autor com id={} encontrado com sucesso.".format(autor_field.id))
autor_field = autor
return autor_field
@ -459,15 +473,22 @@ class ProtocoloMateriaForm(ModelForm):
if data['vincular_materia'] == 'True':
try:
if not data['ano_materia'] or not data['numero_materia']:
self.logger.error("Não foram informados o número ou ano da matéria a ser vinculada")
raise ValidationError(
'Favor informar o número e ano da matéria a ser vinculada')
self.logger.debug("Tentando obter MateriaLegislativa com ano={}, numero={} e data={}."
.format(data['ano_materia'], data['numero_materia'], data['tipo_materia']))
self.materia = MateriaLegislativa.objects.get(ano=data['ano_materia'],
numero=data['numero_materia'],
tipo=data['tipo_materia'])
if self.materia.numero_protocolo:
self.logger.error("MateriaLegislativa informada já possui o protocolo {}/{} vinculado."
.format(self.materia.numero_protocolo, self.materia.ano))
raise ValidationError(_('Matéria Legislativa informada já possui o protocolo {}/{} vinculado.'
.format(self.materia.numero_protocolo, self.materia.ano)))
except ObjectDoesNotExist:
self.logger.error("MateriaLegislativa informada (ano={}, numero={} e data={}) não existente."
.format(data['ano_materia'], data['numero_materia'], data['tipo_materia']))
raise ValidationError(_('Matéria Legislativa informada não existente.'))
return data
@ -528,6 +549,8 @@ class DocumentoAcessorioAdministrativoForm(ModelForm):
class TramitacaoAdmForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = TramitacaoAdministrativo
fields = ['data_tramitacao',
@ -565,11 +588,17 @@ class TramitacaoAdmForm(ModelForm):
if ultima_tramitacao:
destino = ultima_tramitacao.unidade_tramitacao_destino
if (destino != self.cleaned_data['unidade_tramitacao_local']):
self.logger.error('A origem da nova tramitação ({}) deve ser '
'igual ao destino ({}) da última adicionada!'
.format(self.cleaned_data['unidade_tramitacao_local'], destino))
msg = _('A origem da nova tramitação deve ser igual ao '
'destino da última adicionada!')
raise ValidationError(msg)
if self.cleaned_data['data_tramitacao'] > timezone.now().date():
self.logger.error('A data de tramitação ({}) deve ser '
'menor ou igual a data de hoje ({})!'
.format(self.cleaned_data['data_tramitacao'], timezone.now().date()))
msg = _(
'A data de tramitação deve ser ' +
'menor ou igual a data de hoje!')
@ -577,18 +606,27 @@ class TramitacaoAdmForm(ModelForm):
if (ultima_tramitacao and
data_tram_form < ultima_tramitacao.data_tramitacao):
self.logger.error('A data da nova tramitação ({}) deve ser '
'maior que a data da última tramitação ({})!'
.format(data_tram_form, ultima_tramitacao.data_tramitacao))
msg = _('A data da nova tramitação deve ser ' +
'maior que a data da última tramitação!')
raise ValidationError(msg)
if data_enc_form:
if data_enc_form < data_tram_form:
self.logger.error('A data de encaminhamento ({}) deve ser '
'maior que a data de tramitação ({})!'
.format(data_enc_form, data_tram_form))
msg = _('A data de encaminhamento deve ser ' +
'maior que a data de tramitação!')
raise ValidationError(msg)
if data_prazo_form:
if data_prazo_form < data_tram_form:
self.logger.error('A data fim de prazo ({}) deve ser '
'maior que a data de tramitação ({})!'
.format(data_prazo_form, data_tram_form))
msg = _('A data fim de prazo deve ser ' +
'maior que a data de tramitação!')
raise ValidationError(msg)
@ -604,6 +642,8 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
data_tramitacao = forms.DateField(widget=forms.HiddenInput())
logger = logging.getLogger(__name__)
class Meta:
model = TramitacaoAdministrativo
fields = ['data_tramitacao',
@ -631,6 +671,9 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
if ultima_tramitacao != self.instance:
if self.cleaned_data['unidade_tramitacao_destino'] != \
self.instance.unidade_tramitacao_destino:
self.logger.error('Você não pode mudar a Unidade de Destino desta '
'tramitação (id={}), pois irá conflitar com a Unidade '
'Local da tramitação seguinte'.format(self.instance.documento_id))
raise ValidationError(
'Você não pode mudar a Unidade de Destino desta '
'tramitação, pois irá conflitar com a Unidade '
@ -646,6 +689,8 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
class DocumentoAdministrativoForm(ModelForm):
logger = logging.getLogger(__name__)
data = forms.DateField(initial=timezone.now)
ano_protocolo = forms.ChoiceField(required=False,
@ -711,19 +756,26 @@ class DocumentoAdministrativoForm(ModelForm):
tipo=tipo_documento,
ano=ano_protocolo).exists()
if doc_exists:
self.logger.error("DocumentoAdministrativo (numero={}, tipo={} e ano={}) já existe."
.format(numero_documento, tipo_documento, ano_protocolo))
raise ValidationError(_('Documento já existente'))
# campos opcionais, mas que se informados devem ser válidos
if numero_protocolo and ano_protocolo:
try:
self.logger.debug("Tentando obter Protocolo com numero={} e ano={}."
.format(numero_protocolo, ano_protocolo))
self.fields['protocolo'].initial = Protocolo.objects.get(
numero=numero_protocolo,
ano=ano_protocolo).pk
except ObjectDoesNotExist:
self.logger.error("Protocolo %s/%s inexistente." % (
numero_protocolo, ano_protocolo))
msg = _('Protocolo %s/%s inexistente.' % (
numero_protocolo, ano_protocolo))
raise ValidationError(msg)
except MultipleObjectsReturned:
self.logger.error("Existe mais de um Protocolo com este ano ({}) e número ({}).".format(ano_protocolo,numero_protocolo))
msg = _(
'Existe mais de um Protocolo com este ano e número.' % (
numero_protocolo, ano_protocolo))
@ -741,6 +793,8 @@ class DocumentoAdministrativoForm(ModelForm):
protocolo__numero=numero_protocolo,
protocolo__ano=ano_protocolo).exists()
if exist_materia or exist_doc:
self.logger.error('Protocolo com numero=%s e ano=%s já possui'
' documento vinculado' % (numero_protocolo, ano_protocolo))
raise ValidationError(_('Protocolo %s/%s já possui'
' documento vinculado'
% (numero_protocolo, ano_protocolo)))
@ -792,6 +846,8 @@ class DocumentoAdministrativoForm(ModelForm):
class DesvincularDocumentoForm(ModelForm):
logger = logging.getLogger(__name__)
numero = forms.CharField(required=True,
label=DocumentoAdministrativo._meta.
get_field('numero').verbose_name
@ -815,11 +871,15 @@ class DesvincularDocumentoForm(ModelForm):
tipo = cleaned_data['tipo']
try:
self.logger.debug("Tentando obter DocumentoAdministrativo com numero={}, ano={} e tipo={}."
.format(numero, ano, tipo))
documento = DocumentoAdministrativo.objects.get(numero=numero, ano=ano, tipo=tipo)
if not documento.protocolo:
self.logger.error("DocumentoAdministrativo %s %s/%s não se encontra vinculado a nenhum protocolo." % (tipo, numero, ano))
raise forms.ValidationError(
_("%s %s/%s não se encontra vinculado a nenhum protocolo" % (tipo, numero, ano)))
except ObjectDoesNotExist:
self.logger.error("DocumentoAdministrativo %s %s/%s não existe" % (tipo, numero, ano))
raise forms.ValidationError(
_("%s %s/%s não existe" % (tipo, numero, ano)))
@ -853,6 +913,8 @@ class DesvincularDocumentoForm(ModelForm):
class DesvincularMateriaForm(forms.Form):
logger = logging.getLogger(__name__)
numero = forms.CharField(required=True,
label=_('Número da Matéria'))
ano = forms.ChoiceField(required=True,
@ -877,11 +939,15 @@ class DesvincularMateriaForm(forms.Form):
tipo = cleaned_data['tipo']
try:
self.logger.info("Tentando obter MateriaLegislativa com numero={}, ano={} e tipo={}."
.format(numero, ano, tipo))
materia = MateriaLegislativa.objects.get(numero=numero, ano=ano, tipo=tipo)
if not materia.numero_protocolo:
self.logger.error("MateriaLegislativa %s %s/%s não se encontra vinculada a nenhum protocolo" % (tipo, numero, ano))
raise forms.ValidationError(
_("%s %s/%s não se encontra vinculada a nenhum protocolo" % (tipo, numero, ano)))
except ObjectDoesNotExist:
self.logger.error("MateriaLegislativa %s %s/%s não existe" % (tipo, numero, ano))
raise forms.ValidationError(
_("%s %s/%s não existe" % (tipo, numero, ano)))

83
sapl/protocoloadm/views.py

@ -21,8 +21,9 @@ from django.views.generic.edit import FormView
from django_filters.views import FilterView
import sapl
from sapl.base.models import Autor, CasaLegislativa
import logging
from sapl.comissoes.models import Comissao
from sapl.base.models import Autor, CasaLegislativa
from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.parlamentares.models import Legislatura, Parlamentar
@ -59,7 +60,10 @@ def recuperar_materia_protocolo(request):
tipo = request.GET.get('tipo')
ano = request.GET.get('ano')
numero = request.GET.get('numero')
logger = logging.getLogger(__name__)
username = request.user.username
try:
logger.debug("user=" + username + ". Tentando obter matéria com tipo={}, ano={} e numero={}.".format(tipo, ano, numero))
materia = MateriaLegislativa.objects.get(
tipo=tipo, ano=ano,numero=numero)
autoria = materia.autoria_set.first()
@ -70,6 +74,7 @@ def recuperar_materia_protocolo(request):
'tipo_autor':autoria.autor.tipo.pk})
response = JsonResponse(content)
except Exception as e:
logger.error("user=" + username + ". " + str(e))
response = JsonResponse({'error':e})
return response
@ -99,7 +104,11 @@ def doc_texto_integral(request, pk):
class AcompanhamentoConfirmarView(TemplateView):
logger = logging.getLogger(__name__)
def get_redirect_url(self, email):
username = self.request.user.username
self.logger.info('user=' + username + '. Este documento está sendo acompanhado pelo e-mail: {}'.format(email))
msg = _('Este documento está sendo acompanhado pelo e-mail: %s') % (
email)
messages.add_message(self.request, messages.SUCCESS, msg)
@ -109,12 +118,16 @@ class AcompanhamentoConfirmarView(TemplateView):
def get(self, request, *args, **kwargs):
documento_id = kwargs['pk']
hash_txt = request.GET.get('hash_txt', '')
username = request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter objeto AcompanhamentoDocumento com documento_id={} e hash={}"
.format(documento_id, hash_txt))
acompanhar = AcompanhamentoDocumento.objects.get(
documento_id=documento_id,
hash=hash_txt)
except ObjectDoesNotExist:
except ObjectDoesNotExist as e:
self.logger.error("user=" + username + ". " + str(e))
raise Http404()
# except MultipleObjectsReturned:
# A melhor solução deve ser permitir que a exceção
@ -129,21 +142,28 @@ class AcompanhamentoConfirmarView(TemplateView):
class AcompanhamentoExcluirView(TemplateView):
logger = logging.getLogger(__name__)
def get_success_url(self):
username = self.request.user.username
self.logger.info("user=" + username + ". Você parou de acompanhar este Documento (pk={}).".format(self.kwargs['pk']))
msg = _('Você parou de acompanhar este Documento.')
messages.add_message(self.request, messages.INFO, msg)
return reverse('sapl.protocoloadm:documentoadministrativo_detail',
kwargs={'pk': self.kwargs['pk']})
def get(self, request, *args, **kwargs):
materia_id = kwargs['pk']
documento_id = kwargs['pk']
hash_txt = request.GET.get('hash_txt', '')
username = request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter AcompanhamentoDocumento com documento_id={} e hash={}."
.format(documento_id, hash_txt))
AcompanhamentoDocumento.objects.get(documento_id=documento_id,
hash=hash_txt).delete()
except ObjectDoesNotExist:
pass
self.logger.error("user=" + username + ". AcompanhamentoDocumento com documento_id={} e hash={} não encontrado."
.format(documento_id, hash_txt))
return HttpResponseRedirect(self.get_success_url())
@ -151,6 +171,8 @@ class AcompanhamentoExcluirView(TemplateView):
class AcompanhamentoDocumentoView(CreateView):
template_name = "protocoloadm/acompanhamento_documento.html"
logger = logging.getLogger(__name__)
def get_random_chars(self):
s = ascii_letters + digits
return ''.join(choice(s) for i in range(choice([6, 7])))
@ -200,7 +222,9 @@ class AcompanhamentoDocumentoView(CreateView):
"documento",
documento,
destinatario)
self.logger.info('user={} .Foi enviado um e-mail de confirmação. Confira sua caixa '
'de mensagens e clique no link que nós enviamos para '
'confirmar o acompanhamento deste documento.'.format(usuario.username))
msg = _('Foi enviado um e-mail de confirmação. Confira sua caixa \
de mensagens e clique no link que nós enviamos para \
confirmar o acompanhamento deste documento.')
@ -209,6 +233,7 @@ class AcompanhamentoDocumentoView(CreateView):
# Caso esse Acompanhamento já exista
# avisa ao usuário que esse documento já está sendo acompanhado
else:
self.logger.info('user=' + request.user.username + '. Este e-mail já está acompanhando esse documento (pk={}).'.format(pk))
msg = _('Este e-mail já está acompanhando esse documento.')
messages.add_message(request, messages.INFO, msg)
@ -433,6 +458,9 @@ class AnularProtocoloAdmView(PermissionRequiredMixin, CreateView):
class ProtocoloDocumentoView(PermissionRequiredMixin,
FormValidMessageMixin,
CreateView):
logger = logging.getLogger(__name__)
template_name = "protocoloadm/protocolar_documento.html"
form_class = ProtocoloDocumentForm
form_valid_message = _('Protocolo cadastrado com sucesso!')
@ -444,10 +472,14 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
def form_valid(self, form):
protocolo = form.save(commit=False)
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter sequência de numeração.")
numeracao = sapl.base.models.AppConfig.objects.last(
).sequencia_numeracao
except AttributeError:
except AttributeError as e:
self.logger.error("user=" + username + ". É preciso definir a sequencia de "
"numeração na tabelas auxiliares! " + str(e))
msg = _('É preciso definir a sequencia de ' +
'numeração na tabelas auxiliares!')
messages.add_message(self.request, messages.ERROR, msg)
@ -474,7 +506,8 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
if not protocolo.numero:
protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1
elif protocolo.numero < (numero['numero__max'] + 1) if numero['numero__max'] else 0:
msg = _('Número de protocolo deve ser maior que {}').format(numero['numero__max'])
msg = _('Número de protocolo deve ser maior que {}'.format(numero['numero__max']))
self.logger.error("user=" + username + ". Número de protocolo deve ser maior que {}.".format(numero['numero__max']))
messages.add_message(self.request, messages.ERROR, msg)
return self.render_to_response(self.get_context_data())
protocolo.ano = timezone.now().year
@ -518,21 +551,30 @@ class CriarDocumentoProtocolo(PermissionRequiredMixin, CreateView):
class ProtocoloMostrarView(PermissionRequiredMixin, TemplateView):
logger = logging.getLogger(__name__)
template_name = "protocoloadm/protocolo_mostrar.html"
permission_required = ('protocoloadm.detail_protocolo', )
def get_context_data(self, **kwargs):
context = super(ProtocoloMostrarView, self).get_context_data(**kwargs)
protocolo = Protocolo.objects.get(pk=self.kwargs['pk'])
username = self.request.user.username
if protocolo.tipo_materia:
try:
self.logger.debug("user=" + username + ". Tentando obter objeto MateriaLegislativa com numero_protocolo={} e ano={}."
.format(protocolo.numero, protocolo.ano))
materia = MateriaLegislativa.objects.get(
numero_protocolo=protocolo.numero, ano=protocolo.ano)
except ObjectDoesNotExist:
self.logger.error("user=" + username + ". Objeto MateriaLegislativa com numero_protocolo={} e ano={} não encontrado."
" Definido como None.".format(protocolo.numero, protocolo.ano))
context['materia'] = None
else:
self.logger.info("user=" + username + ". Objeto MateriaLegislativa com numero_protocolo={} e ano={} encontrado"
"com sucesso.".format(protocolo.numero, protocolo.ano))
context['materia'] = materia
if protocolo.tipo_documento:
@ -577,6 +619,8 @@ class ComprovanteProtocoloView(PermissionRequiredMixin, TemplateView):
class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
logger = logging.getLogger(__name__)
template_name = "protocoloadm/protocolar_materia.html"
form_class = ProtocoloMateriaForm
form_valid_message = _('Matéria cadastrada com sucesso!')
@ -588,10 +632,14 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
def form_valid(self, form):
protocolo = form.save(commit=False)
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter sequência de numeração.")
numeracao = sapl.base.models.AppConfig.objects.last(
).sequencia_numeracao
except AttributeError:
self.logger.error("user=" + username + ". É preciso definir a sequencia de "
"numeração na tabelas auxiliares!")
msg = _('É preciso definir a sequencia de ' +
'numeração na tabelas auxiliares!')
messages.add_message(self.request, messages.ERROR, msg)
@ -620,6 +668,8 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1
if numero['numero__max']:
if protocolo.numero < (numero['numero__max'] + 1):
self.logger.error("user=" + username + ". Número de protocolo ({}) é menor que {}"
.format(protocolo.numero, numero['numero__max']))
msg = _('Número de protocolo deve ser maior que {}').format(numero['numero__max'])
messages.add_message(self.request, messages.ERROR, msg)
return self.render_to_response(self.get_context_data())
@ -772,7 +822,13 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
self.filterset.form.fields['o'].label = _('Ordenação')
# é usada essa verificação anônima para quando os documentos administrativos
# estão no modo ostensivo, mas podem existir documentos administrativos restritos
if request.user.is_anonymous():
length = self.object_list.filter(restrito=False).count()
else:
length = self.object_list.count()
context = self.get_context_data(filter=self.filterset,
filter_url=url,
numero_res=length
@ -795,6 +851,7 @@ class TramitacaoAdmCrud(MasterDetailCrud):
class CreateView(MasterDetailCrud.CreateView):
form_class = TramitacaoAdmForm
logger = logging.getLogger(__name__)
def get_initial(self):
initial = super(CreateView, self).get_initial()
@ -826,13 +883,16 @@ class TramitacaoAdmCrud(MasterDetailCrud):
def form_valid(self, form):
self.object = form.save()
username = self.request.user.username
try:
tramitacao_signal.send(sender=TramitacaoAdministrativo,
post=self.object,
request=self.request)
except Exception as e:
# TODO log error
self.logger.error('user=' + username + '. Tramitação criada, mas e-mail de acompanhamento de documento '
'não enviado. A não configuração do servidor de e-mail '
'impede o envio de aviso de tramitação. ' + str(e))
msg = _('Tramitação criada, mas e-mail de acompanhamento '
'de documento não enviado. A não configuração do'
' servidor de e-mail impede o envio de aviso de tramitação')
@ -842,14 +902,19 @@ class TramitacaoAdmCrud(MasterDetailCrud):
class UpdateView(MasterDetailCrud.UpdateView):
form_class = TramitacaoAdmEditForm
logger = logging.getLogger(__name__)
def form_valid(self, form):
self.object = form.save()
username = self.request.user.username
try:
tramitacao_signal.send(sender=TramitacaoAdministrativo,
post=self.object,
request=self.request)
except Exception as e:
# TODO log error
self.logger.error('user=' + username + '. Tramitação criada, mas e-mail de acompanhamento de documento '
'não enviado. A não configuração do servidor de e-mail '
'impede o envio de aviso de tramitação. ' + str(e))
msg = _('Tramitação criada, mas e-mail de acompanhamento '
'de documento não enviado. A não configuração do'
' servidor de e-mail impede o envio de aviso de tramitação')

140
sapl/redireciona_urls/views.py

@ -1,3 +1,5 @@
import logging
from django.core.urlresolvers import NoReverseMatch, reverse
from django.views.generic import RedirectView
@ -71,12 +73,16 @@ def has_iframe(url, request):
class RedirecionaSAPLIndex(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url_pattern = 'sapl_index'
username = self.request.user.username
try:
self.logger.info("user=" + username + ". Tentando obter url.")
url = reverse(url_pattern)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(url_pattern)
url = has_iframe(url, self.request)
@ -86,23 +92,30 @@ class RedirecionaSAPLIndex(RedirectView):
class RedirecionaParlamentar(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
pk_parlamentar = self.request.GET.get(
'cod_parlamentar',
EMPTY_STRING)
username = self.request.user.username
if pk_parlamentar:
try:
kwargs = {'pk': pk_parlamentar}
self.logger.debug("user=" + username + ". Tentando obter url correspondente.")
url = reverse(parlamentar_detail, kwargs=kwargs)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(parlamentar_detail, kwargs=kwargs)
else:
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(parlamentar_list)
except NoReverseMatch:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(parlamentar_list)
numero_legislatura = self.request.GET.get(
@ -119,22 +132,28 @@ class RedirecionaParlamentar(RedirectView):
class RedirecionaComissao(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
pk_comissao = self.request.GET.get('cod_comissao', EMPTY_STRING)
username = self.request.user.username
if pk_comissao:
kwargs = {'pk': pk_comissao}
try:
self.logger.debug("user=" + username + ". Tentando obter url correspondente.")
url = reverse(comissao_detail, kwargs=kwargs)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(comissao_detail)
else:
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(comissao_list)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(comissao_list)
url = has_iframe(url, self.request)
@ -144,24 +163,30 @@ class RedirecionaComissao(RedirectView):
class RedirecionaComposicaoComissao(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
pk_composicao = self.request.GET.get(
'cod_periodo_comp_sel', EMPTY_STRING)
pk_comissao = self.request.GET.get('cod_comissao', EMPTY_STRING)
username = self.request.user.username
if pk_comissao:
kwargs = {'pk': pk_comissao}
try:
self.logger.debug("user=" + username + ". Tentando obter url correspondente.")
url = reverse(comissao_detail, kwargs=kwargs)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(comissao_detail)
else:
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(comissao_list)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(comissao_list)
url = has_iframe(url, self.request)
@ -171,22 +196,29 @@ class RedirecionaComposicaoComissao(RedirectView):
class RedirecionaPautaSessao(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
pk_sessao_plenaria = self.request.GET.get(
'cod_sessao_plen',
EMPTY_STRING)
username = self.request.user.username
if pk_sessao_plenaria:
kwargs = {'pk': pk_sessao_plenaria}
try:
self.logger.debug("user=" + username + ". Tentando obter url correspondente.")
url = reverse(pauta_sessao_detail, kwargs=kwargs)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(pauta_sessao_detail)
else:
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(pauta_sessao_list)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(pauta_sessao_list)
data_sessao_plenaria = self.request.GET.get(
@ -212,23 +244,29 @@ class RedirecionaPautaSessao(RedirectView):
class RedirecionaSessaoPlenaria(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
pk_sessao_plenaria = self.request.GET.get(
'cod_sessao_plen',
EMPTY_STRING)
url = EMPTY_STRING
username = self.request.user.username
if pk_sessao_plenaria:
kwargs = {'pk': pk_sessao_plenaria}
try:
self.logger.debug("user=" + username + ". Tentando obter url correspondente.")
url = reverse(sessao_plenaria_detail, kwargs=kwargs)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(sessao_plenaria_detail)
else:
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(sessao_plenaria_list)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(sessao_plenaria_list)
year = self.request.GET.get(
@ -261,12 +299,17 @@ class RedirecionaSessaoPlenaria(RedirectView):
class RedirecionaRelatoriosList(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(relatorios_list)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(relatorios_list)
url = has_iframe(url, self.request)
@ -276,12 +319,16 @@ class RedirecionaRelatoriosList(RedirectView):
class RedirecionaRelatoriosMateriasEmTramitacaoList(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(relatorio_materia_por_tramitacao)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(relatorio_materia_por_tramitacao)
year = self.request.GET.get(
@ -339,13 +386,17 @@ class RedirecionaMateriaLegislativaDetail(RedirectView):
class RedirecionaMateriaLegislativaList(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
args = EMPTY_STRING
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(materialegislativa_list)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(materialegislativa_list)
tipo_materia = self.request.GET.get(
@ -414,12 +465,17 @@ class RedirecionaMateriaLegislativaList(RedirectView):
class RedirecionaMesaDiretoraView(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(parlamentar_mesa_diretora)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(parlamentar_mesa_diretora)
url = has_iframe(url, self.request)
@ -447,14 +503,18 @@ class RedirecionaNormasJuridicasDetail(RedirectView):
class RedirecionaNormasJuridicasTextoIntegral(RedirectView):
permanent = False
logger = logging.getLogger(__name__)
def get_redirect_url(self, **kwargs):
url = EMPTY_STRING
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter NormaJuridica com pk={}.".format(kwargs['norma_id']))
norma = NormaJuridica.objects.get(pk=kwargs['norma_id'])
if norma:
url = norma.texto_integral.url
except Exception as e:
self.logger.error("user=" + username + ". Erro ao obter NormaJuridica com pk={}. ".format(kwargs['norma_id']) + str(e))
raise e
url = has_iframe(url, self.request)
@ -465,13 +525,17 @@ class RedirecionaNormasJuridicasTextoIntegral(RedirectView):
class RedirecionaNormasJuridicasList(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
args = EMPTY_STRING
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(norma_juridica_pesquisa)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(norma_juridica_pesquisa)
tipo_norma = self.request.GET.get(
@ -523,13 +587,18 @@ class RedirecionaNormasJuridicasList(RedirectView):
class RedirecionaHistoricoTramitacoesList(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
args = EMPTY_STRING
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(historico_tramitacoes)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(historico_tramitacoes)
inicio_intervalo_data_tramitacao = self.request.GET.get(
@ -580,13 +649,18 @@ class RedirecionaHistoricoTramitacoesList(RedirectView):
class RedirecionaAtasList(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
args = EMPTY_STRING
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(pesquisar_atas)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(pesquisar_atas)
inicio_intervalo_data_ata = self.request.GET.get(
@ -614,13 +688,18 @@ class RedirecionaAtasList(RedirectView):
class RedirecionaPresencaParlamentares(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
args = EMPTY_STRING
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(presenca_sessao)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(presenca_sessao)
inicio_intervalo_data_presenca_parlamentar = self.request.GET.get(
@ -648,12 +727,16 @@ class RedirecionaPresencaParlamentares(RedirectView):
class RedirecionaMateriasPorAutor(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(relatorio_materia_por_autor)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(relatorio_materia_por_autor)
url = has_iframe(url, self.request)
@ -664,14 +747,18 @@ class RedirecionaMateriasPorAutor(RedirectView):
class RedirecionaMateriasPorAnoAutorTipo(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
url = EMPTY_STRING
ano = self.request.GET.get('ano', '')
username = self.request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(relatorio_materia_por_ano_autor_tipo)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(relatorio_materia_por_ano_autor_tipo)
if ano:
@ -686,23 +773,30 @@ class RedirecionaMateriasPorAnoAutorTipo(RedirectView):
class RedirecionaReuniao(RedirectView):
permanent = True
logger = logging.getLogger(__name__)
def get_redirect_url(self):
pk_reuniao = self.request.GET.get(
'cod_comissao',
EMPTY_STRING)
url = EMPTY_STRING
username = self.request.user.username
if pk_reuniao:
kwargs = {'pk': pk_reuniao}
try:
self.logger.debug("user=" + username + ". Tentando obter url correspondente (pk={}).".format(kwargs['pk']))
url = reverse(reuniao_detail, kwargs=kwargs)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(reuniao_detail)
else:
try:
self.logger.debug("user=" + username + ". Tentando obter url.")
url = reverse(reuniao_list)
except NoReverseMatch:
except NoReverseMatch as e:
self.logger.error("user=" + username + ". Erro ao obter url. " + str(e))
raise UnknownUrlNameError(reuniao_list)
year = self.request.GET.get(

14
sapl/relatorios/templates/pdf_pauta_sessao_gerar.py

@ -122,8 +122,10 @@ def expediente_materia(lst_expediente_materia):
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Situaçã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>Autor: </b>' + expediente_materia['nom_autor'] + '</para></td>\n'
tmp += '<tr><td><para style="P3"><b>' + str(expediente_materia['num_ordem']) + '</b> - ' + \
expediente_materia["tipo_materia"] + ' No. ' + \
expediente_materia['id_materia'] + '</para>\n' + '<para style="P3"><b>Autor: </b>' + \
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">' + \
@ -145,8 +147,12 @@ def votacao(lst_votacao):
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td >Ementa</td><td>Situação</td></tr>\n'
for votacao in lst_votacao:
tmp += '<tr><td><para style="P3"><b>' + str(votacao['num_ordem']) + '</b> - ' + str(votacao['id_materia']) + '</para>\n' + '<para style="P3"><b>Processo: </b>' + str(votacao[
'des_numeracao']) + '</para>\n' + '<para style="P3"><b>Turno: </b>' + str(votacao['des_turno']) + '</para>\n' + '<para style="P3"><b>Autor: </b>' + str(votacao['nom_autor']) + '</para></td>\n'
tmp += '<tr><td><para style="P3"><b>' + str(votacao['num_ordem']) + '</b> - ' + \
votacao["tipo_materia"] + ' No. ' + \
str(votacao['id_materia']) + '</para>\n' + '<para style="P3"><b>Processo: </b>' + \
str(votacao['des_numeracao']) + '</para>\n' + '<para style="P3"><b>Turno: </b>' + \
str(votacao['des_turno']) + '</para>\n' + '<para style="P3"><b>Autor: </b>' + \
str(votacao['nom_autor']) + '</para></td>\n'
tmp += '<td><para style="P4">' + \
str(votacao['txt_ementa']) + '</para></td>\n'
tmp += '<td><para style="P3">' + \

10
sapl/relatorios/views.py

@ -1,5 +1,6 @@
import html
import re
import logging
from datetime import datetime as dt
from django.core.exceptions import ObjectDoesNotExist
@ -782,7 +783,8 @@ def relatorio_sessao_plenaria(request, pk):
'''
pdf_sessao_plenaria_gerar.py
'''
logger = logging.getLogger(__name__)
username = request.user.username
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = (
'inline; filename="relatorio_protocolo.pdf"')
@ -797,8 +799,10 @@ def relatorio_sessao_plenaria(request, pk):
imagem = get_imagem(casa)
try:
logger.debug("user=" + username + ". Tentando obter SessaoPlenaria com id={}.".format(pk))
sessao = SessaoPlenaria.objects.get(id=pk)
except ObjectDoesNotExist:
except ObjectDoesNotExist as e:
logger.error("user=" + username + ". Essa SessaoPlenaria não existe (pk={}). ".format(pk) + str(e))
raise Http404('Essa página não existe')
(inf_basicas_dic,
@ -1061,6 +1065,7 @@ def get_pauta_sessao(sessao, casa):
id=expediente_materia.materia.id).first()
dic_expediente_materia = {}
dic_expediente_materia["tipo_materia"] = materia.tipo.sigla + ' - ' + materia.tipo.descricao
dic_expediente_materia["num_ordem"] = str(
expediente_materia.numero_ordem)
dic_expediente_materia["id_materia"] = str(
@ -1113,6 +1118,7 @@ def get_pauta_sessao(sessao, casa):
id=votacao.materia.id).first()
dic_votacao = {}
dic_votacao["tipo_materia"] = materia.tipo.sigla + ' - ' + materia.tipo.descricao
dic_votacao["num_ordem"] = votacao.numero_ordem
dic_votacao["id_materia"] = str(
materia.numero) + "/" + str(materia.ano)

27
sapl/rules/apps.py

@ -1,6 +1,8 @@
from builtins import LookupError
import django
import logging
from django.apps import apps
from django.contrib.auth import get_user_model
from django.contrib.auth.management import _get_all_permissions
@ -28,12 +30,14 @@ def create_proxy_permissions(
using=DEFAULT_DB_ALIAS, **kwargs):
if not app_config.models_module:
return
logger = logging.getLogger(__name__)
# print(app_config)
try:
logger.info("Tentando obter modelo de permissão do app.")
Permission = apps.get_model('auth', 'Permission')
except LookupError:
except LookupError as e:
logger.error(str(e))
return
if not router.allow_migrate_model(using, Permission):
@ -69,9 +73,11 @@ def create_proxy_permissions(
app_label, model = opts.app_label, opts.model_name
try:
logger.info("Tentando obter db_manager.")
ctype = ContentType.objects.db_manager(
using).get_by_natural_key(app_label, model)
except:
except Exception as e:
logger.error(str(e))
ctype = ContentType.objects.db_manager(
using).create(app_label=app_label, model=model)
else:
@ -81,12 +87,14 @@ def create_proxy_permissions(
# FIXME: Retirar try except quando sapl passar a usar django 1.11
try:
logger.info("_get_all_permissions")
# Função não existe mais em Django 1.11
# como sapl ainda não foi para Django 1.11
# esta excessão foi adicionada para caso o
# Sapl esteja rodando em um projeto 1.11 não ocorra erros
_all_perms_of_klass = _get_all_permissions(klass._meta, ctype)
except:
except Exception as e:
logger.error(str(e))
# Nova função usada em projetos com Django 1.11 e o sapl é uma app
_all_perms_of_klass = _get_all_permissions(klass._meta)
@ -111,6 +119,13 @@ def create_proxy_permissions(
# error when the name is longer than 255 characters
for perm in perms:
if len(perm.name) > permission_name_max_length:
logger.error("The permission name %s of %s.%s "
"is longer than %s characters" % (
perm.name,
perm.content_type.app_label,
perm.content_type.model,
permission_name_max_length,
))
raise exceptions.ValidationError(
'The permission name %s of %s.%s '
'is longer than %s characters' % (
@ -155,15 +170,17 @@ def get_rules():
def _config_group(self, group_name, rules_list):
if not group_name:
return
logger = logging.getLogger(__name__)
group, created = Group.objects.get_or_create(name=group_name)
group.permissions.clear()
try:
logger.info("Tentando associar grupos.")
print(' ', group_name)
for model, perms in rules_list:
self.associar(group, model, perms)
except Exception as e:
logger.error(str(e))
print(group_name, e)
def groups_add_user(self, user, groups_name):

1
sapl/rules/map_rules.py

@ -66,6 +66,7 @@ rules_group_audiencia = {
'rules': [
(audiencia.AudienciaPublica, __base__),
(audiencia.TipoAudienciaPublica, __base__),
(audiencia.AnexoAudienciaPublica, __base__),
]
}

2
sapl/sessao/forms.py

@ -430,7 +430,7 @@ class VotacaoForm(forms.Form):
class VotacaoNominalForm(forms.Form):
resultado_votacao = forms.ModelChoiceField(label='Resultado da Votação',
required=True,
required=False,
queryset=TipoResultadoVotacao.objects.all())

66
sapl/sessao/migrations/0026_auto_20181016_1944.py

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-10-16 22:44
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('sessao', '0025_auto_20180919_1116'),
]
operations = [
migrations.AlterField(
model_name='expedientesessao',
name='sessao_plenaria',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sessao.SessaoPlenaria'),
),
migrations.AlterField(
model_name='integrantemesa',
name='sessao_plenaria',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sessao.SessaoPlenaria'),
),
migrations.AlterField(
model_name='orador',
name='sessao_plenaria',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sessao.SessaoPlenaria'),
),
migrations.AlterField(
model_name='oradorexpediente',
name='sessao_plenaria',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sessao.SessaoPlenaria'),
),
migrations.AlterField(
model_name='presencaordemdia',
name='sessao_plenaria',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sessao.SessaoPlenaria'),
),
migrations.AlterField(
model_name='registrovotacao',
name='expediente',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sessao.ExpedienteMateria'),
),
migrations.AlterField(
model_name='registrovotacao',
name='materia',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa'),
),
migrations.AlterField(
model_name='registrovotacao',
name='ordem',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sessao.OrdemDia'),
),
migrations.AlterField(
model_name='sessaoplenaria',
name='sessao_legislativa',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='parlamentares.SessaoLegislativa', verbose_name='Sessão Legislativa'),
),
migrations.AlterField(
model_name='sessaoplenariapresenca',
name='sessao_plenaria',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sessao.SessaoPlenaria'),
),
]

25
sapl/sessao/migrations/0027_auto_20181023_1239.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8 on 2018-10-23 15:39
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sessao', '0026_auto_20181016_1944'),
]
operations = [
migrations.AlterField(
model_name='sessaoplenaria',
name='finalizada',
field=models.NullBooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Sessão finalizada?'),
),
migrations.AlterField(
model_name='sessaoplenaria',
name='iniciada',
field=models.NullBooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=True, verbose_name='Sessão iniciada?'),
),
]

30
sapl/sessao/models.py

@ -121,7 +121,7 @@ class SessaoPlenaria(models.Model):
verbose_name=_('Tipo'))
sessao_legislativa = models.ForeignKey(
SessaoLegislativa,
on_delete=models.PROTECT,
on_delete=models.CASCADE,
verbose_name=_('Sessão Legislativa'))
legislatura = models.ForeignKey(Legislatura,
on_delete=models.PROTECT,
@ -160,10 +160,12 @@ class SessaoPlenaria(models.Model):
verbose_name=_('Anexo da Sessão'))
iniciada = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
verbose_name=_('Sessão iniciada?'))
verbose_name=_('Sessão iniciada?'),
default=True)
finalizada = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
verbose_name=_('Sessão finalizada?'))
verbose_name=_('Sessão finalizada?'),
default=False)
interativa = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
verbose_name=_('Sessão interativa'))
@ -288,7 +290,7 @@ class TipoExpediente(models.Model):
@reversion.register()
class ExpedienteSessao(models.Model): # ExpedienteSessaoPlenaria
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.PROTECT)
on_delete=models.CASCADE)
tipo = models.ForeignKey(TipoExpediente, on_delete=models.PROTECT)
conteudo = models.TextField(
blank=True, verbose_name=_('Conteúdo do expediente'))
@ -319,7 +321,7 @@ class OcorrenciaSessao(models.Model): # OcorrenciaSessaoPlenaria
@reversion.register()
class IntegranteMesa(models.Model): # MesaSessaoPlenaria
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.PROTECT)
on_delete=models.CASCADE)
cargo = models.ForeignKey(CargoMesa, on_delete=models.PROTECT)
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.PROTECT)
@ -334,7 +336,7 @@ class IntegranteMesa(models.Model): # MesaSessaoPlenaria
@reversion.register()
class AbstractOrador(models.Model): # Oradores
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.PROTECT)
on_delete=models.CASCADE)
parlamentar = models.ForeignKey(Parlamentar,
on_delete=models.PROTECT,
verbose_name=_('Parlamentar'))
@ -387,7 +389,7 @@ class OrdemDia(AbstractOrdemDia):
@reversion.register()
class PresencaOrdemDia(models.Model): # OrdemDiaPresenca
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.PROTECT)
on_delete=models.CASCADE)
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.PROTECT)
class Meta:
@ -427,15 +429,15 @@ class RegistroVotacao(models.Model):
TipoResultadoVotacao,
on_delete=models.PROTECT,
verbose_name=_('Resultado da Votação'))
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.PROTECT)
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
ordem = models.ForeignKey(OrdemDia,
blank=True,
null=True,
on_delete=models.PROTECT)
on_delete=models.CASCADE)
expediente = models.ForeignKey(ExpedienteMateria,
blank=True,
null=True,
on_delete=models.PROTECT)
on_delete=models.CASCADE)
numero_votos_sim = models.PositiveIntegerField(verbose_name=_('Sim'))
numero_votos_nao = models.PositiveIntegerField(verbose_name=_('Não'))
numero_abstencoes = models.PositiveIntegerField(
@ -476,7 +478,7 @@ class VotoParlamentar(models.Model): # RegistroVotacaoParlamentar
'''
votacao = models.ForeignKey(RegistroVotacao,
blank=True,
null=True)
null=True,on_delete=models.CASCADE)
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.PROTECT)
voto = models.CharField(max_length=10)
@ -496,10 +498,10 @@ class VotoParlamentar(models.Model): # RegistroVotacaoParlamentar
ordem = models.ForeignKey(OrdemDia,
blank=True,
null=True)
null=True, on_delete=models.CASCADE)
expediente = models.ForeignKey(ExpedienteMateria,
blank=True,
null=True)
null=True, on_delete=models.CASCADE)
class Meta:
verbose_name = _('Registro de Votação de Parlamentar')
@ -513,7 +515,7 @@ class VotoParlamentar(models.Model): # RegistroVotacaoParlamentar
@reversion.register()
class SessaoPlenariaPresenca(models.Model):
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.PROTECT)
on_delete=models.CASCADE)
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.PROTECT)
data_sessao = models.DateField(blank=True, null=True)

132
sapl/sessao/tests/test_sessao.py

@ -5,11 +5,14 @@ from django.utils.translation import ugettext_lazy as _
from model_mommy import mommy
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.parlamentares.models import Legislatura, Partido, SessaoLegislativa
from sapl.parlamentares.models import Legislatura, Parlamentar, Partido,SessaoLegislativa
from sapl.sessao import forms
from sapl.sessao.models import (ExpedienteMateria, OrdemDia, RegistroVotacao,
SessaoPlenaria, TipoSessaoPlenaria)
from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao,
IntegranteMesa, Orador, OrdemDia,
PresencaOrdemDia, RegistroVotacao,
SessaoPlenaria, SessaoPlenariaPresenca,
TipoResultadoVotacao, TipoSessaoPlenaria,
VotoParlamentar)
def test_valida_campos_obrigatorios_sessao_plenaria_form():
form = forms.SessaoPlenariaForm(data={})
@ -170,3 +173,124 @@ def test_registro_votacao_tem_ordem_xor_expediente():
# a validação NÃO funciona quando ambos são preenchidos
with pytest.raises(ValidationError):
registro_votacao_com(ordem, expediente).full_clean()
def create_sessao_plenaria():
legislatura = mommy.make(Legislatura)
sessao = mommy.make(SessaoLegislativa)
tipo = mommy.make(TipoSessaoPlenaria)
return mommy.make(SessaoPlenaria,
legislatura=legislatura,
sessao_legislativa=sessao,
tipo=tipo,
numero=1)
def create_materia_legislativa():
tipo_materia = mommy.make(TipoMateriaLegislativa)
return mommy.make(MateriaLegislativa, tipo=tipo_materia)
@pytest.mark.django_db(transaction=False)
def test_delete_sessao_plenaria_cascade_registro_votacao_ordemdia():
materia = create_materia_legislativa()
sessao_plenaria = create_sessao_plenaria()
ordem = mommy.make(OrdemDia,
sessao_plenaria=sessao_plenaria,
materia=materia,
tipo_votacao='2')
tipo_resultado_votacao = mommy.make(TipoResultadoVotacao,
nome='ok',
natureza="A")
registro = mommy.make(RegistroVotacao,
tipo_resultado_votacao=tipo_resultado_votacao,
materia=materia,
ordem=ordem)
presenca = mommy.make(PresencaOrdemDia,
sessao_plenaria=sessao_plenaria)
parlamentar = mommy.make(Parlamentar)
voto_parlamentar = mommy.make(VotoParlamentar,
votacao=registro,
parlamentar=parlamentar,
ordem=ordem)
sessao_plenaria.delete()
presenca_filter = PresencaOrdemDia.objects.filter(
sessao_plenaria=sessao_plenaria).exists()
ordem_filter = OrdemDia.objects.filter(
sessao_plenaria=sessao_plenaria).exists()
registro_filter = RegistroVotacao.objects.filter(
tipo_resultado_votacao=tipo_resultado_votacao,
materia=materia,
ordem=ordem).exists()
materia_filter = MateriaLegislativa.objects.filter(id=materia.id).exists()
parlamentar_filter = Parlamentar.objects.exists()
voto_parlamentar_filter = VotoParlamentar.objects.filter(
ordem=ordem).exists()
assert not registro_filter
assert not ordem_filter
assert not presenca_filter
assert not voto_parlamentar_filter
assert materia_filter # Não exclui materia
assert parlamentar_filter # Não exclui Parlamentar
@pytest.mark.django_db(transaction=False)
def test_delete_sessao_plenaria_cascade_registro_votacao_expediente():
materia = create_materia_legislativa()
sessao_plenaria = create_sessao_plenaria()
expediente = mommy.make(ExpedienteMateria,
sessao_plenaria=sessao_plenaria,
materia=materia,
tipo_votacao='2')
tipo_resultado_votacao = mommy.make(TipoResultadoVotacao,
nome='ok',
natureza="A")
registro = mommy.make(RegistroVotacao,
tipo_resultado_votacao=tipo_resultado_votacao,
materia=materia,
expediente=expediente)
presenca = mommy.make(SessaoPlenariaPresenca,
sessao_plenaria=sessao_plenaria)
parlamentar = mommy.make(Parlamentar)
voto_parlamentar = mommy.make(VotoParlamentar,
votacao=registro,
parlamentar=parlamentar,
expediente=expediente)
sessao_plenaria.delete()
expediente_filter = ExpedienteMateria.objects.filter(
sessao_plenaria=sessao_plenaria).exists()
registro_filter = RegistroVotacao.objects.filter(
tipo_resultado_votacao=tipo_resultado_votacao,
materia=materia,
expediente=expediente).exists()
presenca_filter = SessaoPlenariaPresenca.objects.filter(
sessao_plenaria=sessao_plenaria).exists()
parlamentar_filter = Parlamentar.objects.exists()
voto_parlamentar_filter = VotoParlamentar.objects.filter(
expediente=expediente).exists()
assert not registro_filter
assert not expediente_filter
assert not presenca_filter
assert not voto_parlamentar_filter
assert parlamentar_filter # Não exclui Parlamentar
@pytest.mark.django_db(transaction=False)
def test_delete_sessao_plenaria_cascade_integrante_mesa():
sessao_plenaria = create_sessao_plenaria()
mesa = mommy.make(IntegranteMesa,sessao_plenaria=sessao_plenaria)
sessao_plenaria.delete()
mesa_filter = IntegranteMesa.objects.filter(sessao_plenaria=sessao_plenaria).exists()
assert not mesa_filter
@pytest.mark.django_db(transaction=False)
def test_delete_sessao_plenaria_cascade_expedientesessao():
sessao_plenaria = create_sessao_plenaria()
expediente_sessao = mommy.make(ExpedienteSessao, sessao_plenaria=sessao_plenaria)
sessao_plenaria.delete()
expediente_sessao_filter = ExpedienteSessao.objects.filter(sessao_plenaria=sessao_plenaria).exists()
assert not expediente_sessao_filter
@pytest.mark.django_db(transaction=False)
def test_delete_sessao_plenaria_cascade_orador():
sessao_plenaria = create_sessao_plenaria()
expediente_sessao = mommy.make(Orador, sessao_plenaria=sessao_plenaria)
sessao_plenaria.delete()
orador_filter = Orador.objects.filter(sessao_plenaria=sessao_plenaria).exists()
assert not orador_filter

182
sapl/sessao/views.py

@ -1,4 +1,5 @@
from operator import itemgetter
import logging
from re import sub
from django.contrib import messages
@ -62,10 +63,10 @@ TipoResultadoVotacaoCrud = CrudAux.build(
def reordernar_materias_expediente(request, pk):
expedientes = ExpedienteMateria.objects.filter(
sessao_plenaria_id=pk)
for exp_num, e in enumerate(expedientes, 1):
e.numero_ordem = exp_num
e.save()
return HttpResponseRedirect(
reverse('sapl.sessao:expedientemateria_list', kwargs={'pk': pk}))
@ -82,7 +83,10 @@ def reordernar_materias_ordem(request, pk):
def verifica_presenca(request, model, spk):
logger = logging.getLogger(__name__)
if not model.objects.filter(sessao_plenaria_id=spk).exists():
username = request.user.username
logger.error("user=" + username + ". Votação não pode ser aberta sem presenças (sessao_plenaria_id={}).".format(spk))
msg = _('Votação não pode ser aberta sem presenças')
messages.add_message(request, messages.ERROR, msg)
return False
@ -94,6 +98,8 @@ def verifica_votacoes_abertas(request):
Q(ordemdia__votacao_aberta=True) |
Q(expedientemateria__votacao_aberta=True)).distinct()
logger = logging.getLogger(__name__)
if votacoes_abertas:
msg_abertas = []
for v in votacoes_abertas:
@ -101,7 +107,10 @@ def verifica_votacoes_abertas(request):
reverse('sapl.sessao:sessaoplenaria_detail',
kwargs={'pk': v.id}),
v.__str__()))
username = request.user.username
logger.info('user=' + username + '. Já existem votações abertas nas seguintes Sessões: ' +
', '.join(msg_abertas) + '. Para abrir '
'outra, termine ou feche as votações abertas.')
msg = _('Já existem votações abertas nas seguintes Sessões: ' +
', '.join(msg_abertas) + '. Para abrir '
'outra, termine ou feche as votações abertas.')
@ -113,11 +122,16 @@ def verifica_votacoes_abertas(request):
def verifica_sessao_iniciada(request, spk):
logger = logging.getLogger(__name__)
sessao = SessaoPlenaria.objects.get(id=spk)
if not sessao.iniciada or sessao.finalizada:
username = request.user.username
logger.info('user=' + username + '. Não é possível abrir matérias para votação. '
'Esta SessaoPlenaria (id={}) não foi iniciada ou está finalizada.'.format(spk))
msg = _('Não é possível abrir matérias para votação. '
'Esta Sessão Plenária não foi iniciada ou está finalizada.')
'Esta Sessão Plenária não foi iniciada ou está finalizada.'
' Vá em "Abertura"->"Dados Básicos" e altere os valores dos campos necessários.')
messages.add_message(request, messages.INFO, msg)
return False
@ -571,6 +585,16 @@ class OradorCrud(OradorCrud):
return reverse('sapl.sessao:orador_list',
kwargs={'pk': self.kwargs['pk']})
class UpdateView(MasterDetailCrud.UpdateView):
form_class = OradorForm
def get_initial(self):
initial = super(UpdateView, self).get_initial()
initial.update({'id_sessao': self.object.sessao_plenaria.id})
return initial
class BancadaCrud(Crud):
model = Bancada
@ -661,6 +685,7 @@ class SessaoCrud(Crud):
class CreateView(Crud.CreateView):
form_class = SessaoPlenariaForm
logger = logging.getLogger(__name__)
@property
def cancel_url(self):
@ -680,6 +705,11 @@ class SessaoCrud(Crud):
else:
msg = _('Cadastre alguma legislatura antes de adicionar ' +
'uma sessão plenária!')
username = self.request.user.username
self.logger.error('user=' + username + '. Cadastre alguma legislatura antes de adicionar '
'uma sessão plenária!')
messages.add_message(self.request, messages.ERROR, msg)
return {}
@ -716,6 +746,7 @@ class PresencaView(FormMixin, PresencaMixin, DetailView):
template_name = 'sessao/presenca.html'
form_class = PresencaForm
model = SessaoPlenaria
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs):
context = FormMixin.get_context_data(self, **kwargs)
@ -750,7 +781,8 @@ class PresencaView(FormMixin, PresencaMixin, DetailView):
sessao.sessao_plenaria = self.object
sessao.parlamentar = Parlamentar.objects.get(id=p)
sessao.save()
username = request.user.username
self.logger.info("user=" + username + ". SessaoPlenariaPresenca salva com sucesso (parlamentar_id={})!".format(p))
msg = _('Presença em Sessão salva com sucesso!')
messages.add_message(request, messages.SUCCESS, msg)
@ -766,6 +798,7 @@ class PresencaView(FormMixin, PresencaMixin, DetailView):
class PainelView(PermissionRequiredForAppCrudMixin, TemplateView):
template_name = 'sessao/painel.html'
app_label = 'painel'
logger = logging.getLogger(__name__)
def get(self, request, *args, **kwargs):
if request.user.is_anonymous():
@ -787,6 +820,10 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView):
if (not cronometro_discurso or not cronometro_aparte
or not cronometro_ordem or not cronometro_consideracoes):
username = self.request.user.username
self.logger.error('user=' + username + '. Você precisa primeiro configurar os cronômetros'
' nas Configurações da Aplicação')
msg = _(
'Você precisa primeiro configurar os cronômetros \
nas Configurações da Aplicação')
@ -823,6 +860,7 @@ class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView):
template_name = 'sessao/presenca_ordemdia.html'
form_class = PresencaForm
model = SessaoPlenaria
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs):
context = FormMixin.get_context_data(self, **kwargs)
@ -858,6 +896,8 @@ class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView):
ordem.parlamentar = Parlamentar.objects.get(id=p)
ordem.save()
username = request.user.username
self.logger.info('user=' + username + '. PresencaOrdemDia (parlamentar com id={}) salva com sucesso!'.format(p))
msg = _('Presença em Ordem do Dia salva com sucesso!')
messages.add_message(request, messages.SUCCESS, msg)
@ -984,15 +1024,19 @@ class MesaView(FormMixin, DetailView):
template_name = 'sessao/mesa.html'
form_class = MesaForm
model = SessaoPlenaria
logger = logging.getLogger(__name__)
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
username = request.user.username
try:
self.logger.debug("user=" + username + ". Tentando obter SessaoPlenaria com id={}".format(kwargs['pk']))
sessao = SessaoPlenaria.objects.get(
id=kwargs['pk'])
except ObjectDoesNotExist:
self.logger.error("user=" + username + ". SessaoPlenaria com id={} não existe.".format(kwargs['pk']))
mensagem = _('Esta Sessão Plenária não existe!')
messages.add_message(request, messages.INFO, mensagem)
@ -1044,10 +1088,14 @@ def atualizar_mesa(request):
Esta função lida com qualquer alteração nos campos
da Mesa Diretora, atualizando os campos após cada alteração
"""
logger = logging.getLogger(__name__)
username = request.user.username
try:
logger.debug("user=" + username + ". Tentando obter SessaoPlenaria com id={}.".format(request.GET['sessao']))
sessao = SessaoPlenaria.objects.get(
id=int(request.GET['sessao']))
except ObjectDoesNotExist:
logger.error("user=" + username + ". SessaoPlenaria com id={} inexistente.".format(request.GET['sessao']))
return JsonResponse({'msg': ('Sessão Inexistente!', 0)})
# Atualiza os componentes da view após a mudança
@ -1086,6 +1134,8 @@ def insere_parlamentar_composicao(request):
Esta função lida com qualquer operação de inserção
na composição da Mesa Diretora
"""
logger = logging.getLogger(__name__)
username = request.user.username
if request.user.has_perm(
'%s.add_%s' % (
AppConfig.label, IntegranteMesa._meta.model_name)):
@ -1093,15 +1143,19 @@ def insere_parlamentar_composicao(request):
composicao = IntegranteMesa()
try:
logger.debug("user=" + username + ". Tentando obter SessaoPlenaria com id={}.".format(request.POST['sessao']))
composicao.sessao_plenaria = SessaoPlenaria.objects.get(
id=int(request.POST['sessao']))
except MultiValueDictKeyError:
logger.error("user=" + username + ". SessaoPlenaria com id={} não existe.".format(request.POST['sessao']))
return JsonResponse({'msg': ('A Sessão informada não existe!', 0)})
try:
logger.debug("user=" + username + ". Tentando obter Parlamentar com id={}.".format(request.POST['parlamentar']))
composicao.parlamentar = Parlamentar.objects.get(
id=int(request.POST['parlamentar']))
except MultiValueDictKeyError:
logger.error("user=" + username + ". Parlamentar com id={} não existe.".format(request.POST['parlamentar']))
return JsonResponse({
'msg': ('Nenhum parlamentar foi inserido!', 0)})
@ -1113,13 +1167,17 @@ def insere_parlamentar_composicao(request):
cargo_id=composicao.cargo.id).exists()
if parlamentar_ja_inserido:
logger.debug("user=" + username + ". Parlamentar (id={}) já inserido na sessao_plenaria(id={}) e cargo(ìd={})."
.format(request.POST['parlamentar'], composicao.sessao_plenaria.id, composicao.cargo.id))
return JsonResponse({'msg': ('Parlamentar já inserido!', 0)})
composicao.save()
except MultiValueDictKeyError:
except MultiValueDictKeyError as e:
logger.error("user=" + username + ". Nenhum cargo foi inserido! " + str(e))
return JsonResponse({'msg': ('Nenhum cargo foi inserido!', 0)})
logger.info("user=" + username + ". Parlamentar (id={}) inserido com sucesso na sessao_plenaria(id={}) e cargo(ìd={}).")
return JsonResponse({'msg': ('Parlamentar inserido com sucesso!', 1)})
else:
@ -1132,23 +1190,30 @@ def remove_parlamentar_composicao(request):
Essa função lida com qualquer operação de remoção
na composição da Mesa Diretora
"""
logger = logging.getLogger(__name__)
username = request.user.username
if request.POST and request.user.has_perm(
'%s.delete_%s' % (
AppConfig.label, IntegranteMesa._meta.model_name)):
if 'composicao_mesa' in request.POST:
try:
logger.debug("user=" + username + ". Tentando remover IntegranteMesa com id={}".format(request.POST['composicao_mesa']))
IntegranteMesa.objects.get(
id=int(request.POST['composicao_mesa'])).delete()
except ObjectDoesNotExist:
logger.error("user=" + username + ". IntegranteMesa com id={} não existe e não pôde ser removido."
.format(request.POST['composicao_mesa']))
return JsonResponse(
{'msg': (
'Composição da Mesa não pôde ser removida!', 0)})
logger.info("user=" + username + ". IntegranteMesa com id={} removido com sucesso.")
return JsonResponse(
{'msg': (
'Parlamentar excluido com sucesso!', 1)})
else:
logger.debug("user=" + username + ". Nenhum parlamentar selecionado para ser excluido!")
return JsonResponse(
{'msg': (
'Selecione algum parlamentar para ser excluido!', 0)})
@ -1470,6 +1535,8 @@ class ResumoView(DetailView):
class ResumoAtaView(ResumoView):
template_name = 'sessao/resumo_ata.html'
logger = logging.getLogger(__name__)
logger.debug('Gerando Resumo.')
class ExpedienteView(FormMixin, DetailView):
@ -1477,6 +1544,8 @@ class ExpedienteView(FormMixin, DetailView):
form_class = ExpedienteForm
model = SessaoPlenaria
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs):
context = FormMixin.get_context_data(self, **kwargs)
context['title'] = '%s <small>(%s)</small>' % (
@ -1487,10 +1556,12 @@ class ExpedienteView(FormMixin, DetailView):
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = ExpedienteForm(request.POST)
username = request.user.username
if 'apagar-expediente' in request.POST:
ExpedienteSessao.objects.filter(
sessao_plenaria_id=self.object.id).delete()
self.logger.info('user=' + username + '. ExpedienteSessao de sessao_plenaria_id={} deletado.'.format(self.object.id))
return self.form_valid(form)
if form.is_valid():
@ -1511,9 +1582,13 @@ class ExpedienteView(FormMixin, DetailView):
msg = _('Registro salvo com sucesso')
messages.add_message(self.request, messages.SUCCESS, msg)
self.logger.info('user=' + username + '. ExpedienteSessao(sessao_plenaria_id={} e tipo_id={}) salvo com sucesso.'
.format(self.object.id, tipo))
return self.form_valid(form)
else:
msg = _('Erro ao salvar registro')
self.logger.error("user=" + username + ". Erro ao salvar registro (sessao_plenaria_id={}).".format(self.object.id))
msg = _('Erro ao salvar ExpedienteSessao')
messages.add_message(self.request, messages.SUCCESS, msg)
return self.form_invalid(form)
@ -1557,9 +1632,15 @@ class OcorrenciaSessaoView(FormMixin, DetailView):
form_class = OcorrenciaSessaoForm
model = SessaoPlenaria
logger = logging.getLogger(__name__)
def delete(self):
OcorrenciaSessao.objects.filter(sessao_plenaria=self.object).delete()
username = self.request.user.username
self.logger.info('user=' + username + '. OcorrenciaSessao com SessaoPlenaria de id={} deletada.'
.format(self.object.id))
msg = _('Registro deletado com sucesso')
messages.add_message(self.request, messages.SUCCESS, msg)
@ -1576,6 +1657,9 @@ class OcorrenciaSessaoView(FormMixin, DetailView):
msg = _('Registro salvo com sucesso')
messages.add_message(self.request, messages.SUCCESS, msg)
username = self.request.user.username
self.logger.info('user=' + username + '. OcorrenciaSessao de sessao_plenaria_id={} atualizada com sucesso.'.format(self.object.id))
@method_decorator(permission_required('sessao.add_ocorrenciasessao'))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
@ -1677,6 +1761,8 @@ class VotacaoView(SessaoPermissionMixin):
template_name = 'sessao/votacao/votacao.html'
form_class = VotacaoForm
logger = logging.getLogger(__name__)
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
@ -1761,7 +1847,10 @@ class VotacaoView(SessaoPermissionMixin):
votacao.tipo_resultado_votacao_id = int(
request.POST['resultado_votacao'])
votacao.save()
except:
except Exception as e:
username = request.user.username
self.logger.error('user=' + username + '. Problemas ao salvar RegistroVotacao da materia de id={} '
'e da ordem de id={}. '.format(materia_id, ordem_id) + str(e))
return self.form_invalid(form)
else:
ordem = OrdemDia.objects.get(
@ -1809,18 +1898,23 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
expediente = None
form_class = VotacaoNominalForm
logger = logging.getLogger(__name__)
def get(self, request, *args, **kwargs):
username = request.user.username
if self.ordem:
ordem_id = kwargs['oid']
if RegistroVotacao.objects.filter(ordem_id=ordem_id).exists():
msg = _('Esta matéria já foi votada!')
messages.add_message(request, messages.ERROR, msg)
self.logger.info('user=' + username + '. Matéria (ordem_id={}) já votada!'.format(ordem_id))
return HttpResponseRedirect(reverse(
'sapl.sessao:ordemdia_list', kwargs={'pk': kwargs['pk']}))
try:
ordem = OrdemDia.objects.get(id=ordem_id)
except ObjectDoesNotExist:
self.logger.error('user=' + username + '. Objeto OrdemDia (pk={}) não existe.'.format(ordem_id))
raise Http404()
presentes = PresencaOrdemDia.objects.filter(
@ -1830,6 +1924,7 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
materia_votacao = ordem
if not ordem.votacao_aberta:
self.logger.error('user=' + username + '. A votação para esta OrdemDia (id={}) encontra-se fechada!'.format(ordem_id))
msg = _('A votação para esta matéria encontra-se fechada!')
messages.add_message(request, messages.ERROR, msg)
return HttpResponseRedirect(reverse(
@ -1842,6 +1937,7 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
expediente_id = kwargs['oid']
if (RegistroVotacao.objects.filter(
expediente_id=expediente_id).exists()):
self.logger.error("user=" + username + ". RegistroVotacao (expediente_id={}) já existe.".format(expediente_id))
msg = _('Esta matéria já foi votada!')
messages.add_message(request, messages.ERROR, msg)
return HttpResponseRedirect(reverse(
@ -1849,8 +1945,10 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
kwargs={'pk': kwargs['pk']}))
try:
self.logger.debug("user=" + username + ". Tentando obter Objeto ExpedienteMateria com id={}.".format(expediente_id))
expediente = ExpedienteMateria.objects.get(id=expediente_id)
except ObjectDoesNotExist:
self.logger.error('user=' + username + '. Objeto ExpedienteMateria com id={} não existe.'.format(expediente_id))
raise Http404()
presentes = SessaoPlenariaPresenca.objects.filter(
@ -1860,7 +1958,7 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
materia_votacao = expediente
if not expediente.votacao_aberta:
msg = _('A votação para esta matéria encontra-se fechada!')
msg = _('A votação para este ExpedienteMateria (id={}) encontra-se fechada!'.format(expediente_id))
messages.add_message(request, messages.ERROR, msg)
return HttpResponseRedirect(reverse(
'sapl.sessao:expedientemateria_list',
@ -1883,24 +1981,26 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
username = request.user.username
if self.ordem:
ordem_id = kwargs['oid']
try:
self.logger.debug("user=" + username + ". Tentando obter objeto OrdemDia com id={}.".format(ordem_id))
materia_votacao = OrdemDia.objects.get(id=ordem_id)
except ObjectDoesNotExist:
self.logger.error('user=' + username + '. Objeto OrdemDia com id={} não existe.'.format(ordem_id))
raise Http404()
elif self.expediente:
expediente_id = kwargs['oid']
try:
self.logger.debug("user=" + username + ". Tentando obter ExpedienteMateria com id={}.".format(expediente_id))
materia_votacao = ExpedienteMateria.objects.get(
id=expediente_id)
except ObjectDoesNotExist:
self.logger.error('user=' + username + '. Objeto ExpedienteMateria com id={} não existe.'.format(expediente_id))
raise Http404()
if 'cancelar-votacao' in request.POST:
fechar_votacao_materia(materia_votacao)
return self.form_valid(form)
if form.is_valid():
votos_sim = 0
@ -1908,6 +2008,21 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
abstencoes = 0
nao_votou = 0
if 'cancelar-votacao' in request.POST:
fechar_votacao_materia(materia_votacao)
if self.ordem:
return HttpResponseRedirect(reverse(
'sapl.sessao:ordemdia_list', kwargs={'pk': kwargs['pk']}))
else:
return HttpResponseRedirect(reverse(
'sapl.sessao:expedientemateria_list',
kwargs={'pk': kwargs['pk']}))
else:
if form.cleaned_data['resultado_votacao'] == None:
form.add_error(None, 'Não é possível finalizar a votação sem '
'nenhum resultado da votação')
return self.form_invalid(form)
for votos in request.POST.getlist('voto_parlamentar'):
v = votos.split(':')
voto = v[0]
@ -1924,6 +2039,8 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
# Caso todas as opções sejam 'Não votou', fecha a votação
if nao_votou == len(request.POST.getlist('voto_parlamentar')):
self.logger.error('user=' + username + '. Não é possível finalizar a votação sem '
'nenhum voto')
form.add_error(None, 'Não é possível finalizar a votação sem '
'nenhum voto')
return self.form_invalid(form)
@ -2034,6 +2151,9 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
voto = voto_parlamentar.get(
parlamentar=parlamentar)
except ObjectDoesNotExist:
username = self.request.user.username
self.logger.error('user=' + username + '. Objeto voto_parlamentar do ' +
'parlamentar de id={} não existe.'.format(parlamentar.pk))
yield [parlamentar, None]
else:
yield [parlamentar, voto.voto]
@ -2052,8 +2172,11 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
class VotacaoNominalEditAbstract(SessaoPermissionMixin):
template_name = 'sessao/votacao/nominal_edit.html'
logger = logging.getLogger(__name__)
def get(self, request, *args, **kwargs):
context = {}
username = request.user.username
if self.ordem:
ordem_id = kwargs['oid']
@ -2062,6 +2185,7 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin):
votacao = RegistroVotacao.objects.filter(ordem_id=ordem_id).last()
if not ordem or not votacao:
self.logger.error('user=' + username + '. Objeto OrdemDia com id={} ou RegistroVotacao de OrdemDia não existe.'.format(ordem_id))
raise Http404()
materia = ordem.materia
@ -2076,6 +2200,8 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin):
expediente_id=expediente_id).last()
if not expediente or not votacao:
self.logger.error('user=' + username + '. Objeto ExpedienteMateria com id={} ou RegistroVotacao de ' +
'ExpedienteMateria não existe.'.format(expediente_id))
raise Http404()
materia = expediente.materia
@ -2124,6 +2250,7 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin):
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = VotacaoEditForm(request.POST)
username = request.user.username
if self.ordem:
ordem_id = kwargs['oid']
@ -2131,6 +2258,7 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin):
try:
materia_votacao = OrdemDia.objects.get(id=ordem_id)
except ObjectDoesNotExist:
self.logger.error('user=' + username + '. Objeto OrdemDia com id={} não existe.'.format(ordem_id))
raise Http404()
elif self.expediente:
@ -2140,6 +2268,7 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin):
materia_votacao = ExpedienteMateria.objects.get(
id=expediente_id)
except ObjectDoesNotExist:
self.logger.error('user=' + username + '. Objeto ExpedienteMateria com id={} não existe.'.format(expediente_id))
raise Http404()
if(int(request.POST['anular_votacao']) == 1):
@ -2315,6 +2444,7 @@ class VotacaoExpedienteView(SessaoPermissionMixin):
template_name = 'sessao/votacao/votacao.html'
form_class = VotacaoForm
logger = logging.getLogger(__name__)
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -2402,7 +2532,9 @@ class VotacaoExpedienteView(SessaoPermissionMixin):
votacao.tipo_resultado_votacao_id = int(
request.POST['resultado_votacao'])
votacao.save()
except:
except Exception as e:
username = request.user.username
self.logger.error("user=" + username + ". " + str(e))
return self.form_invalid(form)
else:
expediente = ExpedienteMateria.objects.get(
@ -2671,6 +2803,8 @@ class PesquisarSessaoPlenariaView(FilterView):
filterset_class = SessaoPlenariaFilterSet
paginate_by = 10
logger = logging.getLogger(__name__)
def get_filterset_kwargs(self, filterset_class):
super(PesquisarSessaoPlenariaView,
self).get_filterset_kwargs(filterset_class)
@ -2726,6 +2860,9 @@ class PesquisarSessaoPlenariaView(FilterView):
context['show_results'] = show_results_filter_set(
self.request.GET.copy())
username = request.user.username
self.logger.debug('user=' + username + '. Pesquisa de SessaoPlenaria.')
return self.render_to_response(context)
@ -2733,6 +2870,9 @@ class PesquisarPautaSessaoView(PesquisarSessaoPlenariaView):
filterset_class = PautaSessaoFilterSet
template_name = 'sessao/pauta_sessao_filter.html'
logger = logging.getLogger(__name__)
logger.debug('Pesquisa de PautaSessao.')
def get_context_data(self, **kwargs):
context = super(PesquisarPautaSessaoView,
self).get_context_data(**kwargs)
@ -2753,6 +2893,8 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin,
template_name = 'sessao/adicionar_varias_materias_expediente.html'
app_label = AppConfig.label
logger = logging.getLogger(__name__)
def get_filterset_kwargs(self, filterset_class):
super(AdicionarVariasMateriasExpediente,
self).get_filterset_kwargs(filterset_class)
@ -2795,6 +2937,7 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin,
def post(self, request, *args, **kwargs):
marcadas = request.POST.getlist('materia_id')
username = request.user.username
for m in marcadas:
try:
@ -2802,11 +2945,14 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin,
msg = _('%s adicionado(a) com sucesso!'
% MateriaLegislativa.objects.get(id=m))
messages.add_message(request, messages.SUCCESS, msg)
self.logger.info("user=" + username + ". MateriaLegislativa de id={} adicionado(a) com sucesso!".format(m))
except MultiValueDictKeyError:
msg = _('Formulário Inválido. Você esqueceu de selecionar ' +
'o tipo de votação de %s' %
'%s' %
MateriaLegislativa.objects.get(id=m))
messages.add_message(request, messages.ERROR, msg)
self.logger.error("user=" + username + '. Formulário Inválido. Você esqueceu de ' +
'selecionar o tipo de votação de MateriaLegislativa de id={}.'.format(m))
return self.get(request, self.kwargs)
if tipo_votacao:
@ -2838,6 +2984,8 @@ class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente):
filterset_class = AdicionarVariasMateriasFilterSet
template_name = 'sessao/adicionar_varias_materias_ordem.html'
logger = logging.getLogger(__name__)
def get_filterset_kwargs(self, filterset_class):
super(AdicionarVariasMateriasExpediente,
self).get_filterset_kwargs(filterset_class)
@ -2864,6 +3012,7 @@ class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente):
def post(self, request, *args, **kwargs):
marcadas = request.POST.getlist('materia_id')
username = request.user.username
for m in marcadas:
try:
@ -2871,11 +3020,15 @@ class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente):
msg = _('%s adicionado(a) com sucesso!'
% MateriaLegislativa.objects.get(id=m))
messages.add_message(request, messages.SUCCESS, msg)
self.logger.debug('user=' + username + '. MateriaLegislativa de id={} adicionado(a) com sucesso!'.format(m))
except MultiValueDictKeyError:
msg = _('Formulário Inválido. Você esqueceu de selecionar ' +
'o tipo de votação de %s' %
MateriaLegislativa.objects.get(id=m))
messages.add_message(request, messages.ERROR, msg)
self.logger.error('user=' + username + '. Formulário Inválido. Você esqueceu de selecionar '
'o tipo de votação de MateriaLegislativa com id={}'.format(m))
return self.get(request, self.kwargs)
if tipo_votacao:
@ -2909,6 +3062,7 @@ def mudar_ordem_materia_sessao(request):
posicao_inicial = int(request.POST['pos_ini']) + 1
posicao_final = int(request.POST['pos_fim']) + 1
pk_sessao = int(request.POST['pk_sessao'])
logger = logging.getLogger(__name__)
materia = request.POST['materia']
@ -2926,6 +3080,8 @@ def mudar_ordem_materia_sessao(request):
sessao_plenaria=pk_sessao,
numero_ordem=posicao_inicial)
except ObjectDoesNotExist:
username = request.user.username
logger.error("user=" + username + ". Materia com sessao_plenaria={} e numero_ordem={}.".format(pk_sessao, posicao_inicial))
raise # TODO tratar essa exceção
# Se a posição inicial for menor que a final, todos que

72
sapl/settings.py

@ -13,6 +13,8 @@ Quick-start development settings - unsuitable for production
See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
"""
import socket
import logging
from decouple import config
from dj_database_url import parse as db_url
@ -22,10 +24,11 @@ from unipath import Path
from .temp_suppress_crispy_form_warnings import \
SUPRESS_CRISPY_FORM_WARNINGS_LOGGING
host = socket.gethostbyname_ex(socket.gethostname())[0]
BASE_DIR = Path(__file__).ancestor(1)
PROJECT_DIR = Path(__file__).ancestor(2)
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config('SECRET_KEY', default='')
# SECURITY WARNING: don't run with debug turned on in production!
@ -115,11 +118,7 @@ HAYSTACK_CONNECTIONS = {
},
}
if DEBUG:
INSTALLED_APPS += ('debug_toolbar', 'rest_framework_docs',)
MIDDLEWARE_CLASSES = (
MIDDLEWARE = [
'reversion.middleware.RevisionMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
@ -130,8 +129,13 @@ MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
# 'speedinfo.middleware.ProfilerMiddleware', # Bug na versão 1.9
)
'speedinfo.middleware.ProfilerMiddleware',
]
if DEBUG:
INSTALLED_APPS += ('debug_toolbar', 'rest_framework_docs',)
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware', ]
INTERNAL_IPS = ('127.0.0.1')
CACHES = {
'default': {
@ -292,34 +296,40 @@ SASS_PROCESSOR_INCLUDE_DIRS = (BOWER_COMPONENTS_ROOT.child(
# suprime texto de ajuda default do django-filter
FILTERS_HELP_TEXT_FILTER = False
# FIXME update cripy-forms and remove this
# hack to suppress many annoying warnings from crispy_forms
# see sapl.temp_suppress_crispy_form_warnings
LOGGING = SUPRESS_CRISPY_FORM_WARNINGS_LOGGING
# FIXME: gerando problemas na alternancia entre django 1.9.13 e 1.10.8
# Issue 52 https://github.com/interlegis/sapl/issues/52
LOGGING_CONSOLE = config('LOGGING_CONSOLE', default=False, cast=bool)
"""if DEBUG and LOGGING_CONSOLE:
# Descomentar linha abaixo fará com que logs aparecam, inclusive SQL
# LOGGING['handlers']['console']['level'] = 'DEBUG'
LOGGING['loggers']['django']['level'] = 'DEBUG'
LOGGING['formatters'].update({
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(pathname)s '
'%(funcName)s %(message)s'
'format': '%(levelname)s %(asctime)s ' + host + ' %(pathname)s %(name)s:%(funcName)s:%(lineno)d %(message)s'
},
'simple': {
'format': '%(levelname)s %(message)s'
'format': '%(levelname)s %(asctime)s - %(message)s'
},
},
'handlers': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'simple',
},
'applogfile': {
'level':'INFO',
'class':'logging.handlers.RotatingFileHandler',
'filename': 'sapl.log',
'maxBytes': 1024*1024*15, # 15MB
'backupCount': 10,
'formatter': 'verbose',
},
},
'loggers': {
'sapl': {
'handlers': ['applogfile'],
'level': 'INFO',
'propagate': True,
},
})
LOGGING['handlers']['console']['formatter'] = 'verbose'
LOGGING['loggers'][BASE_DIR.name] = {
'handlers': ['console'],
'level': 'DEBUG',
}
}
def excepthook(*args):

1
sapl/static/styles/app.scss

@ -168,6 +168,7 @@ fieldset {
img.img-responsive {
height: 95px;
margin-right: $navbar-padding-horizontal;
display: inline-block;
}
small {
color: #93A4AA;

171
sapl/templates/404.html

@ -0,0 +1,171 @@
{% load i18n staticfiles sass_tags menus %}
{% load common_tags %}
<!DOCTYPE html>
<!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js" lang="pt-br">
<!--<![endif]-->
<head>
<meta charset="utf-8">
<title>{% block head_title %}{% trans 'SAPL - Sistema de Apoio ao Processo Legislativo' %}{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% block head_content %}
<link rel="icon" href="{% static 'img/favicon.ico' %}" type="image/png" >
{# Styles #}
<link rel="stylesheet" href="{% static 'components-font-awesome/css/font-awesome.css' %}">
<link rel="stylesheet" href="{% sass_src 'bootstrap-sass/assets/stylesheets/_bootstrap.scss' %}" type="text/css">
<link rel="stylesheet" href="{% static 'drunken-parrot-flat-ui/css/drunken-parrot.css' %}">
<link rel="stylesheet" href="{% sass_src 'styles/app.scss' %}" type="text/css">
<link rel="stylesheet" href="{% static 'jquery-ui/themes/cupertino/jquery-ui.min.css' %}">
<script type="text/javascript" src="{% static 'jquery/dist/jquery.min.js' %}"></script>
{# Scripts #}
{# modernizr must be in head (see http://modernizr.com/docs/#installing) #}
{% endblock %}
</head>
<body>
<div class="page fadein">
{% if not request|has_iframe %}
{% block navigation %}
<nav class="navbar navbar-inverse navbar-static-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div id="navbar" class="navbar-collapse collapse">
</div><!--/.nav-collapse -->
</div>
</nav>
{% endblock navigation %}
{# Header #}
{% block main_header %}
<header class="masthead">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">
<img src="{% if logotipo %}{{ MEDIA_URL }}{{ logotipo }}{% else %}{% static 'img/logo.png' %}{% endif %}"
alt="Logo" class="img-responsive visible-md-inline-block visible-lg-inline-block" >
<span class="vcenter">
{# XXX Make better use of translation tags in html blocks ie. actually use the proper blocktrans tag efficiently #}
<br/><small>{% trans 'Sistema de Apoio ao Processo Legislativo' %}</small>
</span>
</a>
</div>
<div class="hidden-print">
{% block sections_nav %} {% subnav %} {% endblock sections_nav %}
</div>
</div>
</header>
{% endblock main_header %}
{% else %}
<div class="btn-cancel-iframe">
<a href="?iframe=0" target="_blank"><i class="fa fa-2x fa-arrows-alt"></i></a>
</div>
<header class="masthead">
<div class="container">
<div class="hidden-print">
{% subnav %}
</div>
</div>
</header>
{% endif %}
<div class="container">
<span class="text-center">
<br/><h1><big>{% trans 'Página não encontrada! Erro 404' %}</big></h1>
</span>
</div>
{% block base_content %}
{% endblock %}
{% if not request|has_iframe %}
{% block footer_container %}
<footer id="footer" class="footer page__row hidden-print">
<div class="container">
<div class="row">
<div class="col-md-4">
<a class="footer__logo" href="#">
<a href="http://www.interlegis.leg.br/">
<img src="{% static 'img/logo_interlegis.png' %}" alt="{% trans 'Logo do Interlegis' %} ">
</a>
</a>
<p>
<small>
Desenvolvido pelo <a href="http://www.interlegis.leg.br/">Interlegis</a> em software livre e aberto.
</small>
</p>
</div>
<div class="col-md-4">
<a class="footer__logo" href="#">
<img src="{% static 'img/logo_cc.png' %}" alt="{% trans 'Logo do Creative Commons BY SA' %}">
</a>
<p>
<small>
Conteúdo e dados sob licença <a href="https://creativecommons.org">Creative Commons</a> 4.0 <a href="https://creativecommons.org/licenses/by/4.0/">Atribuir Fonte - Compartilhar Igual</a>
</small>
</p>
</div>
</div>
</div>
</footer>
</div>
{% endblock footer_container %}
{% endif %}
{% block foot_js %}
<!-- Bootstrap core JavaScript ================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="{% static 'bootstrap-sass/assets/javascripts/bootstrap.min.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-ui/jquery-ui.min.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-ui/ui/i18n/datepicker-pt-BR.js' %}"></script>
<script type="text/javascript" src="{% static 'js/jquery.runner.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-mask-plugin/dist/jquery.mask.js' %}"></script>
<script src="{% static 'tinymce/tinymce.min.js' %}"></script>
<script type="text/javascript" src="{% static 'jsdiff/diff.min.js' %}"></script>
<script type="text/javascript" src="{% static 'drunken-parrot-flat-ui/js/checkbox.js' %}"></script>
<script type="text/javascript" src="{% static 'drunken-parrot-flat-ui/js/radio.js' %}"></script>
<script type="text/javascript" src="{% static 'js/app.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-query-object/jquery.query-object.js' %}"></script>
{% block extra_js %}{% endblock %}
<script type="text/javascript" >
function inIframe () {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
$(document).ready(function(){
let iframe_set_backend = {{ request|has_iframe|lower }}
if (iframe_set_backend && !inIframe() ) {
location.href = location.origin + '?iframe=0'
}
});
</script>
{% endblock foot_js %}
</body>
</html>

135
sapl/templates/500.html

@ -0,0 +1,135 @@
{% load i18n staticfiles sass_tags menus %}
{% load common_tags %}
<!DOCTYPE html>
<!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js" lang="pt-br">
<!--<![endif]-->
<head>
<meta charset="utf-8">
<title>{% block head_title %}{% trans 'SAPL - Sistema de Apoio ao Processo Legislativo' %}{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% block head_content %}
<link rel="icon" href="{% static 'img/favicon.ico' %}" type="image/png" >
{# Styles #}
<link rel="stylesheet" href="{% static 'components-font-awesome/css/font-awesome.css' %}">
<link rel="stylesheet" href="{% sass_src 'bootstrap-sass/assets/stylesheets/_bootstrap.scss' %}" type="text/css">
<link rel="stylesheet" href="{% static 'drunken-parrot-flat-ui/css/drunken-parrot.css' %}">
<link rel="stylesheet" href="{% sass_src 'styles/app.scss' %}" type="text/css">
<link rel="stylesheet" href="{% static 'jquery-ui/themes/cupertino/jquery-ui.min.css' %}">
<script type="text/javascript" src="{% static 'jquery/dist/jquery.min.js' %}"></script>
{# Scripts #}
{# modernizr must be in head (see http://modernizr.com/docs/#installing) #}
{% endblock %}
</head>
<body>
<div class="page fadein">
{% block navigation %}
<nav class="navbar navbar-inverse navbar-static-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div id="navbar" class="navbar-collapse collapse">
</div><!--/.nav-collapse -->
</div>
</nav>
{% endblock navigation %}
{# Header #}
{% block main_header %}
<header class="masthead">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">
<span class="text-center">
<br/><small>{% trans 'Sistema de Apoio ao Processo Legislativo' %}</small>
</span>
</a>
</div>
<div class="hidden-print">
{% block sections_nav %} {% subnav %} {% endblock sections_nav %}
</div>
</div>
</header>
{% endblock main_header %}
<div class="container">
<span class="text-center">
<br/><h1><big>{% trans 'Ocorreu um erro inesperado! Erro 500' %}</big></h1>
</span>
</div>
{% block base_content %}
{% endblock %}
{% block footer_container %}
<footer id="footer" class="footer page__row hidden-print">
<div class="container">
<div class="row">
<div class="col-md-4">
<a class="footer__logo" href="#">
<a href="http://www.interlegis.leg.br/">
<img src="{% static 'img/logo_interlegis.png' %}" alt="{% trans 'Logo do Interlegis' %} ">
</a>
</a>
<p>
<small>
Desenvolvido pelo <a href="http://www.interlegis.leg.br/">Interlegis</a> em software livre e aberto.
</small>
</p>
</div>
<div class="col-md-4">
<a class="footer__logo" href="#">
<img src="{% static 'img/logo_cc.png' %}" alt="{% trans 'Logo do Creative Commons BY SA' %}">
</a>
<p>
<small>
Conteúdo e dados sob licença <a href="https://creativecommons.org">Creative Commons</a> 4.0 <a href="https://creativecommons.org/licenses/by/4.0/">Atribuir Fonte - Compartilhar Igual</a>
</small>
</p>
</div>
</div>
</div>
</footer>
</div>
{% endblock footer_container %}
{% block foot_js %}
<!-- Bootstrap core JavaScript ================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="{% static 'bootstrap-sass/assets/javascripts/bootstrap.min.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-ui/jquery-ui.min.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-ui/ui/i18n/datepicker-pt-BR.js' %}"></script>
<script type="text/javascript" src="{% static 'js/jquery.runner.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-mask-plugin/dist/jquery.mask.js' %}"></script>
<script src="{% static 'tinymce/tinymce.min.js' %}"></script>
<script type="text/javascript" src="{% static 'jsdiff/diff.min.js' %}"></script>
<script type="text/javascript" src="{% static 'drunken-parrot-flat-ui/js/checkbox.js' %}"></script>
<script type="text/javascript" src="{% static 'drunken-parrot-flat-ui/js/radio.js' %}"></script>
<script type="text/javascript" src="{% static 'js/app.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-query-object/jquery.query-object.js' %}"></script>
{% block extra_js %}{% endblock %}
{% endblock foot_js %}
</body>
</html>

5
sapl/templates/audiencia/layouts.yaml

@ -22,3 +22,8 @@ AudienciaPublicaDetail:
- upload_pauta upload_ata upload_anexo
- observacao
- audiencia_cancelada
AnexoAudienciaPublica:
{% trans 'Documento Acessório' %}:
- assunto
- arquivo

5
sapl/templates/audiencia/subnav.yaml

@ -0,0 +1,5 @@
{% load i18n common_tags %}
- title: {% trans 'Início' %}
url: audienciapublica_detail
- title: {% trans 'Documento Acessório' %}
url: anexoaudienciapublica_list

6
sapl/templates/base.html

@ -1,6 +1,6 @@
<!DOCTYPE html>
{% load i18n staticfiles sass_tags menus %}
{% load common_tags %}
<!DOCTYPE html>
<!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js" lang="pt-br">
@ -90,7 +90,7 @@
<div class="navbar-header">
<a class="navbar-brand" href="/">
<img src="{% if logotipo %}{{ MEDIA_URL }}{{ logotipo }}{% else %}{% static 'img/logo.png' %}{% endif %}"
alt="Logo" class="img-responsive visible-md-inline-block visible-lg-inline-block" >
alt="Logo" class="img-responsive" >
<span class="vcenter">
{# XXX Make better use of translation tags in html blocks ie. actually use the proper blocktrans tag efficiently #}
{% if nome %}
@ -184,7 +184,7 @@
<small>
Desenvolvido pelo <a href="http://www.interlegis.leg.br/">Interlegis</a> em software livre e aberto.
</small>
<span>Release: 3.1.124</span>
<span>Release: 3.1.131</span>
</p>
</div>
<div class="col-md-4">

9
sapl/templates/compilacao/dispositivo_form_search_fragment.html

@ -1,5 +1,14 @@
{% load i18n compilacao_filters %}
{% for message in messages %}
<div class="alert alert-{% if message.tags == 'error' %}danger{% else %}{{ message.tags }}{% endif %} alert-dismissible fade in" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
{{ message|safe }}
</div>
{% endfor %}
{% if object_list.count >= 100 %}
<div class="alert-box success radius">
{% trans 'Use argumentos para simplificar listagem...' %}

10
sapl/templates/compilacao/messages.html

@ -0,0 +1,10 @@
{% load i18n compilacao_filters %}
{% for message in messages %}
<div class="alert alert-{% if message.tags == 'error' %}danger{% else %}{{ message.tags }}{% endif %} alert-dismissible fade in" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
{{ message|safe }}
</div>
{% endfor %}

16
sapl/templates/crud/detail.html

@ -65,7 +65,21 @@
<div id="div_id_{{ column.id }}" class="form-group">
<p class="control-label">{{ column.verbose_name }}</p>
<div class="controls">
{% if column.text|url %}
{% if column.text|audio_url %}
<div class="form-control-static">
<audio controls>
<source src="{{ column.text|safe }}" type="audio/{{ column.text|file_extension }}">
<p>Este navegador não suporta o elemento áudio.</p>
</audio>
</div>
{% elif column.text|video_url %}
<div class="form-control-static">
<video width="320" height="120" controls>
<source src="{{ column.text|safe }}" type="video/{{ column.text|file_extension }}">
<p>Este navegador não suporta o elemento vídeo.</p>
</video>
</div>
{% elif column.text|url %}
<div class="form-control-static"><a href="{{ column.text|safe }}"> {{ column.text|safe|default:"" }} </a></div>
{% else %}
<div class="form-control-static">{{ column.text|safe|default:"" }}</div>

10
sapl/templates/materia/impressos/ficha_pdf.html

@ -70,7 +70,7 @@ body
<strong class="text_pdf">PROCESSO Nº {{ materia.numeracao_set.first.numero_materia }} / {{ materia.numeracao_set.first.ano_materia }}</strong><br>
&nbsp;
{% else %}
<strong class="text_pdf">PROCESSO Nº: {{ materia.numero }}</strong><br>
<strong class="text_pdf">PROCESSO Nº: {{ materia.numero }} / {{materia.ano}}</strong><br>
&nbsp;
{% endif %}
</div>
@ -96,6 +96,14 @@ body
<strong class="text_pdf">Autor: </strong><span class="text_pdf">{{materia.autoria_set.first.autor.nome}}</span><br>
</td>
</table>
{% if materia.numero_protocolo%}
<table border=0>
<td height="60pt" valign=top>
<div>
<strong class="text_pdf">Protocolo: </strong><span class="text_pdf">{{materia.numero_protocolo}} / {{materia.ano}}</span><br>
</td>
</table>
{% endif %}
<!-- Ementa -->
<table border=0>

15
sapl/templates/materia/materialegislativa_detail.html

@ -10,6 +10,21 @@
{% endblock sub_actions %}
{% block detail_content %}
{{ block.super }}
{% if object.registrovotacao_set.exists %}
<strong>Data Votação:</strong>
{% for rv in object.registrovotacao_set.all %}
{% if rv.ordem %}
<a href="{% url 'sapl.sessao:ordemdia_list' rv.ordem.sessao_plenaria_id %}">
{{ rv.ordem.sessao_plenaria.data_inicio }}
</a>
{% elif rv.expediente %}
<a href="{% url 'sapl.sessao:expedientemateria_list' rv.expediente.sessao_plenaria_id %}">
{{ rv.expediente.sessao_plenaria.data_inicio }}
</a>
{% endif %}
</br>
{% endfor %}
{% endif %}
{% if object.normajuridica_set.last %}
<p class="control-label">&emsp; Norma Jurídica Relacionada</p>
<div class="actions btn-group btn-group-sm" role="group">

17
sapl/templates/materia/proposicao_detail.html

@ -143,9 +143,26 @@
<h2 class="legend">{% trans "Vínculo com a Matéria Legislativa" %}</h2>
<div id="div_id_materia_de_vinculo" class="form-group">
<div class="controls">
Matéria</br>
&nbsp;&nbsp;&nbsp;&nbsp;
<a href="{% url object.materia_de_vinculo|urldetail object.materia_de_vinculo.id%}">
{{object.materia_de_vinculo}}
</a>
</br>
{% if object.materia_de_vinculo.autoria_set.all %}
Autores
{% for a in object.materia_de_vinculo.autoria_set.all %}
</br>&nbsp;&nbsp;&nbsp;&nbsp;{{a.autor}}
{% endfor %}
{% endif %}
</br>
Texto Original
</br>
&nbsp;&nbsp;&nbsp;&nbsp;
<a href="{{object.materia_de_vinculo.texto_original.url}}">
{{object.materia_de_vinculo.texto_original| to_str | split:"/" | get_last_item_from_list:-1}}
</a>
</br>
</div>
</div>
</div>

6
sapl/templates/protocoloadm/protocolo_mostrar.html

@ -9,10 +9,10 @@
<a href="{% url 'sapl.relatorios:relatorio_etiqueta_protocolo' protocolo.numero protocolo.ano %}"><img src="{% static 'img/etiqueta.png' %}" alt="Etiqueta Individual"></a></br>
<strong>Assunto: </strong> {{ protocolo.assunto_ementa|default:"Não informado" }}</br>
{% if p.timestamp%}
<strong>Data Protocolo:</strong> {{ p.timestamp|localtime|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ p.timestamp|localtime|date:"G:i:s" }}</br>
{% if protocolo.timestamp %}
<strong>Data Protocolo:</strong> {{ protocolo.timestamp|localtime|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ protocolo.timestamp|localtime|date:"G:i:s" }}</br>
{% else %}
<strong>Data Protocolo:</strong> {{ p.data|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ p.hora|date:"G:i:s" }}</br>
<strong>Data Protocolo:</strong> {{ protocolo.data|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ protocolo.hora|date:"G:i:s" }}</br>
{% endif %}
{% if protocolo.tipo_processo == 0 %}

2
sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html

@ -1,6 +1,6 @@
<fieldset>
<p align="justify">
<strong>Ocorrências da Sessão: </strong>
{{object.ocorrenciasessao.conteudo|safe}}
{{object.ocorrenciasessao.conteudo|striptags|safe}}
</p>
</fieldset>

2
sapl/test_urls.py

@ -56,7 +56,7 @@ def create_perms_post_migrate(sapl_app_config):
ctype = ContentType.objects.get_for_model(klass)
ctypes.add(ctype)
for perm in _get_all_permissions(klass._meta, ctype):
for perm in _get_all_permissions(klass._meta):
searched_perms.append((ctype, perm))
all_perms = set(Permission.objects.filter(

6
sapl/urls.py

@ -70,6 +70,12 @@ urlpatterns = [
# http://stackoverflow.com/questions/35510373/
if settings.DEBUG:
import debug_toolbar
urlpatterns += [
url(r'^__debug__/', include(debug_toolbar.urls)),
]
urlpatterns += static(settings.STATIC_URL,
document_root=settings.STATIC_ROOT)

6
sapl/utils.py

@ -28,6 +28,10 @@ from unipath.path import Path
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
# (26/10/2018): O separador foi mudador de '/' para 'K'
# por conta dos leitores de códigos de barra, que trocavam
# a '/' por '&' ou ';'
SEPARADOR_HASH_PROPOSICAO = 'K'
def pil_image(source, exif_orientation=False, **options):
return source_generators.pil_image(source, exif_orientation, **options)
@ -484,7 +488,7 @@ def gerar_hash_arquivo(arquivo, pk, block_size=2**20):
if not data:
break
md5.update(data)
return 'P' + md5.hexdigest() + '/' + pk
return 'P' + md5.hexdigest() + SEPARADOR_HASH_PROPOSICAO + pk
class ChoiceWithoutValidationField(forms.ChoiceField):

27
setup.py

@ -11,29 +11,30 @@ os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
install_requires = [
'dj-database-url==0.4.1',
'django-haystack==2.6.0',
'django>=1.9,<1.10',
'django>=1.10,<1.11',
# TODO O django-admin-bootstrapped 2.5.7 não inseriu a mudança que permite
# a compatibilidade com Django 1.9+. A linha abaixo será mudada quando uma
# nova versão do django-admin-bootstrapped for lançada
# 'git+git://github.com/django-admin-bootstrapped/
# django-admin-bootstrapped.git',
'django-bootstrap3==7.0.1',
'django-bower==5.1.0',
'django-bower==5.2.0',
'django-braces==1.9.0',
'django-compressor==2.0',
'django-crispy-forms==1.6.0',
'django-extensions==1.6.7',
'django-extra-views==0.8.0',
'django-crispy-forms==1.6.1',
'django-extensions==1.9.8',
'django-extra-views==0.11.0',
'django-filter==0.15.3',
'django-floppyforms==1.6.2',
'django-model-utils==2.5',
'django-sass-processor==0.5.4',
'djangorestframework',
'django-model-utils==3.1.1',
'django-sass-processor==0.5.8',
'djangorestframework==3.4.0',
'drfdocs',
'easy-thumbnails==2.3',
'easy-thumbnails==2.5',
'django-image-cropping==1.1.0',
# 'git+git://github.com/interlegis/trml2pdf.git',
'libsass==0.11.1',
'psycopg2==2.7.3',
'psycopg2==2.7.4',
'python-decouple==3.0',
'pytz==2016.4',
'pyyaml==3.11',
@ -45,11 +46,13 @@ install_requires = [
'gunicorn==19.6.0',
'django-reversion==2.0.8',
'WeasyPrint==0.42',
'whoosh==2.7.4'
'whoosh==2.7.4',
'django-speedinfo==1.3.5',
'django-reversion-compare==0.8.4'
]
setup(
name='interlegis-sapl',
version='3.1.124',
version='3.1.131',
packages=find_packages(),
include_package_data=True,
license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007',

Loading…
Cancel
Save