Browse Source

Merge pull request #529 from interlegis/103-autorizacao-final

Fix #103 autorizacao final
pull/534/head
Edward 9 years ago
committed by GitHub
parent
commit
91ce328702
  1. 1
      .travis.yml
  2. 69
      sapl/base/templatetags/common_tags.py
  3. 4
      sapl/base/urls.py
  4. 26
      sapl/base/views.py
  5. 12
      sapl/comissoes/tests/test_comissoes.py
  6. 66
      sapl/comissoes/views.py
  7. 109
      sapl/materia/forms.py
  8. 37
      sapl/materia/migrations/0039_auto_20160628_1251.py
  9. 6
      sapl/materia/migrations/0044_merge.py
  10. 24
      sapl/materia/migrations/0045_auto_20160823_1658.py
  11. 23
      sapl/materia/models.py
  12. 149
      sapl/materia/tests/test_materia.py
  13. 10
      sapl/materia/urls.py
  14. 343
      sapl/materia/views.py
  15. 8
      sapl/norma/tests/test_norma.py
  16. 33
      sapl/norma/views.py
  17. 13
      sapl/painel/views.py
  18. 6
      sapl/parlamentares/forms.py
  19. 22
      sapl/parlamentares/migrations/0022_auto_20160624_1124.py
  20. 21
      sapl/parlamentares/migrations/0022_auto_20160702_1519.py
  21. 21
      sapl/parlamentares/migrations/0023_auto_20160628_1247.py
  22. 16
      sapl/parlamentares/migrations/0024_merge.py
  23. 4
      sapl/parlamentares/models.py
  24. 35
      sapl/parlamentares/tests/test_parlamentares.py
  25. 189
      sapl/parlamentares/views.py
  26. 87
      sapl/protocoloadm/forms.py
  27. 114
      sapl/protocoloadm/migrations/0001_initial.py
  28. 59
      sapl/protocoloadm/migrations/0002_auto_20150729_1717.py
  29. 22
      sapl/protocoloadm/migrations/0003_documentoacessorioadministrativo_texto_integral.py
  30. 27
      sapl/protocoloadm/migrations/0004_auto_20151007_1035.py
  31. 22
      sapl/protocoloadm/migrations/0005_auto_20151008_0744.py
  32. 74
      sapl/protocoloadm/migrations/0006_auto_20160216_1015.py
  33. 19
      sapl/protocoloadm/migrations/0007_auto_20160218_1429.py
  34. 20
      sapl/protocoloadm/migrations/0008_auto_20160308_1436.py
  35. 20
      sapl/protocoloadm/migrations/0009_auto_20160309_1323.py
  36. 25
      sapl/protocoloadm/migrations/0010_auto_20160309_1407.py
  37. 20
      sapl/protocoloadm/migrations/0011_auto_20160318_1504.py
  38. 26
      sapl/protocoloadm/migrations/0012_auto_20160503_0926.py
  39. 26
      sapl/protocoloadm/migrations/0012_tipoinstituicao.py
  40. 7
      sapl/protocoloadm/models.py
  41. 8
      sapl/protocoloadm/tests/test_protocoloadm.py
  42. 17
      sapl/protocoloadm/urls.py
  43. 187
      sapl/protocoloadm/views.py
  44. 261
      sapl/sessao/views.py
  45. 2
      sapl/settings.py
  46. 19
      sapl/templates/base.html
  47. 7
      sapl/templates/confirma_email.html
  48. 6
      sapl/templates/crud/detail.html
  49. 7
      sapl/templates/crud/list.html
  50. 12
      sapl/templates/materia/layouts.yaml
  51. 4
      sapl/templates/materia/materialegislativa_filter.html
  52. 20
      sapl/templates/materia/proposicao_detail.html
  53. 8
      sapl/templates/mesa_diretora/mesa_diretora.html
  54. 4
      sapl/templates/norma/list_pesquisa.html
  55. 3
      sapl/templates/norma/pesquisa.html
  56. 73
      sapl/templates/parlamentares/parlamentar_perfil_publico.html
  57. 9
      sapl/templates/protocoloadm/documentoadministrativo_detail.html
  58. 26
      sapl/templates/protocoloadm/documentoadministrativo_filter.html
  59. 6
      sapl/templates/protocoloadm/protocolo_filter.html
  60. 9
      sapl/templates/protocoloadm/protocolo_pesquisa.html
  61. 6
      sapl/templates/protocoloadm/protocoloadm_detail.html
  62. 40
      sapl/templates/protocoloadm/tramitacao.html
  63. 15
      sapl/templates/protocoloadm/tramitacao_edit.html
  64. 14
      sapl/templates/protocoloadm/tramitacao_incluir.html
  65. 9
      sapl/templates/protocoloadm/tramitacaoadministrativo_detail.html
  66. 84
      sapl/templates/sessao/materia_ordemdia_list.html
  67. 92
      sapl/utils.py
  68. 114
      scripts/inicializa_grupos_autorizacoes.py
  69. 47
      scripts/test_inicializa_grupos_autorizacoes.py

1
.travis.yml

@ -3,7 +3,6 @@ language: python
python:
- 3.4.3
services:
- postgresql

69
sapl/base/templatetags/common_tags.py

@ -1,6 +1,8 @@
from compressor.utils import get_class
from django import template
from sapl.parlamentares.models import Filiacao
register = template.Library()
@ -36,3 +38,70 @@ def lookup(d, key):
def isinst(value, class_str):
classe = value.__class__.__name__
return classe == class_str
@register.filter
def get_add_perm(value, arg):
perm = value
view = arg
try:
nome_app = view.__class__.model._meta.app_label
except AttributeError:
return None
nome_model = view.__class__.model.__name__.lower()
can_add = '.add_' + nome_model
return perm.__contains__(nome_app + can_add)
@register.filter
def get_change_perm(value, arg):
perm = value
view = arg
try:
nome_app = view.__class__.model._meta.app_label
except AttributeError:
return None
nome_model = view.__class__.model.__name__.lower()
can_change = '.change_' + nome_model
return perm.__contains__(nome_app + can_change)
@register.filter
def get_delete_perm(value, arg):
perm = value
view = arg
try:
nome_app = view.__class__.model._meta.app_label
except AttributeError:
return None
nome_model = view.__class__.model.__name__.lower()
can_delete = '.delete_' + nome_model
return perm.__contains__(nome_app + can_delete)
@register.filter
def ver_menu_sistema_perm(value):
u = value
if u.groups.filter(name='Operador Geral').exists() or u.is_superuser:
return True
else:
return False
@register.filter
def ultima_filiacao(value):
parlamentar = value
ultima_filiacao = Filiacao.objects.filter(
parlamentar=parlamentar).order_by('-data').first()
if ultima_filiacao:
return ultima_filiacao.partido
else:
return None

4
sapl/base/urls.py

@ -4,7 +4,7 @@ from django.views.generic.base import TemplateView
from .apps import AppConfig
from .forms import LoginForm
from .views import CasaLegislativaCrud, HelpView
from .views import CasaLegislativaCrud, HelpView, SistemaView
app_name = AppConfig.name
@ -21,5 +21,5 @@ urlpatterns = [
url(r'^login/$', views.login, {
'template_name': 'base/login.html', 'authentication_form': LoginForm},
name='login'),
url(r'^logout/$', views.logout, {'next_page': '/login'}, name='logout')
url(r'^logout/$', views.logout, {'next_page': '/login'}, name='logout'),
]

26
sapl/base/views.py

@ -1,9 +1,11 @@
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.views.generic.base import TemplateView
from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView,
CrudDetailView, CrudUpdateView)
from sapl.utils import permissao_tb_aux
from .forms import CasaLegislativaForm
from .models import CasaLegislativa
@ -17,13 +19,21 @@ class CasaLegislativaCrud(Crud):
model = CasaLegislativa
help_path = ''
class BaseMixin(CrudBaseMixin):
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
list_field_names = ['codigo', 'nome', 'sigla']
class CreateView(CrudCreateView):
def has_permission(self):
if self.request.user.is_superuser:
return True
else:
return False
class CreateView(PermissionRequiredMixin, CrudCreateView):
permission_required = {'base.add_casa_legislativa'}
form_class = CasaLegislativaForm
class UpdateView(CrudUpdateView):
class UpdateView(PermissionRequiredMixin, CrudUpdateView):
permission_required = {'base.change_casalegislativa'}
form_class = CasaLegislativaForm
class DetailView(CrudDetailView):
@ -35,8 +45,16 @@ class CasaLegislativaCrud(Crud):
kwargs={'pk': self.kwargs['pk']}))
class HelpView(TemplateView):
class HelpView(PermissionRequiredMixin, TemplateView):
# XXX treat non existing template as a 404!!!!
def get_template_names(self):
return ['ajuda/%s.html' % self.kwargs['topic']]
class SistemaView(PermissionRequiredMixin, TemplateView):
template_name = 'sistema.html'
permission_required = ''
def has_permission(self):
return permissao_tb_aux(self)

12
sapl/comissoes/tests/test_comissoes.py

@ -44,11 +44,11 @@ def make_filiacao():
@pytest.mark.django_db(transaction=False)
def test_incluir_parlamentar_errors(client):
def test_incluir_parlamentar_errors(admin_client):
comissao = make_comissao()
composicao = make_composicao(comissao)
response = client.post(reverse('sapl.comissoes:participacao_create',
response = admin_client.post(reverse('sapl.comissoes:participacao_create',
kwargs={'pk': composicao.pk}),
{'salvar': 'salvar'},
follow=True)
@ -62,12 +62,12 @@ def test_incluir_parlamentar_errors(client):
@pytest.mark.django_db(transaction=False)
def test_incluir_comissao_submit(client):
def test_incluir_comissao_submit(admin_client):
tipo = mommy.make(TipoComissao,
sigla='T',
nome='Teste')
response = client.post(reverse('sapl.comissoes:comissao_create'),
response = admin_client.post(reverse('sapl.comissoes:comissao_create'),
{'tipo': tipo.pk,
'nome': 'Comissão Teste',
'sigla': 'CT',
@ -82,9 +82,9 @@ def test_incluir_comissao_submit(client):
@pytest.mark.django_db(transaction=False)
def test_incluir_comissao_errors(client):
def test_incluir_comissao_errors(admin_client):
response = client.post(reverse('sapl.comissoes:comissao_create'),
response = admin_client.post(reverse('sapl.comissoes:comissao_create'),
{'salvar': 'salvar'},
follow=True)

66
sapl/comissoes/views.py

@ -1,17 +1,16 @@
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.urlresolvers import reverse
from django.views.generic import ListView
from sapl.crud.base import Crud, CrudBaseMixin
from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView,
CrudDeleteView, CrudUpdateView)
from sapl.crud.masterdetail import MasterDetailCrud
from sapl.materia.models import Tramitacao
from sapl.utils import permissao_tb_aux, permissoes_comissoes
from .models import (CargoComissao, Comissao, Composicao, Participacao,
Periodo, TipoComissao)
CargoCrud = Crud.build(CargoComissao, 'cargo_comissao')
PeriodoComposicaoCrud = Crud.build(Periodo, 'periodo_composicao_comissao')
TipoComissaoCrud = Crud.build(TipoComissao, 'tipo_comissao')
def pegar_url_composicao(pk):
participacao = Participacao.objects.get(id=pk)
@ -20,13 +19,46 @@ def pegar_url_composicao(pk):
return url
class CargoCrud(Crud):
model = CargoComissao
help_path = 'cargo_comissao'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
list_field_names = ['nome', 'unico']
def has_permission(self):
return permissao_tb_aux(self)
class PeriodoComposicaoCrud(Crud):
model = Periodo
help_path = 'periodo_composicao_comissao'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
list_field_names = ['data_inicio', 'data_fim']
def has_permission(self):
return permissao_tb_aux(self)
class TipoComissaoCrud(Crud):
model = TipoComissao
help_path = 'tipo_comissao'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
list_field_names = ['sigla', 'nome', 'natureza',
'dispositivo_regimental']
def has_permission(self):
return permissao_tb_aux(self)
class ParticipacaoCrud(MasterDetailCrud):
model = Participacao
parent_field = 'composicao'
help_path = ''
class DetailView(MasterDetailCrud.DetailView):
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
@ -63,6 +95,10 @@ class ParticipacaoCrud(MasterDetailCrud):
def cancel_url(self):
return pegar_url_composicao(self.kwargs['pk'])
class BaseMixin(PermissionRequiredMixin, MasterDetailCrud.BaseMixin):
permission_required = permissoes_comissoes()
list_field_names = ['composicao', 'parlamentar', 'cargo']
class ComposicaoCrud(MasterDetailCrud):
model = Composicao
@ -78,11 +114,29 @@ class ComposicaoCrud(MasterDetailCrud):
context['participacoes'] = composicao.participacao_set.all()
return self.render_to_response(context)
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
permission_required = permissoes_comissoes()
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
permission_required = permissoes_comissoes()
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_comissoes()
class ComissaoCrud(Crud):
model = Comissao
help_path = 'modulo_comissoes'
class CreateView(PermissionRequiredMixin, CrudCreateView):
permission_required = permissoes_comissoes()
class UpdateView(PermissionRequiredMixin, CrudUpdateView):
permission_required = permissoes_comissoes()
class DeleteView(PermissionRequiredMixin, CrudDeleteView):
permission_required = permissoes_comissoes()
class BaseMixin(CrudBaseMixin):
list_field_names = ['nome', 'sigla', 'tipo', 'data_criacao', 'ativa']

109
sapl/materia/forms.py

@ -4,8 +4,10 @@ import django_filters
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout
from django import forms
from django.contrib.auth.models import Group, User
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models
from django.db import models, transaction
from django.db.models import Max
from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _
@ -136,7 +138,8 @@ class ProposicaoForm(ModelForm):
class Meta:
model = Proposicao
fields = ['tipo', 'data_envio', 'descricao', 'texto_original']
fields = ['tipo', 'data_envio', 'descricao', 'texto_original', 'autor']
widgets = {'autor': forms.HiddenInput()}
class AcompanhamentoMateriaForm(ModelForm):
@ -580,3 +583,105 @@ class AutoriaForm(ModelForm):
raise ValidationError(msg)
return self.cleaned_data
class AutorForm(ModelForm):
senha = forms.CharField(
max_length=20,
label=_('Senha'),
required=True,
widget=forms.PasswordInput())
senha_confirma = forms.CharField(
max_length=20,
label=_('Confirmar Senha'),
required=True,
widget=forms.PasswordInput())
confirma_email = forms.EmailField(
required=True,
label=_('Confirmar Email'))
class Meta:
model = Autor
fields = ['username',
'senha',
'email',
'nome',
'tipo',
'cargo',
'parlamentar',
'comissao']
def valida_igualdade(self, texto1, texto2, msg):
if texto1 != texto2:
raise ValidationError(msg)
return True
def valida_email_existente(self):
return User.objects.filter(
email=self.cleaned_data['email']).exists()
def usuario_existente(self):
return User.objects.filter(
username=self.cleaned_data['username']).exists()
def clean(self):
if ('senha' not in self.cleaned_data or
'senha_confirma' not in self.cleaned_data):
raise ValidationError(_('Favor informar as senhas'))
msg = _('As senhas não conferem.')
self.valida_igualdade(
self.cleaned_data['senha'],
self.cleaned_data['senha_confirma'],
msg)
if ('email' not in self.cleaned_data or
'confirma_email' not in self.cleaned_data):
raise ValidationError(_('Favor informar endereços de email'))
msg = _('Os emails não conferem.')
self.valida_igualdade(
self.cleaned_data['email'],
self.cleaned_data['confirma_email'],
msg)
email_existente = self.valida_email_existente()
if email_existente:
msg = _('Este email já foi cadastrado.')
raise ValidationError(msg)
if self.usuario_existente():
msg = _('Este nome de usuario já foi cadastrado.')
raise ValidationError(msg)
try:
validate_password(self.cleaned_data['senha'])
except ValidationError as error:
raise ValidationError(error)
return self.cleaned_data
@transaction.atomic
def save(self, commit=False):
autor = super(AutorForm, self).save(commit)
u = User.objects.get_or_create(
username=autor.username,
email=autor.email)
u = u[0]
u.set_password(self.cleaned_data['senha'])
u.is_active = False
u.save()
autor.user = u
autor.save()
grupo = Group.objects.filter(name='Autor')[0]
u.groups.add(grupo)
return autor

37
sapl/materia/migrations/0039_auto_20160628_1251.py

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-28 15:51
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import sapl.materia.models
class Migration(migrations.Migration):
dependencies = [
('auth', '0007_alter_validators_add_error_messages'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('materia', '0038_auto_20160612_1506'),
]
operations = [
migrations.AddField(
model_name='autor',
name='email',
field=models.EmailField(default=' ', max_length=254, verbose_name='Email'),
preserve_default=False,
),
migrations.AddField(
model_name='autor',
name='grupo_usuario',
field=models.ForeignKey(default=sapl.materia.models.grupo_autor, on_delete=django.db.models.deletion.CASCADE, to='auth.Group'),
),
migrations.AddField(
model_name='autor',
name='user',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
preserve_default=False,
),
]

6
sapl/protocoloadm/migrations/0013_merge.py → sapl/materia/migrations/0044_merge.py

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-05-19 17:03
# Generated by Django 1.9.7 on 2016-08-22 20:18
from __future__ import unicode_literals
from django.db import migrations
@ -8,8 +8,8 @@ from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0012_tipoinstituicao'),
('protocoloadm', '0012_auto_20160503_0926'),
('materia', '0039_auto_20160628_1251'),
('materia', '0043_auto_20160810_1738'),
]
operations = [

24
sapl/materia/migrations/0045_auto_20160823_1658.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-23 19:58
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('materia', '0044_merge'),
]
operations = [
migrations.RemoveField(
model_name='autor',
name='grupo_usuario',
),
migrations.AlterField(
model_name='autor',
name='username',
field=models.CharField(blank=True, max_length=50, verbose_name='Nome de Usuário'),
),
]

23
sapl/materia/models.py

@ -1,3 +1,4 @@
from django.contrib.auth.models import Group, User
from django.db import models
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
@ -8,6 +9,14 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
restringe_tipos_de_arquivo_txt, xstr)
def grupo_autor():
try:
grupo = Group.objects.get(name='Autor')
except Group.DoesNotExist:
return None
return grupo.id
class TipoMateriaLegislativa(models.Model):
sigla = models.CharField(max_length=5, verbose_name=_('Sigla'))
descricao = models.CharField(max_length=50, verbose_name=_('Descrição '))
@ -199,6 +208,7 @@ class TipoAutor(models.Model):
class Autor(models.Model):
user = models.ForeignKey(User)
partido = models.ForeignKey(Partido, blank=True, null=True)
comissao = models.ForeignKey(Comissao, blank=True, null=True)
parlamentar = models.ForeignKey(Parlamentar, blank=True, null=True)
@ -206,18 +216,23 @@ class Autor(models.Model):
nome = models.CharField(
max_length=50, blank=True, verbose_name=_('Autor'))
cargo = models.CharField(max_length=50, blank=True)
username = models.CharField(max_length=50, blank=True)
username = models.CharField(
max_length=50,
blank=True,
verbose_name=_('Nome de Usuário'))
email = models.EmailField(
verbose_name=_('Email'))
class Meta:
verbose_name = _('Autor')
verbose_name_plural = _('Autores')
def __str__(self):
if str(self.tipo) == 'Parlamentar':
if str(self.tipo) == 'Parlamentar' and self.parlamentar:
return self.parlamentar.nome_parlamentar
elif str(self.tipo) == 'Comissao':
elif str(self.tipo) == 'Comissao' and self.comissao:
return str(self.comissao)
elif str(self.tipo) == 'Partido':
elif str(self.tipo) == 'Partido' and self.partido:
return str(self.partido)
else:
if str(self.cargo):

149
sapl/materia/tests/test_materia.py

@ -1,12 +1,16 @@
import pytest
from django.contrib.auth.models import User
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.urlresolvers import reverse
from model_mommy import mommy
from model_mommy import mommy
from sapl.comissoes.models import Comissao, TipoComissao
from sapl.materia.models import (Anexada, Autor, Autoria, DespachoInicial,
DocumentoAcessorio, MateriaLegislativa,
Numeracao, RegimeTramitacao, StatusTramitacao,
TipoAutor, TipoDocumento,
Numeracao, Proposicao,
RegimeTramitacao, StatusTramitacao,
TipoAutor, TipoProposicao, TipoDocumento,
TipoMateriaLegislativa, Tramitacao,
UnidadeTramitacao)
from sapl.norma.models import (LegislacaoCitada, NormaJuridica,
@ -80,7 +84,7 @@ def make_materia_principal():
@pytest.mark.django_db(transaction=False)
def test_materia_anexada_submit(client):
def test_materia_anexada_submit(admin_client):
materia_principal = make_materia_principal()
# Cria a matéria que será anexada
@ -99,7 +103,7 @@ def test_materia_anexada_submit(client):
materia_anexada = MateriaLegislativa.objects.get(numero=32, ano=2004)
# Testa POST
response = client.post(reverse('sapl.materia:anexada_create',
response = admin_client.post(reverse('sapl.materia:anexada_create',
kwargs={'pk': materia_principal.pk}),
{'tipo': materia_anexada.tipo.pk,
'numero': materia_anexada.numero,
@ -116,17 +120,19 @@ def test_materia_anexada_submit(client):
@pytest.mark.django_db(transaction=False)
def test_autoria_submit(client):
def test_autoria_submit(admin_client):
materia_principal = make_materia_principal()
# Cria um tipo de Autor
tipo_autor = mommy.make(TipoAutor, descricao='Teste Tipo_Autor')
# Cria um Autor
autor = mommy.make(Autor, tipo=tipo_autor, nome='Autor Teste')
autor = mommy.make(
Autor,
tipo=tipo_autor,
nome='Autor Teste')
# Testa POST
response = client.post(reverse('sapl.materia:autoria_create',
response = admin_client.post(reverse('sapl.materia:autoria_create',
kwargs={'pk': materia_principal.pk}),
{'autor': autor.pk,
'primeiro_autor': True,
@ -144,7 +150,7 @@ def test_autoria_submit(client):
@pytest.mark.django_db(transaction=False)
def test_despacho_inicial_submit(client):
def test_despacho_inicial_submit(admin_client):
materia_principal = make_materia_principal()
# Cria uma comissão
@ -156,7 +162,7 @@ def test_despacho_inicial_submit(client):
data_criacao='2016-03-18')
# Testa POST
response = client.post(reverse('sapl.materia:despachoinicial_create',
response = admin_client.post(reverse('sapl.materia:despachoinicial_create',
kwargs={'pk': materia_principal.pk}),
{'comissao': comissao.pk,
'salvar': 'salvar'},
@ -170,12 +176,12 @@ def test_despacho_inicial_submit(client):
@pytest.mark.django_db(transaction=False)
def test_numeracao_submit(client):
def test_numeracao_submit(admin_client):
materia_principal = make_materia_principal()
materia = make_materia_principal()
# Testa POST
response = client.post(reverse('sapl.materia:numeracao_create',
response = admin_client.post(reverse('sapl.materia:numeracao_create',
kwargs={'pk': materia_principal.pk}),
{'tipo_materia': materia.tipo.pk,
'numero_materia': materia.numero,
@ -193,21 +199,25 @@ def test_numeracao_submit(client):
@pytest.mark.django_db(transaction=False)
def test_documento_acessorio_submit(client):
def test_documento_acessorio_submit(admin_client):
materia_principal = make_materia_principal()
# Cria um tipo de Autor
tipo_autor = mommy.make(TipoAutor, descricao='Teste Tipo_Autor')
# Cria um Autor
autor = mommy.make(Autor, tipo=tipo_autor, nome='Autor Teste')
autor = mommy.make(
Autor,
tipo=tipo_autor,
nome='Autor Teste')
# Cria um tipo de documento
tipo = mommy.make(TipoDocumento,
descricao='Teste')
# Testa POST
response = client.post(reverse('sapl.materia:documentoacessorio_create',
response = admin_client.post(reverse(
'sapl.materia:documentoacessorio_create',
kwargs={'pk': materia_principal.pk}),
{'tipo': tipo.pk,
'nome': 'teste_nome',
@ -227,12 +237,13 @@ def test_documento_acessorio_submit(client):
@pytest.mark.django_db(transaction=False)
def test_legislacao_citada_submit(client):
def test_legislacao_citada_submit(admin_client):
materia_principal = make_materia_principal()
norma = make_norma()
# Testa POST
response = client.post(reverse('sapl.materia:legislacaocitada_create',
response = admin_client.post(
reverse('sapl.materia:legislacaocitada_create',
kwargs={'pk': materia_principal.pk}),
{'tipo': norma.tipo.pk,
'numero': norma.numero,
@ -249,7 +260,7 @@ def test_legislacao_citada_submit(client):
@pytest.mark.django_db(transaction=False)
def test_tramitacao_submit(client):
def test_tramitacao_submit(admin_client):
materia_principal = make_materia_principal()
# Cria status para tramitação
status_tramitacao = mommy.make(StatusTramitacao,
@ -257,7 +268,7 @@ def test_tramitacao_submit(client):
sigla='ST',
descricao='Status_Teste')
# Testa POST
response = client.post(
response = admin_client.post(
reverse('sapl.materia:tramitacao_create',
kwargs={'pk': materia_principal.pk}),
{'unidade_tramitacao_local': make_unidade_tramitacao(
@ -283,9 +294,9 @@ def test_tramitacao_submit(client):
@pytest.mark.django_db(transaction=False)
def test_form_errors_anexada(client):
def test_form_errors_anexada(admin_client):
materia_principal = make_materia_principal()
response = client.post(reverse('sapl.materia:anexada_create',
response = admin_client.post(reverse('sapl.materia:anexada_create',
kwargs={'pk': materia_principal.pk}),
{'salvar': 'salvar'},
follow=True)
@ -301,10 +312,10 @@ def test_form_errors_anexada(client):
@pytest.mark.django_db(transaction=False)
def test_form_errors_autoria(client):
def test_form_errors_autoria(admin_client):
materia_principal = make_materia_principal()
response = client.post(reverse('sapl.materia:autoria_create',
response = admin_client.post(reverse('sapl.materia:autoria_create',
kwargs={'pk': materia_principal.pk}),
{'materia_id': materia_principal.pk,
'partido': '',
@ -317,10 +328,10 @@ def test_form_errors_autoria(client):
@pytest.mark.django_db(transaction=False)
def test_form_errors_despacho_inicial(client):
def test_form_errors_despacho_inicial(admin_client):
materia_principal = make_materia_principal()
response = client.post(reverse('sapl.materia:despachoinicial_create',
response = admin_client.post(reverse('sapl.materia:despachoinicial_create',
kwargs={'pk': materia_principal.pk}),
{'salvar': 'salvar'},
follow=True)
@ -330,10 +341,11 @@ def test_form_errors_despacho_inicial(client):
@pytest.mark.django_db(transaction=False)
def test_form_errors_documento_acessorio(client):
def test_form_errors_documento_acessorio(admin_client):
materia_principal = make_materia_principal()
response = client.post(reverse('sapl.materia:documentoacessorio_create',
response = admin_client.post(
reverse('sapl.materia:documentoacessorio_create',
kwargs={'pk': materia_principal.pk}),
{'salvar': 'salvar'},
follow=True)
@ -345,10 +357,11 @@ def test_form_errors_documento_acessorio(client):
@pytest.mark.django_db(transaction=False)
def test_form_errors_legislacao_citada(client):
def test_form_errors_legislacao_citada(admin_client):
materia_principal = make_materia_principal()
response = client.post(reverse('sapl.materia:legislacaocitada_create',
response = admin_client.post(
reverse('sapl.materia:legislacaocitada_create',
kwargs={'pk': materia_principal.pk}),
{'salvar': 'salvar'},
follow=True)
@ -362,10 +375,10 @@ def test_form_errors_legislacao_citada(client):
@pytest.mark.django_db(transaction=False)
def test_form_errors_numeracao(client):
def test_form_errors_numeracao(admin_client):
materia_principal = make_materia_principal()
response = client.post(reverse('sapl.materia:numeracao_create',
response = admin_client.post(reverse('sapl.materia:numeracao_create',
kwargs={'pk': materia_principal.pk}),
{'salvar': 'salvar'},
follow=True)
@ -381,10 +394,11 @@ def test_form_errors_numeracao(client):
@pytest.mark.django_db(transaction=False)
def test_form_errors_tramitacao(client):
def test_form_errors_tramitacao(admin_client):
materia_principal = make_materia_principal()
response = client.post(reverse('sapl.materia:tramitacao_create',
response = admin_client.post(
reverse('sapl.materia:tramitacao_create',
kwargs={'pk': materia_principal.pk}),
{'salvar': 'salvar'},
follow=True)
@ -402,10 +416,11 @@ def test_form_errors_tramitacao(client):
@pytest.mark.django_db(transaction=False)
def test_form_errors_relatoria(client):
def test_form_errors_relatoria(admin_client):
materia_principal = make_materia_principal()
response = client.post(reverse('sapl.materia:relatoria_create',
response = admin_client.post(
reverse('sapl.materia:relatoria_create',
kwargs={'pk': materia_principal.pk}),
{'salvar': 'salvar'},
follow=True)
@ -414,3 +429,65 @@ def test_form_errors_relatoria(client):
['Este campo é obrigatório.'])
assert (response.context_data['form'].errors['parlamentar'] ==
['Este campo é obrigatório.'])
@pytest.mark.django_db(transaction=False)
def test_proposicao_submit(admin_client):
tipo_autor = mommy.make(TipoAutor, descricao='Teste Tipo_Autor')
user = User.objects.filter(is_active=True)[0]
autor = mommy.make(
Autor,
user=user,
tipo=tipo_autor,
nome='Autor Teste')
file_content = 'file_content'
texto = SimpleUploadedFile("file.txt", file_content.encode('UTF-8'))
response = admin_client.post(reverse('sapl.materia:proposicao_create'),
{'tipo': mommy.make(TipoProposicao, pk=3).pk,
'descricao': 'Teste proposição',
'justificativa_devolucao': ' ',
'status': 'E',
'autor': autor.pk,
'texto_original': texto,
'salvar': 'salvar',
},
follow=True)
assert response.status_code == 200
proposicao = Proposicao.objects.first()
assert proposicao is not None
assert proposicao.descricao == 'Teste proposição'
assert proposicao.tipo.pk == 3
@pytest.mark.django_db(transaction=False)
def test_form_errors_proposicao(admin_client):
tipo_autor = mommy.make(TipoAutor, descricao='Teste Tipo_Autor')
user = User.objects.filter(is_active=True)[0]
autor = mommy.make(
Autor,
user=user,
tipo=tipo_autor,
nome='Autor Teste')
file_content = 'file_content'
texto = SimpleUploadedFile("file.txt", file_content.encode('UTF-8'))
response = admin_client.post(reverse('sapl.materia:proposicao_create'),
{'autor': autor.pk,
'justificativa_devolucao': ' ',
'texto_original': texto,
'salvar': 'salvar'},
follow=True)
assert (response.context_data['form'].errors['tipo'] ==
['Este campo é obrigatório.'])
assert (response.context_data['form'].errors['descricao'] ==
['Este campo é obrigatório.'])

10
sapl/materia/urls.py

@ -3,9 +3,10 @@ from django.conf.urls import include, url
from sapl.materia.views import (AcompanhamentoConfirmarView,
AcompanhamentoExcluirView,
AcompanhamentoMateriaView, AnexadaCrud,
AutorCrud, AutoriaCrud, ConfirmarProposicao,
DespachoInicialCrud, DocumentoAcessorioCrud,
LegislacaoCitadaCrud, MateriaLegislativaCrud,
AutorCrud, AutoriaCrud, ConfirmarEmailView,
ConfirmarProposicao, DespachoInicialCrud,
DocumentoAcessorioCrud, LegislacaoCitadaCrud,
MateriaLegislativaCrud,
MateriaLegislativaPesquisaView, MateriaTaView,
NumeracaoCrud, OrgaoCrud, OrigemCrud,
ProposicaoCrud, ProposicaoDevolvida,
@ -33,6 +34,9 @@ urlpatterns = [
RelatoriaCrud.get_urls() +
DocumentoAcessorioCrud.get_urls())),
url(r'^confirmar/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$',
ConfirmarEmailView.as_view(), name='confirmar_email'),
url(r'^proposicao/', include(ProposicaoCrud.get_urls())),
url(r'^proposicao/recibo/(?P<pk>\d+)', ReciboProposicaoView.as_view(),
name='recibo-proposicao'),

343
sapl/materia/views.py

@ -4,28 +4,38 @@ from string import ascii_letters, digits
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.models import User
from django.contrib.auth.tokens import default_token_generator
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from django.http.response import HttpResponseRedirect
from django.shortcuts import redirect
from django.template import Context, loader
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
from django.utils.translation import ugettext_lazy as _
from django.views.generic import CreateView, ListView, TemplateView, UpdateView
from django.views.generic import (CreateView, DetailView, ListView,
TemplateView, UpdateView)
from django_filters.views import FilterView
from sapl.base.models import CasaLegislativa
from sapl.compilacao.views import IntegracaoTaView
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView, CrudListView,
from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView,
CrudDeleteView, CrudDetailView, CrudListView,
CrudUpdateView, make_pagination)
from sapl.crud.masterdetail import MasterDetailCrud
from sapl.norma.models import LegislacaoCitada
from sapl.utils import (autor_label, autor_modal, gerar_hash_arquivo,
get_base_url)
get_base_url, permissao_tb_aux, permissoes_autor,
permissoes_materia)
from .forms import (AcompanhamentoMateriaForm, AnexadaForm, AutoriaForm,
ConfirmarProposicaoForm, DespachoInicialForm,
from .forms import (AcompanhamentoMateriaForm, AnexadaForm, AutorForm,
AutoriaForm, ConfirmarProposicaoForm, DespachoInicialForm,
DocumentoAcessorioForm, LegislacaoCitadaForm,
MateriaLegislativaFilterSet, NumeracaoForm, ProposicaoForm,
ReceberProposicaoForm, RelatoriaForm, TramitacaoForm,
@ -39,18 +49,145 @@ from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria,
TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao,
Tramitacao, UnidadeTramitacao)
OrigemCrud = Crud.build(Origem, 'origem')
TipoMateriaCrud = Crud.build(TipoMateriaLegislativa,
'tipo_materia_legislativa')
RegimeTramitacaoCrud = Crud.build(RegimeTramitacao, 'regime_tramitacao')
TipoDocumentoCrud = Crud.build(TipoDocumento, 'tipo_documento')
TipoFimRelatoriaCrud = Crud.build(TipoFimRelatoria, 'fim_relatoria')
AnexadaCrud = Crud.build(Anexada, '')
TipoAutorCrud = Crud.build(TipoAutor, 'tipo_autor')
AutorCrud = Crud.build(Autor, 'autor')
OrgaoCrud = Crud.build(Orgao, 'orgao')
TipoProposicaoCrud = Crud.build(TipoProposicao, 'tipo_proposicao')
StatusTramitacaoCrud = Crud.build(StatusTramitacao, 'status_tramitacao')
class OrigemCrud(Crud):
model = Origem
help_path = 'origem'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class TipoMateriaCrud(Crud):
model = TipoMateriaLegislativa
help_path = 'tipo_materia_legislativa'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class RegimeTramitacaoCrud(Crud):
model = RegimeTramitacao
help_path = 'regime_tramitacao'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class TipoDocumentoCrud(Crud):
model = TipoDocumento
help_path = 'tipo_documento'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class TipoFimRelatoriaCrud(Crud):
model = TipoFimRelatoria
help_path = 'fim_relatoria'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class TipoAutorCrud(Crud):
model = TipoAutor
help_path = 'tipo_autor'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class AutorCrud(Crud):
model = Autor
help_path = 'autor'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
list_field_names = ['tipo', 'nome',
'username', 'cargo']
def has_permission(self):
return permissao_tb_aux(self)
class CreateView(CrudCreateView):
form_class = AutorForm
layout_key = 'AutorCreate'
def get_success_url(self):
pk_autor = Autor.objects.get(
email=self.request.POST.get('email')).id
kwargs = {}
user = User.objects.get(email=self.request.POST.get('email'))
kwargs['token'] = default_token_generator.make_token(user)
kwargs['uidb64'] = urlsafe_base64_encode(force_bytes(user.pk))
assunto = "SAPL - Confirmação de Conta"
full_url = self.request.get_raw_uri()
url_base = full_url[:full_url.find('sistema') - 1]
mensagem = ("Este e-mail foi utilizado para fazer cadastro no " +
"SAPL com o perfil de Autor. Agora você pode " +
"criar/editar/enviar Proposições.\n" +
"Seu nome de usuário é: " +
self.request.POST['username'] + "\n"
"Caso você não tenha feito este cadastro, por favor " +
"ignore esta mensagem. Caso tenha, clique " +
"no link abaixo\n" + url_base +
reverse('sapl.materia:confirmar_email', kwargs=kwargs))
remetente = settings.EMAIL_SEND_USER
destinatario = [self.request.POST.get('email')]
send_mail(assunto, mensagem, remetente, destinatario,
fail_silently=False)
return reverse('sapl.materia:autor_detail',
kwargs={'pk': pk_autor})
class ConfirmarEmailView(TemplateView):
template_name = "confirma_email.html"
def get(self, request, *args, **kwargs):
uid = urlsafe_base64_decode(self.kwargs['uidb64'])
user = User.objects.get(id=uid)
user.is_active = True
user.save()
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
class OrgaoCrud(Crud):
model = Orgao
help_path = 'orgao'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class TipoProposicaoCrud(Crud):
model = TipoProposicao
help_path = 'tipo_proposicao'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class StatusTramitacaoCrud(Crud):
model = StatusTramitacao
help_path = 'status_tramitacao'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
def criar_materia_proposicao(proposicao):
@ -94,12 +231,17 @@ class UnidadeTramitacaoCrud(Crud):
model = UnidadeTramitacao
help_path = 'unidade_tramitacao'
class CreateView(CrudCreateView):
class CreateView(PermissionRequiredMixin, CrudCreateView):
permission_required = permissoes_materia()
form_class = UnidadeTramitacaoForm
class UpdateView(CrudUpdateView):
class UpdateView(PermissionRequiredMixin, CrudUpdateView):
permission_required = permissoes_materia()
form_class = UnidadeTramitacaoForm
class DeleteView(PermissionRequiredMixin, CrudDeleteView):
permission_required = permissoes_materia()
class ProposicaoDevolvida(ListView):
template_name = 'materia/prop_devolvidas_list.html'
@ -245,18 +387,57 @@ class ProposicaoCrud(Crud):
list_field_names = ['data_envio', 'descricao',
'tipo', 'data_recebimento']
class CreateView(CrudCreateView):
class CreateView(PermissionRequiredMixin, CrudCreateView):
form_class = ProposicaoForm
permission_required = {'materia.add_proposicao'}
@property
def layout_key(self):
return 'ProposicaoCreate'
class UpdateView(CrudUpdateView):
def get_initial(self):
try:
autor_id = Autor.objects.get(user=self.request.user.id).id
except MultipleObjectsReturned:
msg = _('Este usuário está relacionado a mais de um autor. ' +
'Operação cancelada')
messages.add_message(self.request, messages.ERROR, msg)
return redirect(self.get_success_url())
else:
return {'autor': autor_id}
class UpdateView(PermissionRequiredMixin, CrudUpdateView):
form_class = ProposicaoForm
permission_required = permissoes_autor()
@property
def layout_key(self):
return 'ProposicaoCreate'
def has_permission(self):
perms = self.get_permission_required()
if self.request.user.has_perms(perms):
if (Proposicao.objects.filter(
id=self.kwargs['pk'],
autor__user_id=self.request.user.id).exists()):
proposicao = Proposicao.objects.get(
id=self.kwargs['pk'],
autor__user_id=self.request.user.id)
if not proposicao.data_recebimento:
return True
else:
msg = _('Essa proposição já foi recebida. ' +
'Não pode mais ser editada')
messages.add_message(self.request, messages.ERROR, msg)
return False
else:
return False
class DetailView(PermissionRequiredMixin, CrudDetailView):
permission_required = permissoes_autor()
def get_context_data(self, **kwargs):
context = super(UpdateView, self).get_context_data(**kwargs)
context = super(DetailView, self).get_context_data(**kwargs)
if self.object.materia:
context['form'].fields['tipo_materia'].initial = (
self.object.materia.tipo.id)
@ -270,8 +451,21 @@ class ProposicaoCrud(Crud):
def layout_key(self):
return 'ProposicaoCreate'
class ListView(CrudListView):
ordering = ['-data_envio', '-descricao']
def has_permission(self):
perms = self.get_permission_required()
if self.request.user.has_perms(perms):
if (Proposicao.objects.filter(
id=self.kwargs['pk'],
autor__user_id=self.request.user.id).exists()):
return True
else:
return False
else:
return False
class ListView(PermissionRequiredMixin, CrudListView):
ordering = ['-data_envio', 'descricao']
permission_required = permissoes_autor()
def get_rows(self, object_list):
@ -288,7 +482,13 @@ class ProposicaoCrud(Crud):
return [self._as_row(obj) for obj in object_list]
class DeleteView(MasterDetailCrud.DeleteView):
def get_queryset(self):
lista = Proposicao.objects.filter(
autor__user_id=self.request.user.id)
return lista
class DeleteView(PermissionRequiredMixin, CrudDeleteView):
permission_required = permissoes_materia()
def delete(self, request, *args, **kwargs):
proposicao = Proposicao.objects.get(id=self.kwargs['pk'])
@ -324,7 +524,8 @@ class RelatoriaCrud(MasterDetailCrud):
parent_field = 'materia'
help_path = ''
class CreateView(MasterDetailCrud.CreateView):
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
permission_required = permissoes_materia()
form_class = RelatoriaForm
def get_initial(self):
@ -344,9 +545,13 @@ class RelatoriaCrud(MasterDetailCrud):
return {'comissao': localizacao}
class UpdateView(MasterDetailCrud.UpdateView):
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
permission_required = permissoes_materia()
form_class = RelatoriaForm
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_materia()
class TramitacaoCrud(MasterDetailCrud):
model = Tramitacao
@ -357,16 +562,18 @@ class TramitacaoCrud(MasterDetailCrud):
list_field_names = ['data_tramitacao', 'unidade_tramitacao_local',
'unidade_tramitacao_destino', 'status']
class CreateView(MasterDetailCrud.CreateView):
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
form_class = TramitacaoForm
permission_required = permissoes_materia()
def post(self, request, *args, **kwargs):
materia = MateriaLegislativa.objects.get(id=kwargs['pk'])
do_envia_email_tramitacao(request, materia)
return super(CreateView, self).post(request, *args, **kwargs)
class UpdateView(MasterDetailCrud.UpdateView):
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
form_class = TramitacaoForm
permission_required = permissoes_materia()
def post(self, request, *args, **kwargs):
materia = MateriaLegislativa.objects.get(id=kwargs['pk'])
@ -380,7 +587,8 @@ class TramitacaoCrud(MasterDetailCrud):
kwargs = {self.crud.parent_field: self.kwargs['pk']}
return qs.filter(**kwargs).order_by('-data_tramitacao')
class DeleteView(MasterDetailCrud.DeleteView):
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_materia()
def delete(self, request, *args, **kwargs):
tramitacao = Tramitacao.objects.get(id=self.kwargs['pk'])
@ -437,8 +645,9 @@ class DocumentoAcessorioCrud(MasterDetailCrud):
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['nome', 'tipo', 'data', 'autor', 'arquivo']
class CreateView(MasterDetailCrud.CreateView):
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
form_class = DocumentoAcessorioForm
permission_required = permissoes_materia()
def __init__(self, *args, **kwargs):
montar_helper_documento_acessorio(self)
@ -449,8 +658,9 @@ class DocumentoAcessorioCrud(MasterDetailCrud):
context['helper'] = self.helper
return context
class UpdateView(MasterDetailCrud.UpdateView):
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
form_class = DocumentoAcessorioForm
permission_required = permissoes_materia()
def __init__(self, *args, **kwargs):
montar_helper_documento_acessorio(self)
@ -461,17 +671,25 @@ class DocumentoAcessorioCrud(MasterDetailCrud):
context['helper'] = self.helper
return context
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_materia()
class AutoriaCrud(MasterDetailCrud):
model = Autoria
parent_field = 'materia'
help_path = ''
class CreateView(MasterDetailCrud.CreateView):
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
form_class = AutoriaForm
permission_required = permissoes_materia()
class UpdateView(MasterDetailCrud.UpdateView):
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
form_class = AutoriaForm
permission_required = permissoes_materia()
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_materia()
class DespachoInicialCrud(MasterDetailCrud):
@ -479,11 +697,16 @@ class DespachoInicialCrud(MasterDetailCrud):
parent_field = 'materia'
help_path = ''
class CreateView(MasterDetailCrud.CreateView):
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
form_class = DespachoInicialForm
permission_required = permissoes_materia()
class UpdateView(MasterDetailCrud.UpdateView):
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
form_class = DespachoInicialForm
permission_required = permissoes_materia()
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_materia()
class LegislacaoCitadaCrud(MasterDetailCrud):
@ -499,11 +722,13 @@ class LegislacaoCitadaCrud(MasterDetailCrud):
return reverse('%s:%s' % (namespace, self.url_name(suffix)),
args=args)
class CreateView(MasterDetailCrud.CreateView):
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
form_class = LegislacaoCitadaForm
permission_required = permissoes_materia()
class UpdateView(MasterDetailCrud.UpdateView):
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
form_class = LegislacaoCitadaForm
permission_required = permissoes_materia()
def get_initial(self):
self.initial['tipo'] = self.object.norma.tipo.id
@ -511,6 +736,9 @@ class LegislacaoCitadaCrud(MasterDetailCrud):
self.initial['ano'] = self.object.norma.ano
return self.initial
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_materia()
class DetailView(MasterDetailCrud.DetailView):
@property
@ -523,11 +751,16 @@ class NumeracaoCrud(MasterDetailCrud):
parent_field = 'materia'
help_path = ''
class CreateView(MasterDetailCrud.CreateView):
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
form_class = NumeracaoForm
permission_required = permissoes_materia()
class UpdateView(MasterDetailCrud.UpdateView):
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
form_class = NumeracaoForm
permission_required = permissoes_materia()
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_materia()
class AnexadaCrud(MasterDetailCrud):
@ -538,11 +771,13 @@ class AnexadaCrud(MasterDetailCrud):
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['materia_anexada', 'data_anexacao']
class CreateView(MasterDetailCrud.CreateView):
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
form_class = AnexadaForm
permission_required = permissoes_materia()
class UpdateView(MasterDetailCrud.UpdateView):
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
form_class = AnexadaForm
permission_required = permissoes_materia()
def get_initial(self):
self.initial['tipo'] = self.object.materia_anexada.tipo.id
@ -557,6 +792,9 @@ class AnexadaCrud(MasterDetailCrud):
def layout_key(self):
return 'AnexadaDetail'
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_materia()
class MateriaLegislativaCrud(Crud):
model = MateriaLegislativa
@ -565,10 +803,20 @@ class MateriaLegislativaCrud(Crud):
class BaseMixin(CrudBaseMixin):
list_field_names = ['tipo', 'numero', 'ano', 'data_apresentacao']
class CreateView(PermissionRequiredMixin, CrudCreateView):
permission_required = permissoes_materia()
class UpdateView(PermissionRequiredMixin, CrudUpdateView):
permission_required = permissoes_materia()
class DeleteView(PermissionRequiredMixin, CrudDeleteView):
permission_required = permissoes_materia()
class DocumentoAcessorioView(CreateView):
class DocumentoAcessorioView(PermissionRequiredMixin, CreateView):
template_name = "materia/documento_acessorio.html"
form_class = DocumentoAcessorioForm
permission_required = permissoes_materia()
def get(self, request, *args, **kwargs):
materia = MateriaLegislativa.objects.get(id=kwargs['pk'])
@ -602,7 +850,8 @@ class DocumentoAcessorioView(CreateView):
return reverse('sapl.materia:documento_acessorio', kwargs={'pk': pk})
class AcompanhamentoConfirmarView(TemplateView):
class AcompanhamentoConfirmarView(PermissionRequiredMixin, TemplateView):
permission_required = permissoes_materia()
def get_redirect_url(self):
return reverse('sapl.sessao:list_pauta_sessao')
@ -619,7 +868,8 @@ class AcompanhamentoConfirmarView(TemplateView):
return HttpResponseRedirect(self.get_redirect_url())
class AcompanhamentoExcluirView(TemplateView):
class AcompanhamentoExcluirView(PermissionRequiredMixin, TemplateView):
permission_required = permissoes_materia()
def get_redirect_url(self):
return reverse('sapl.sessao:list_pauta_sessao')
@ -703,8 +953,9 @@ class ProposicaoTaView(IntegracaoTaView):
model_type_foreignkey = TipoProposicao
class AcompanhamentoMateriaView(CreateView):
class AcompanhamentoMateriaView(PermissionRequiredMixin, CreateView):
template_name = "materia/acompanhamento_materia.html"
permission_required = permissoes_materia()
def get_random_chars(self):
s = ascii_letters + digits

8
sapl/norma/tests/test_norma.py

@ -6,14 +6,14 @@ from sapl.norma.models import NormaJuridica, TipoNormaJuridica
@pytest.mark.django_db(transaction=False)
def test_incluir_norma_submit(client):
def test_incluir_norma_submit(admin_client):
# Cria um tipo de norma
tipo = mommy.make(TipoNormaJuridica,
sigla='T',
descricao='Teste')
# Testa POST
response = client.post(reverse('sapl.norma:normajuridica_create'),
response = admin_client.post(reverse('sapl.norma:normajuridica_create'),
{'tipo': tipo.pk,
'numero': '1',
'ano': '2016',
@ -31,9 +31,9 @@ def test_incluir_norma_submit(client):
@pytest.mark.django_db(transaction=False)
def test_incluir_norma_errors(client):
def test_incluir_norma_errors(admin_client):
response = client.post(reverse('sapl.norma:normajuridica_create'),
response = admin_client.post(reverse('sapl.norma:normajuridica_create'),
{'salvar': 'salvar'},
follow=True)

33
sapl/norma/views.py

@ -1,27 +1,46 @@
from datetime import datetime
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.shortcuts import redirect
from django.views.generic import FormView, ListView
from sapl.compilacao.views import IntegracaoTaView
from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView,
CrudUpdateView, make_pagination)
CrudDeleteView, CrudUpdateView, make_pagination)
from sapl.utils import permissoes_norma
from .forms import NormaJuridicaForm, NormaJuridicaPesquisaForm
from .models import (AssuntoNorma, LegislacaoCitada, NormaJuridica,
TipoNormaJuridica)
AssuntoNormaCrud = Crud.build(AssuntoNorma, 'assunto_norma_juridica')
TipoNormaCrud = Crud.build(TipoNormaJuridica, 'tipo_norma_juridica')
LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '')
class AssuntoNormaCrud(Crud):
model = AssuntoNorma
help_path = 'assunto_norma_juridica'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
permission_required = permissoes_norma()
list_field_names = ['assunto', 'descricao']
class TipoNormaCrud(Crud):
model = TipoNormaJuridica
help_path = 'tipo_norma_juridica'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
permission_required = permissoes_norma()
list_field_names = ['equivalente_lexml', 'sigla', 'descricao']
class NormaCrud(Crud):
model = NormaJuridica
help_path = 'norma_juridica'
class UpdateView(CrudUpdateView):
class UpdateView(PermissionRequiredMixin, CrudUpdateView):
form_class = NormaJuridicaForm
permission_required = permissoes_norma()
@property
def layout_key(self):
@ -35,13 +54,17 @@ class NormaCrud(Crud):
self.initial['numero_materia'] = norma.materia.numero
return self.initial.copy()
class CreateView(CrudCreateView):
class CreateView(PermissionRequiredMixin, CrudCreateView):
form_class = NormaJuridicaForm
permission_required = permissoes_norma()
@property
def layout_key(self):
return 'NormaJuridicaCreate'
class DeleteView(PermissionRequiredMixin, CrudDeleteView):
permission_required = permissoes_norma()
class BaseMixin(CrudBaseMixin):
list_field_names = ['tipo', 'numero', 'ano', 'ementa']

13
sapl/painel/views.py

@ -1,5 +1,6 @@
from datetime import date
from django.contrib.auth.decorators import user_passes_test
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render
@ -11,12 +12,18 @@ from sapl.parlamentares.models import Filiacao
from sapl.sessao.models import (ExpedienteMateria, OrdemDia, PresencaOrdemDia,
RegistroVotacao, SessaoPlenaria,
SessaoPlenariaPresenca, VotoParlamentar)
from sapl.utils import permissoes_painel
from .models import Cronometro
CronometroPainelCrud = Crud.build(Cronometro, '')
def check_permission(user):
return user.has_perms(permissoes_painel())
@user_passes_test(check_permission)
def controlador_painel(request):
painel_created = Painel.objects.get_or_create(data_painel=date.today())
@ -37,23 +44,28 @@ def controlador_painel(request):
return render(request, 'painel/controlador.html', context)
@user_passes_test(check_permission)
def painel_view(request, pk):
context = {'head_title': str(_('Painel Plenário')), 'sessao_id': pk}
return render(request, 'painel/index.html', context)
@user_passes_test(check_permission)
def painel_mensagem_view(request):
return render(request, 'painel/mensagem.html')
@user_passes_test(check_permission)
def painel_parlamentar_view(request):
return render(request, 'painel/parlamentares.html')
@user_passes_test(check_permission)
def painel_votacao_view(request):
return render(request, 'painel/votacao.html')
@user_passes_test(check_permission)
def cronometro_painel(request):
request.session[request.GET['tipo']] = request.GET['action']
return HttpResponse({})
@ -320,6 +332,7 @@ def get_votos_nominal(response, materia):
return response
@user_passes_test(check_permission)
def get_dados_painel(request, pk):
sessao = SessaoPlenaria.objects.get(id=pk)
cronometro_discurso = get_cronometro_status(request, 'discurso')

6
sapl/parlamentares/forms.py

@ -29,9 +29,9 @@ class LegislaturaForm(ModelForm):
data_eleicao = cleaned_data['data_eleicao']
if data_inicio >= data_fim or data_eleicao >= data_inicio:
raise ValidationError(_('A data início deve ser menor que a data \
fim, e a data eleição deve ser menor que\
a data início'))
raise ValidationError(_('A data início deve ser menor que a ' +
'data fim, e a data eleição deve ser ' +
'menor que a data início'))
return cleaned_data

22
sapl/parlamentares/migrations/0022_auto_20160624_1124.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-24 14:24
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import sapl.parlamentares.models
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0021_merge'),
]
operations = [
migrations.AlterField(
model_name='sessaolegislativa',
name='legislatura',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='parlamentares.Legislatura', verbose_name=sapl.parlamentares.models.Legislatura),
),
]

21
sapl/parlamentares/migrations/0022_auto_20160702_1519.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-07-02 18:19
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0021_merge'),
]
operations = [
migrations.AlterField(
model_name='sessaolegislativa',
name='legislatura',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='parlamentares.Legislatura', verbose_name='Legislatura'),
),
]

21
sapl/parlamentares/migrations/0023_auto_20160628_1247.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-28 15:47
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0022_auto_20160624_1124'),
]
operations = [
migrations.AlterField(
model_name='sessaolegislativa',
name='legislatura',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='parlamentares.Legislatura', verbose_name='Legislatura'),
),
]

16
sapl/parlamentares/migrations/0024_merge.py

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-18 21:39
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0022_auto_20160702_1519'),
('parlamentares', '0023_auto_20160628_1247'),
]
operations = [
]

4
sapl/parlamentares/models.py

@ -40,7 +40,9 @@ class SessaoLegislativa(models.Model):
('E', 'extraordinaria', _('Extraordinária')),
)
legislatura = models.ForeignKey(Legislatura)
legislatura = models.ForeignKey(
Legislatura,
verbose_name=Legislatura._meta.verbose_name)
numero = models.PositiveIntegerField(verbose_name=_('Número'))
tipo = models.CharField(
max_length=1, verbose_name=_('Tipo'), choices=TIPO_SESSAO_CHOICES)

35
sapl/parlamentares/tests/test_parlamentares.py

@ -8,14 +8,14 @@ from sapl.parlamentares.models import (Dependente, Filiacao, Legislatura,
@pytest.mark.django_db(transaction=False)
def test_cadastro_parlamentar(client):
def test_cadastro_parlamentar(admin_client):
legislatura = mommy.make(Legislatura)
url = reverse('sapl.parlamentares:parlamentar_create')
response = client.get(url)
response = admin_client.get(url)
assert response.status_code == 200
response = client.post(url, {'nome_completo': 'Teresa Barbosa',
response = admin_client.post(url, {'nome_completo': 'Teresa Barbosa',
'nome_parlamentar': 'Terezinha',
'sexo': 'F',
'ativo': 'True',
@ -36,9 +36,9 @@ def test_cadastro_parlamentar(client):
@pytest.mark.django_db(transaction=False)
def test_incluir_parlamentar_errors(client):
def test_incluir_parlamentar_errors(admin_client):
url = reverse('sapl.parlamentares:parlamentar_create')
response = client.post(url)
response = admin_client.post(url)
erros_esperados = {campo: ['Este campo é obrigatório.']
for campo in ['legislatura',
'data_expedicao_diploma',
@ -50,11 +50,11 @@ def test_incluir_parlamentar_errors(client):
@pytest.mark.django_db(transaction=False)
def test_filiacao_submit(client):
def test_filiacao_submit(admin_client):
mommy.make(Parlamentar, pk=14)
mommy.make(Partido, pk=32)
client.post(reverse('sapl.parlamentares:filiacao_create',
admin_client.post(reverse('sapl.parlamentares:filiacao_create',
kwargs={'pk': 14}),
{'partido': 32,
'data': '2016-03-22',
@ -66,12 +66,12 @@ def test_filiacao_submit(client):
@pytest.mark.django_db(transaction=False)
def test_dependente_submit(client):
def test_dependente_submit(admin_client):
mommy.make(Parlamentar, pk=14)
mommy.make(Partido, pk=32)
mommy.make(TipoDependente, pk=3)
client.post(reverse('sapl.parlamentares:dependente_create',
admin_client.post(reverse('sapl.parlamentares:dependente_create',
kwargs={'pk': 14}),
{'nome': 'Eduardo',
'tipo': 3,
@ -85,9 +85,10 @@ def test_dependente_submit(client):
@pytest.mark.django_db(transaction=False)
def test_form_errors_dependente(client):
def test_form_errors_dependente(admin_client):
mommy.make(Parlamentar, pk=14)
response = client.post(reverse('sapl.parlamentares:dependente_create',
response = admin_client.post(
reverse('sapl.parlamentares:dependente_create',
kwargs={'pk': 14}),
{'salvar': 'salvar'},
follow=True)
@ -101,10 +102,10 @@ def test_form_errors_dependente(client):
@pytest.mark.django_db(transaction=False)
def test_form_errors_filiacao(client):
def test_form_errors_filiacao(admin_client):
mommy.make(Parlamentar, pk=14)
response = client.post(reverse('sapl.parlamentares:filiacao_create',
response = admin_client.post(reverse('sapl.parlamentares:filiacao_create',
kwargs={'pk': 14}),
{'partido': '',
'salvar': 'salvar'},
@ -117,11 +118,11 @@ def test_form_errors_filiacao(client):
@pytest.mark.django_db(transaction=False)
def test_mandato_submit(client):
def test_mandato_submit(admin_client):
mommy.make(Parlamentar, pk=14)
mommy.make(Legislatura, pk=5)
client.post(reverse('sapl.parlamentares:mandato_create',
admin_client.post(reverse('sapl.parlamentares:mandato_create',
kwargs={'pk': 14}),
{'legislatura': 5,
'data_fim_mandato': '2016-01-01',
@ -135,9 +136,9 @@ def test_mandato_submit(client):
@pytest.mark.django_db(transaction=False)
def test_form_errors_mandato(client):
def test_form_errors_mandato(admin_client):
mommy.make(Parlamentar, pk=14)
response = client.post(reverse('sapl.parlamentares:mandato_create',
response = admin_client.post(reverse('sapl.parlamentares:mandato_create',
kwargs={'pk': 14}),
{'legislatura': '',
'salvar': 'salvar'},

189
sapl/parlamentares/views.py

@ -1,13 +1,19 @@
from django.contrib import messages
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import redirect
from django.utils.datastructures import MultiValueDictKeyError
from django.utils.translation import ugettext_lazy as _
from django.views.generic import FormView
from sapl.crud.base import Crud, CrudCreateView, CrudListView, CrudUpdateView
from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView,
CrudDeleteView, CrudDetailView,
CrudListView, CrudUpdateView)
from sapl.crud.masterdetail import MasterDetailCrud
from sapl.utils import permissao_tb_aux, permissoes_parlamentares
from .forms import (ComposicaoColigacaoForm, FiliacaoForm, LegislaturaForm,
ParlamentarCreateForm, ParlamentarForm)
@ -16,15 +22,89 @@ from .models import (CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa,
NivelInstrucao, Parlamentar, Partido, SessaoLegislativa,
SituacaoMilitar, TipoAfastamento, TipoDependente)
CargoMesaCrud = Crud.build(CargoMesa, 'cargo_mesa')
PartidoCrud = Crud.build(Partido, 'partidos')
SessaoLegislativaCrud = Crud.build(SessaoLegislativa, 'sessao_legislativa')
TipoDependenteCrud = Crud.build(TipoDependente, 'tipo_dependente')
NivelInstrucaoCrud = Crud.build(NivelInstrucao, 'nivel_instrucao')
TipoAfastamentoCrud = Crud.build(TipoAfastamento, 'tipo_afastamento')
TipoMilitarCrud = Crud.build(SituacaoMilitar, 'tipo_situa_militar')
DependenteCrud = MasterDetailCrud.build(Dependente, 'parlamentar', '')
class CargoMesaCrud(Crud):
model = CargoMesa
help_path = 'cargo_mesa'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class PartidoCrud(Crud):
model = Partido
help_path = 'partidos'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class SessaoLegislativaCrud(Crud):
model = SessaoLegislativa
help_path = 'sessao_legislativa'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class TipoDependenteCrud(Crud):
model = TipoDependente
help_path = 'nivel_instrucao'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class NivelInstrucaoCrud(Crud):
model = NivelInstrucao
help_path = 'tipo_dependente'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class TipoAfastamentoCrud(Crud):
model = TipoAfastamento
help_path = 'tipo_afastamento'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class TipoMilitarCrud(Crud):
model = SituacaoMilitar
help_path = 'tipo_situa_militar'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class DependenteCrud(MasterDetailCrud):
model = Dependente
parent_field = 'parlamentar'
help_path = ''
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
permission_required = permissoes_parlamentares()
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
permission_required = permissoes_parlamentares()
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_parlamentares()
class ListView(PermissionRequiredMixin, MasterDetailCrud.ListView):
permission_required = permissoes_parlamentares()
class DetailView(PermissionRequiredMixin, MasterDetailCrud.DetailView):
permission_required = permissoes_parlamentares()
class MandatoCrud(MasterDetailCrud):
@ -35,6 +115,15 @@ class MandatoCrud(MasterDetailCrud):
class ListView(MasterDetailCrud.ListView):
ordering = ('-legislatura__data_inicio')
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
permission_required = permissoes_parlamentares()
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
permission_required = permissoes_parlamentares()
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_parlamentares()
class ColigacaoCrud(Crud):
model = Coligacao
@ -43,6 +132,10 @@ class ColigacaoCrud(Crud):
class ListView(CrudListView):
ordering = ('-legislatura__data_inicio', 'nome')
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class ComposicaoColigacaoCrud(MasterDetailCrud):
model = ComposicaoColigacao
@ -66,6 +159,10 @@ class ComposicaoColigacaoCrud(MasterDetailCrud):
class ListView(MasterDetailCrud.ListView):
ordering = '-partido__sigla'
class BaseMixin(PermissionRequiredMixin, MasterDetailCrud.BaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class LegislaturaCrud(Crud):
model = Legislatura
@ -77,36 +174,72 @@ class LegislaturaCrud(Crud):
class UpdateView(CrudUpdateView):
form_class = LegislaturaForm
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class FiliacaoCrud(MasterDetailCrud):
model = Filiacao
parent_field = 'parlamentar'
help_path = ''
class CreateView(MasterDetailCrud.CreateView):
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
form_class = FiliacaoForm
permission_required = permissoes_parlamentares()
class UpdateView(MasterDetailCrud.UpdateView):
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
form_class = FiliacaoForm
permission_required = permissoes_parlamentares()
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_parlamentares()
class ListView(MasterDetailCrud.ListView):
ordering = '-data'
def get_parlamentar_permissions():
lista_permissoes = []
cts = ContentType.objects.filter(app_label='parlamentares')
perms_parlamentares = list(Permission.objects.filter(
content_type__in=cts))
for p in perms_parlamentares:
lista_permissoes.append('parlamentares.' + p.codename)
return set(lista_permissoes)
class ParlamentarCrud(Crud):
model = Parlamentar
help_path = ''
class UpdateView(CrudUpdateView):
class DetailView(CrudDetailView):
def get_template_names(self):
usuario = self.request.user
lista_permissoes = get_parlamentar_permissions()
if usuario.has_perms(lista_permissoes):
return ['crud/detail.html']
else:
return ['parlamentares/parlamentar_perfil_publico.html']
class UpdateView(PermissionRequiredMixin, CrudUpdateView):
form_class = ParlamentarForm
permission_required = permissoes_parlamentares()
class CreateView(CrudCreateView):
class CreateView(PermissionRequiredMixin, CrudCreateView):
form_class = ParlamentarCreateForm
permission_required = permissoes_parlamentares()
@property
def layout_key(self):
return 'ParlamentarCreate'
class DeleteView(PermissionRequiredMixin, CrudDeleteView):
form_class = ParlamentarCreateForm
permission_required = permissoes_parlamentares()
class ListView(CrudListView):
template_name = "parlamentares/parlamentares_list.html"
paginate_by = None
@ -142,6 +275,9 @@ class ParlamentarCrud(Crud):
partido = _('Sem Partido')
parlamentar = [
("<img src=" + m.parlamentar.fotografia.url + " \
height='42' width='42' />" if m.parlamentar.fotografia
else '', ''),
(m.parlamentar.nome_parlamentar, m.parlamentar.id),
(partido, None),
('Sim' if m.parlamentar.ativo else 'Não', None)
@ -150,7 +286,7 @@ class ParlamentarCrud(Crud):
return parlamentares
def get_headers(self):
return ['Parlamentar', 'Partido', 'Ativo?']
return ['', 'Parlamentar', 'Partido', 'Ativo?']
def get_context_data(self, **kwargs):
context = super(ParlamentarCrud.ListView, self
@ -165,15 +301,26 @@ class ParlamentarCrud(Crud):
return context
def check_permission_mesa(request):
lista_permissoes = []
cts = ContentType.objects.filter(app_label='parlamentares')
cts = cts.filter(model__icontains='mesa')
perms = list(Permission.objects.filter(content_type__in=cts))
for p in perms:
lista_permissoes.append('parlamentares.' + p.codename)
return request.user.has_perms(set(lista_permissoes))
class MesaDiretoraView(FormView):
template_name = "mesa_diretora/mesa_diretora.html"
success_url = reverse_lazy('sapl.parlamentares:mesa_diretora')
# Essa função avisa quando se pode compor uma Mesa Legislativa)
# Essa função avisa quando se pode compor uma Mesa Legislativa
def validation(self, request):
mensagem = _("Não há nenhuma Sessão Legislativa cadastrada. \
é possível compor uma Mesa Diretora quando 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.')
messages.add_message(request, messages.INFO, mensagem)
return self.render_to_response(
@ -217,7 +364,7 @@ class MesaDiretoraView(FormView):
})
def post(self, request, *args, **kwargs):
if 'Incluir' in request.POST:
if 'Incluir' in request.POST and check_permission_mesa(request):
if (not Legislatura.objects.all() or
not SessaoLegislativa.objects.all()):
@ -234,7 +381,7 @@ class MesaDiretoraView(FormView):
return redirect('sapl.parlamentares:mesa_diretora')
elif 'Excluir' in request.POST:
elif 'Excluir' in request.POST and check_permission_mesa(request):
if (not Legislatura.objects.all() or
not SessaoLegislativa.objects.all()):

87
sapl/protocoloadm/forms.py

@ -1,16 +1,18 @@
from datetime import datetime
import django_filters
from crispy_forms.bootstrap import InlineRadios
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Field, Fieldset, Layout, Submit
from crispy_forms.layout import HTML, Button, Fieldset, Layout, Submit
from django import forms
from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models
from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _
from sapl.crispy_layout_mixin import form_actions, to_row
from sapl.materia.forms import RangeWidgetOverride
from sapl.materia.models import Autor
from sapl.materia.models import Autor, UnidadeTramitacao
from sapl.utils import RANGE_ANOS, autor_label, autor_modal
from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo,
@ -494,7 +496,6 @@ class TramitacaoAdmForm(ModelForm):
'data_encaminhamento',
'data_fim_prazo',
'texto',
'documento',
]
widgets = {
@ -503,22 +504,78 @@ class TramitacaoAdmForm(ModelForm):
'data_fim_prazo': forms.DateInput(format='%d/%m/%Y'),
}
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(_('Incluir Tramitação'),
'data_tramitacao',
def clean(self):
data_enc_form = self.cleaned_data['data_encaminhamento']
data_prazo_form = self.cleaned_data['data_fim_prazo']
data_tram_form = self.cleaned_data['data_tramitacao']
if self.errors:
return self.errors
ultima_tramitacao = TramitacaoAdministrativo.objects.filter(
documento_id=self.instance.documento_id).exclude(
id=self.instance.id).last()
if not self.instance.data_tramitacao:
if ultima_tramitacao:
destino = ultima_tramitacao.unidade_tramitacao_destino
if (destino != self.cleaned_data['unidade_tramitacao_local']):
msg = _('A origem da nova tramitação deve ser igual ao '
'destino da última adicionada!')
raise ValidationError(msg)
if self.cleaned_data['data_tramitacao'] > datetime.now().date():
msg = _(
'A data de tramitação deve ser ' +
'menor ou igual a data de hoje!')
raise ValidationError(msg)
if (ultima_tramitacao and
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 < data_tram_form or data_prazo_form < data_tram_form:
msg = _('A data fim de prazo e encaminhamento devem ser ' +
'maiores que a data de tramitação!')
raise ValidationError(msg)
return self.cleaned_data
class TramitacaoAdmEditForm(TramitacaoAdmForm):
unidade_tramitacao_local = forms.ModelChoiceField(
queryset=UnidadeTramitacao.objects.all(),
widget=forms.HiddenInput())
data_tramitacao = forms.DateField(widget=forms.HiddenInput())
class Meta:
model = TramitacaoAdministrativo
fields = ['data_tramitacao',
'unidade_tramitacao_local',
'status',
'unidade_tramitacao_destino',
'data_encaminhamento',
'data_fim_prazo',
'texto'),
Field('documento', type="hidden"),
form_actions()
)
super(TramitacaoAdmForm, self).__init__(
*args, **kwargs)
'texto',
]
widgets = {
'data_encaminhamento': forms.DateInput(format='%d/%m/%Y'),
'data_fim_prazo': forms.DateInput(format='%d/%m/%Y'),
}
def clean(self):
local = self.instance.unidade_tramitacao_local
data_tram = self.instance.data_tramitacao
self.cleaned_data['data_tramitacao'] = data_tram
self.cleaned_data['unidade_tramitacao_local'] = local
return super(TramitacaoAdmEditForm, self).clean()
class DocumentoAdministrativoForm(ModelForm):

114
sapl/protocoloadm/migrations/0001_initial.py

@ -1,147 +1,163 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-24 14:31
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import sapl.protocoloadm.models
class Migration(migrations.Migration):
initial = True
dependencies = [
('materia', '0001_initial'),
('materia', '0038_auto_20160612_1506'),
]
operations = [
migrations.CreateModel(
name='DocumentoAcessorioAdministrativo',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
('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.CharField(max_length=100, verbose_name='Arquivo')),
('arquivo', models.FileField(blank=True, null=True, upload_to=sapl.protocoloadm.models.texto_upload_path, verbose_name='Arquivo')),
('data', models.DateField(blank=True, null=True, verbose_name='Data')),
('autor', models.CharField(blank=True, max_length=50, null=True, verbose_name='Autor')),
('assunto', models.TextField(blank=True, null=True, verbose_name='Assunto')),
('indexacao', models.TextField(blank=True, null=True)),
('autor', models.CharField(blank=True, max_length=50, verbose_name='Autor')),
('assunto', models.TextField(blank=True, verbose_name='Assunto')),
('indexacao', models.TextField(blank=True)),
],
options={
'verbose_name_plural': 'Documentos Acessórios',
'verbose_name': 'Documento Acessório',
'verbose_name_plural': 'Documentos Acessórios',
},
),
migrations.CreateModel(
name='DocumentoAdministrativo',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
('numero', models.IntegerField(verbose_name='Número')),
('ano', models.SmallIntegerField(verbose_name='Ano')),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('numero', models.PositiveIntegerField(verbose_name='Número')),
('ano', models.PositiveSmallIntegerField(choices=[(2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano')),
('data', models.DateField(verbose_name='Data')),
('numero_protocolo', models.IntegerField(blank=True, null=True, verbose_name='Núm. Protocolo')),
('interessado', models.CharField(blank=True, max_length=50, null=True, verbose_name='Interessado')),
('dias_prazo', models.IntegerField(blank=True, null=True, verbose_name='Dias Prazo')),
('numero_protocolo', models.PositiveIntegerField(blank=True, null=True, verbose_name='Núm. Protocolo')),
('interessado', models.CharField(blank=True, max_length=50, verbose_name='Interessado')),
('dias_prazo', models.PositiveIntegerField(blank=True, null=True, verbose_name='Dias Prazo')),
('data_fim_prazo', models.DateField(blank=True, null=True, verbose_name='Data Fim Prazo')),
('tramitacao', models.BooleanField(verbose_name='Em Tramitação?')),
('tramitacao', models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], verbose_name='Em Tramitação?')),
('assunto', models.TextField(verbose_name='Assunto')),
('observacao', models.TextField(blank=True, null=True, verbose_name='Observação')),
('autor', models.ForeignKey(blank=True, null=True, to='materia.Autor')),
('observacao', models.TextField(blank=True, verbose_name='Observação')),
('texto_integral', models.FileField(blank=True, null=True, upload_to=sapl.protocoloadm.models.texto_upload_path, verbose_name='Texto Integral')),
('autor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='materia.Autor')),
],
options={
'verbose_name_plural': 'Documentos Administrativos',
'verbose_name': 'Documento Administrativo',
'verbose_name_plural': 'Documentos Administrativos',
},
),
migrations.CreateModel(
name='Protocolo',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
('numero', models.IntegerField(blank=True, null=True, verbose_name='Número do Protocolo')),
('ano', models.SmallIntegerField()),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('numero', models.PositiveIntegerField(verbose_name='Número de Protocolo')),
('ano', models.PositiveSmallIntegerField(choices=[(2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano do Protocolo')),
('data', models.DateField()),
('hora', models.TimeField()),
('timestamp', models.DateTimeField()),
('tipo_protocolo', models.IntegerField(verbose_name='Tipo de Protocolo')),
('tipo_processo', models.IntegerField()),
('interessado', models.CharField(blank=True, max_length=60, null=True, verbose_name='Interessado')),
('assunto_ementa', models.TextField(blank=True, null=True)),
('numero_paginas', models.IntegerField(blank=True, null=True, verbose_name='Número de Páginas')),
('observacao', models.TextField(blank=True, null=True, verbose_name='Observação')),
('tipo_protocolo', models.PositiveIntegerField(verbose_name='Tipo de Protocolo')),
('tipo_processo', models.PositiveIntegerField()),
('interessado', models.CharField(blank=True, max_length=60, verbose_name='Interessado')),
('assunto_ementa', models.TextField(blank=True)),
('numero_paginas', models.PositiveIntegerField(blank=True, null=True, verbose_name='Número de Páginas')),
('observacao', models.TextField(blank=True, verbose_name='Observação')),
('anulado', models.BooleanField()),
('user_anulacao', models.CharField(blank=True, max_length=20, null=True)),
('ip_anulacao', models.CharField(blank=True, max_length=15, null=True)),
('justificativa_anulacao', models.CharField(blank=True, max_length=60, null=True)),
('user_anulacao', models.CharField(blank=True, max_length=20)),
('ip_anulacao', models.CharField(blank=True, max_length=15)),
('justificativa_anulacao', models.CharField(blank=True, max_length=60, verbose_name='Motivo')),
('timestamp_anulacao', models.DateTimeField(blank=True, null=True)),
('autor', models.ForeignKey(blank=True, null=True, to='materia.Autor')),
('autor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='materia.Autor')),
],
options={
'verbose_name_plural': 'Protocolos',
'verbose_name': 'Protocolo',
'verbose_name_plural': 'Protocolos',
},
),
migrations.CreateModel(
name='StatusTramitacaoAdministrativo',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sigla', models.CharField(max_length=10, verbose_name='Sigla')),
('descricao', models.CharField(max_length=60, verbose_name='Descrição')),
('indicador', models.CharField(choices=[('F', 'Fim'), ('R', 'Retorno')], max_length=1, verbose_name='Indicador da Tramitação')),
],
options={
'verbose_name_plural': 'Status de Tramitação',
'verbose_name': 'Status de Tramitação',
'verbose_name_plural': 'Status de Tramitação',
},
),
migrations.CreateModel(
name='TipoDocumentoAdministrativo',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sigla', models.CharField(max_length=5, verbose_name='Sigla')),
('descricao', models.CharField(max_length=50, verbose_name='Descrição')),
],
options={
'verbose_name_plural': 'Tipos de Documento Administrativo',
'verbose_name': 'Tipo de Documento Administrativo',
'verbose_name_plural': 'Tipos de Documento Administrativo',
},
),
migrations.CreateModel(
name='TipoInstituicao',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('descricao', models.CharField(max_length=50, verbose_name='Descrição')),
],
options={
'verbose_name': 'Tipo de Instituição',
'verbose_name_plural': 'Tipos de Instituições',
},
),
migrations.CreateModel(
name='TramitacaoAdministrativo',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
('data_tramitacao', models.DateField(blank=True, null=True, verbose_name='Data Tramitação')),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('data_tramitacao', models.DateField(verbose_name='Data Tramitação')),
('data_encaminhamento', models.DateField(blank=True, null=True, verbose_name='Data Encaminhamento')),
('ultima', models.BooleanField()),
('texto', models.TextField(blank=True, null=True, verbose_name='Texto da Ação')),
('texto', models.TextField(blank=True, verbose_name='Texto da Ação')),
('data_fim_prazo', models.DateField(blank=True, null=True, verbose_name='Data Fim do Prazo')),
('documento', models.ForeignKey(to='protocoloadm.DocumentoAdministrativo')),
('status', models.ForeignKey(blank=True, null=True, to='protocoloadm.StatusTramitacaoAdministrativo', verbose_name='Status')),
('unidade_tramitacao_destino', models.ForeignKey(blank=True, null=True, to='materia.UnidadeTramitacao', verbose_name='Unidade Destino', related_name='+')),
('unidade_tramitacao_local', models.ForeignKey(blank=True, null=True, to='materia.UnidadeTramitacao', verbose_name='Unidade Local', related_name='+')),
('documento', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='protocoloadm.DocumentoAdministrativo')),
('status', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='protocoloadm.StatusTramitacaoAdministrativo', verbose_name='Status')),
('unidade_tramitacao_destino', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='adm_tramitacoes_destino', to='materia.UnidadeTramitacao', verbose_name='Unidade Destino')),
('unidade_tramitacao_local', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='adm_tramitacoes_origem', to='materia.UnidadeTramitacao', verbose_name='Unidade Local')),
],
options={
'verbose_name_plural': 'Tramitações de Documento Administrativo',
'verbose_name': 'Tramitação de Documento Administrativo',
'verbose_name_plural': 'Tramitações de Documento Administrativo',
},
),
migrations.AddField(
model_name='protocolo',
name='tipo_documento',
field=models.ForeignKey(blank=True, null=True, to='protocoloadm.TipoDocumentoAdministrativo', verbose_name='Tipo de documento'),
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='protocoloadm.TipoDocumentoAdministrativo', verbose_name='Tipo de documento'),
),
migrations.AddField(
model_name='protocolo',
name='tipo_materia',
field=models.ForeignKey(blank=True, null=True, to='materia.TipoMateriaLegislativa', verbose_name='Tipo Matéria'),
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='materia.TipoMateriaLegislativa', verbose_name='Tipo Matéria'),
),
migrations.AddField(
model_name='documentoadministrativo',
name='tipo',
field=models.ForeignKey(to='protocoloadm.TipoDocumentoAdministrativo', verbose_name='Tipo Documento'),
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='protocoloadm.TipoDocumentoAdministrativo', verbose_name='Tipo Documento'),
),
migrations.AddField(
model_name='documentoacessorioadministrativo',
name='documento',
field=models.ForeignKey(to='protocoloadm.DocumentoAdministrativo'),
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='protocoloadm.DocumentoAdministrativo'),
),
migrations.AddField(
model_name='documentoacessorioadministrativo',
name='tipo',
field=models.ForeignKey(to='protocoloadm.TipoDocumentoAdministrativo', verbose_name='Tipo'),
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='protocoloadm.TipoDocumentoAdministrativo', verbose_name='Tipo'),
),
]

59
sapl/protocoloadm/migrations/0002_auto_20150729_1717.py

@ -1,59 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='documentoadministrativo',
name='ano',
field=models.PositiveSmallIntegerField(verbose_name='Ano'),
),
migrations.AlterField(
model_name='documentoadministrativo',
name='dias_prazo',
field=models.PositiveIntegerField(blank=True, verbose_name='Dias Prazo', null=True),
),
migrations.AlterField(
model_name='documentoadministrativo',
name='numero',
field=models.PositiveIntegerField(verbose_name='Número'),
),
migrations.AlterField(
model_name='documentoadministrativo',
name='numero_protocolo',
field=models.PositiveIntegerField(blank=True, verbose_name='Núm. Protocolo', null=True),
),
migrations.AlterField(
model_name='protocolo',
name='ano',
field=models.PositiveSmallIntegerField(),
),
migrations.AlterField(
model_name='protocolo',
name='numero',
field=models.PositiveIntegerField(blank=True, verbose_name='Número do Protocolo', null=True),
),
migrations.AlterField(
model_name='protocolo',
name='numero_paginas',
field=models.PositiveIntegerField(blank=True, verbose_name='Número de Páginas', null=True),
),
migrations.AlterField(
model_name='protocolo',
name='tipo_processo',
field=models.PositiveIntegerField(),
),
migrations.AlterField(
model_name='protocolo',
name='tipo_protocolo',
field=models.PositiveIntegerField(verbose_name='Tipo de Protocolo'),
),
]

22
sapl/protocoloadm/migrations/0003_documentoacessorioadministrativo_texto_integral.py

@ -1,22 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import sapl.protocoloadm.models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0002_auto_20150729_1717'),
]
operations = [
migrations.AddField(
model_name='documentoacessorioadministrativo',
name='texto_integral',
field=models.FileField(verbose_name='Texto Integral', blank=True,
null=True, upload_to=sapl.protocoloadm.models.texto_upload_path),
),
]

27
sapl/protocoloadm/migrations/0004_auto_20151007_1035.py

@ -1,27 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import sapl.protocoloadm.models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm',
'0003_documentoacessorioadministrativo_texto_integral'),
]
operations = [
migrations.RemoveField(
model_name='documentoacessorioadministrativo',
name='texto_integral',
),
migrations.AddField(
model_name='documentoadministrativo',
name='texto_integral',
field=models.FileField(
blank=True, null=True, upload_to=sapl.protocoloadm.models.texto_upload_path, verbose_name='Texto Integral'),
),
]

22
sapl/protocoloadm/migrations/0005_auto_20151008_0744.py

@ -1,22 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import sapl.protocoloadm.models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0004_auto_20151007_1035'),
]
operations = [
migrations.AlterField(
model_name='documentoacessorioadministrativo',
name='arquivo',
field=models.FileField(
blank=True, null=True, upload_to=sapl.protocoloadm.models.texto_upload_path, verbose_name='Arquivo'),
),
]

74
sapl/protocoloadm/migrations/0006_auto_20160216_1015.py

@ -1,74 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0005_auto_20151008_0744'),
]
operations = [
migrations.AlterField(
model_name='documentoacessorioadministrativo',
name='assunto',
field=models.TextField(verbose_name='Assunto', blank=True),
),
migrations.AlterField(
model_name='documentoacessorioadministrativo',
name='autor',
field=models.CharField(verbose_name='Autor', max_length=50, blank=True),
),
migrations.AlterField(
model_name='documentoacessorioadministrativo',
name='indexacao',
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='documentoadministrativo',
name='interessado',
field=models.CharField(verbose_name='Interessado', max_length=50, blank=True),
),
migrations.AlterField(
model_name='documentoadministrativo',
name='observacao',
field=models.TextField(verbose_name='Observação', blank=True),
),
migrations.AlterField(
model_name='protocolo',
name='assunto_ementa',
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='protocolo',
name='interessado',
field=models.CharField(verbose_name='Interessado', max_length=60, blank=True),
),
migrations.AlterField(
model_name='protocolo',
name='ip_anulacao',
field=models.CharField(max_length=15, blank=True),
),
migrations.AlterField(
model_name='protocolo',
name='justificativa_anulacao',
field=models.CharField(max_length=60, blank=True),
),
migrations.AlterField(
model_name='protocolo',
name='observacao',
field=models.TextField(verbose_name='Observação', blank=True),
),
migrations.AlterField(
model_name='protocolo',
name='user_anulacao',
field=models.CharField(max_length=20, blank=True),
),
migrations.AlterField(
model_name='tramitacaoadministrativo',
name='texto',
field=models.TextField(verbose_name='Texto da Ação', blank=True),
),
]

19
sapl/protocoloadm/migrations/0007_auto_20160218_1429.py

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0006_auto_20160216_1015'),
]
operations = [
migrations.AlterField(
model_name='documentoadministrativo',
name='tramitacao',
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], verbose_name='Em Tramitação?'),
),
]

20
sapl/protocoloadm/migrations/0008_auto_20160308_1436.py

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-03-08 17:36
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0007_auto_20160218_1429'),
]
operations = [
migrations.AlterField(
model_name='protocolo',
name='ano',
field=models.PositiveSmallIntegerField(verbose_name='Ano do Protocolo'),
),
]

20
sapl/protocoloadm/migrations/0009_auto_20160309_1323.py

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-03-09 16:23
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0008_auto_20160308_1436'),
]
operations = [
migrations.AlterField(
model_name='protocolo',
name='numero',
field=models.PositiveIntegerField(verbose_name='Número de Protocolo'),
),
]

25
sapl/protocoloadm/migrations/0010_auto_20160309_1407.py

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-03-09 17:07
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0009_auto_20160309_1323'),
]
operations = [
migrations.AlterField(
model_name='documentoadministrativo',
name='ano',
field=models.PositiveSmallIntegerField(choices=[(2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano'),
),
migrations.AlterField(
model_name='protocolo',
name='ano',
field=models.PositiveSmallIntegerField(choices=[(2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano do Protocolo'),
),
]

20
sapl/protocoloadm/migrations/0011_auto_20160318_1504.py

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-03-18 18:04
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0010_auto_20160309_1407'),
]
operations = [
migrations.AlterField(
model_name='protocolo',
name='justificativa_anulacao',
field=models.CharField(blank=True, max_length=60, verbose_name='Motivo'),
),
]

26
sapl/protocoloadm/migrations/0012_auto_20160503_0926.py

@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-05-03 12:26
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0011_auto_20160318_1504'),
]
operations = [
migrations.AlterField(
model_name='tramitacaoadministrativo',
name='unidade_tramitacao_destino',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='adm_tramitacoes_destino', to='materia.UnidadeTramitacao', verbose_name='Unidade Destino'),
),
migrations.AlterField(
model_name='tramitacaoadministrativo',
name='unidade_tramitacao_local',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='adm_tramitacoes_origem', to='materia.UnidadeTramitacao', verbose_name='Unidade Local'),
),
]

26
sapl/protocoloadm/migrations/0012_tipoinstituicao.py

@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-05-17 18:07
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0011_auto_20160318_1504'),
]
operations = [
migrations.CreateModel(
name='TipoInstituicao',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('descricao', models.CharField(max_length=50, verbose_name='Descrição')),
],
options={
'verbose_name': 'Tipo de Instituição',
'verbose_name_plural': 'Tipos de Instituições',
},
),
]

7
sapl/protocoloadm/models.py

@ -167,16 +167,12 @@ class StatusTramitacaoAdministrativo(models.Model):
class TramitacaoAdministrativo(models.Model):
status = models.ForeignKey(
StatusTramitacaoAdministrativo,
blank=True,
null=True,
verbose_name=_('Status'))
documento = models.ForeignKey(DocumentoAdministrativo)
data_tramitacao = models.DateField(
blank=True, null=True, verbose_name=_('Data Tramitação'))
verbose_name=_('Data Tramitação'))
unidade_tramitacao_local = models.ForeignKey(
UnidadeTramitacao,
blank=True,
null=True,
related_name='adm_tramitacoes_origem',
verbose_name=_('Unidade Local'))
data_encaminhamento = models.DateField(
@ -187,7 +183,6 @@ class TramitacaoAdministrativo(models.Model):
null=True,
related_name='adm_tramitacoes_destino',
verbose_name=_('Unidade Destino'))
ultima = models.BooleanField()
texto = models.TextField(
blank=True, verbose_name=_('Texto da Ação'))
data_fim_prazo = models.DateField(

8
sapl/protocoloadm/tests/test_protocoloadm.py

@ -8,17 +8,17 @@ from sapl.protocoloadm.models import Protocolo
@pytest.mark.django_db(transaction=False)
def test_anular_protocolo_acessivel(client):
response = client.get(reverse('sapl.protocoloadm:anular_protocolo'))
def test_anular_protocolo_acessivel(admin_client):
response = admin_client.get(reverse('sapl.protocoloadm:anular_protocolo'))
assert response.status_code == 200
@pytest.mark.django_db(transaction=False)
def test_anular_protocolo_submit(client):
def test_anular_protocolo_submit(admin_client):
mommy.make(Protocolo, numero='76', ano='2016', anulado=False)
# TODO: setar usuario e IP
response = client.post(reverse('sapl.protocoloadm:anular_protocolo'),
response = admin_client.post(reverse('sapl.protocoloadm:anular_protocolo'),
{'numero': '76',
'ano': '2016',
'justificativa_anulacao': 'TESTE',

17
sapl/protocoloadm/urls.py

@ -17,12 +17,7 @@ from sapl.protocoloadm.views import (AnularProtocoloAdmView,
ProtocoloPesquisaView,
StatusTramitacaoAdministrativoCrud,
TipoDocumentoAdministrativoCrud,
TipoInstituicaoCrud,
TramitacaoAdmDeleteView,
TramitacaoAdmEditView,
TramitacaoAdmIncluirView,
TramitacaoAdministrativoCrud,
TramitacaoAdmView)
TipoInstituicaoCrud)
from .apps import AppConfig
@ -39,8 +34,6 @@ urlpatterns = [
include(StatusTramitacaoAdministrativoCrud.get_urls())),
url(r'^protocoloadm/tipo-instituicao/',
include(TipoInstituicaoCrud.get_urls())),
url(r'^protocoloadm/tramitacao-adm/',
include(TramitacaoAdministrativoCrud.get_urls())),
url(r'^protocoloadm/protocolo-doc/',
include(ProtocoloDocumentoCrud.get_urls())),
url(r'^protocoloadm/protocolo-mat/',
@ -67,14 +60,6 @@ urlpatterns = [
DocumentoAcessorioAdministrativoEditView.as_view(),
name='doc_ace_adm_edit'),
url(r'^protocoloadm/(?P<pk>\d+)/tramitacao$',
TramitacaoAdmView.as_view(), name='tramitacao_adm'),
url(r'^protocoloadm/(?P<pk>\d+)/tramitacao_incluir',
TramitacaoAdmIncluirView.as_view(), name='tramitacao_incluir'),
url(r'^protocoloadm/(?P<pk>\d+)/tramitacao_edit',
TramitacaoAdmEditView.as_view(), name='tramitacao_edit'),
url(r'^protocoloadm/(?P<pk>\d+)/tramitacao_delete/(?P<oid>\d+)',
TramitacaoAdmDeleteView.as_view(), name='tramitacao_delete'),
url(r'^protocoloadm/(?P<pk>\d+)/(?P<ano>\d+)/comprovante$',
ComprovanteProtocoloView.as_view(), name='comprovante_protocolo'),

187
sapl/protocoloadm/views.py

@ -2,6 +2,7 @@ import json
from datetime import date, datetime
from braces.views import FormValidMessageMixin
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.db.models import Max, Q
@ -12,14 +13,20 @@ from django.views.generic import CreateView, DetailView, FormView, ListView
from django.views.generic.base import TemplateView
from django_filters.views import FilterView
from sapl.crud.base import Crud, CrudBaseMixin, CrudListView, make_pagination
import sapl.crud.base
from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView,
CrudDeleteView, CrudListView, CrudUpdateView,
make_pagination)
from sapl.crud.masterdetail import MasterDetailCrud
from sapl.materia.models import TipoMateriaLegislativa
from sapl.utils import create_barcode, get_client_ip
from sapl.utils import (create_barcode, get_client_ip, permissoes_adm,
permissoes_protocoloadm)
from .forms import (AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm,
DocumentoAdministrativoFilterSet,
DocumentoAdministrativoForm, ProtocoloDocumentForm,
ProtocoloFilterSet, ProtocoloMateriaForm,
DocumentoAdministrativoForm,
ProtocoloDocumentForm, ProtocoloFilterSet,
ProtocoloMateriaForm, TramitacaoAdmEditForm,
TramitacaoAdmForm)
from .models import (Autor, DocumentoAcessorioAdministrativo,
DocumentoAdministrativo, Protocolo,
@ -28,16 +35,33 @@ from .models import (Autor, DocumentoAcessorioAdministrativo,
TramitacaoAdministrativo)
TipoDocumentoAdministrativoCrud = Crud.build(TipoDocumentoAdministrativo, '')
DocumentoAdministrativoCrud = Crud.build(DocumentoAdministrativo, '')
DocumentoAcessorioAdministrativoCrud = Crud.build(
DocumentoAcessorioAdministrativo, '')
TramitacaoAdministrativoCrud = Crud.build(TramitacaoAdministrativo, '')
ProtocoloDocumentoCrud = Crud.build(Protocolo, '')
# FIXME precisa de uma chave diferente para o layout
ProtocoloMateriaCrud = Crud.build(Protocolo, '')
TipoInstituicaoCrud = Crud.build(TipoInstituicao, '')
class DocumentoAdministrativoCrud(Crud):
model = DocumentoAdministrativo
help_path = ''
class BaseMixin(sapl.crud.base.CrudBaseMixin):
list_field_names = ['tipo', 'numero', 'ano', 'data',
'numero_protocolo', 'assunto',
'interessado', 'tramitacao', 'texto_integral']
class CreateView(PermissionRequiredMixin, CrudCreateView):
permission_required = permissoes_adm()
class UpdateView(PermissionRequiredMixin, CrudUpdateView):
permission_required = permissoes_adm()
class DeleteView(PermissionRequiredMixin, CrudDeleteView):
permission_required = permissoes_adm()
class StatusTramitacaoAdministrativoCrud(Crud):
model = StatusTramitacaoAdministrativo
help_path = ''
@ -48,11 +72,21 @@ class StatusTramitacaoAdministrativoCrud(Crud):
class ListView(CrudListView):
ordering = 'sigla'
class CreateView(PermissionRequiredMixin, CrudCreateView):
permission_required = permissoes_adm()
class UpdateView(PermissionRequiredMixin, CrudUpdateView):
permission_required = permissoes_adm()
class DeleteView(PermissionRequiredMixin, CrudDeleteView):
permission_required = permissoes_adm()
class ProtocoloPesquisaView(FilterView):
class ProtocoloPesquisaView(PermissionRequiredMixin, FilterView):
model = Protocolo
filterset_class = ProtocoloFilterSet
paginate_by = 10
permission_required = permissoes_protocoloadm()
def get_filterset_kwargs(self, filterset_class):
super(ProtocoloPesquisaView,
@ -108,11 +142,12 @@ class ProtocoloPesquisaView(FilterView):
return self.render_to_response(context)
class ProtocoloListView(ListView):
class ProtocoloListView(PermissionRequiredMixin, ListView):
template_name = 'protocoloadm/protocolo_list.html'
context_object_name = 'protocolos'
model = Protocolo
paginate_by = 10
permission_required = permissoes_protocoloadm()
def get_queryset(self):
kwargs = self.request.session['kwargs']
@ -131,10 +166,11 @@ class ProtocoloListView(ListView):
return context
class AnularProtocoloAdmView(CreateView):
class AnularProtocoloAdmView(PermissionRequiredMixin, CreateView):
template_name = 'protocoloadm/anular_protocoloadm.html'
form_class = AnularProcoloAdmForm
form_valid_message = _('Protocolo anulado com sucesso!')
permission_required = permissoes_protocoloadm()
def get_success_url(self):
return reverse('sapl.protocoloadm:protocolo')
@ -157,10 +193,13 @@ class AnularProtocoloAdmView(CreateView):
return redirect(self.get_success_url())
class ProtocoloDocumentoView(FormValidMessageMixin, CreateView):
class ProtocoloDocumentoView(PermissionRequiredMixin,
FormValidMessageMixin,
CreateView):
template_name = "protocoloadm/protocolar_documento.html"
form_class = ProtocoloDocumentForm
form_valid_message = _('Protocolo cadastrado com sucesso!')
permission_required = permissoes_protocoloadm()
def get_success_url(self):
return reverse('sapl.protocoloadm:protocolo')
@ -189,9 +228,10 @@ class ProtocoloDocumentoView(FormValidMessageMixin, CreateView):
return redirect(self.get_success_url())
class CriarDocumentoProtocolo(CreateView):
class CriarDocumentoProtocolo(PermissionRequiredMixin, CreateView):
template_name = "protocoloadm/criar_documento.html"
form_class = DocumentoAdministrativoForm
permission_required = permissoes_protocoloadm()
def get_initial(self):
numero = self.kwargs['pk']
@ -226,9 +266,10 @@ class CriarDocumentoProtocolo(CreateView):
return doc
class ProtocoloMostrarView(TemplateView):
class ProtocoloMostrarView(PermissionRequiredMixin, TemplateView):
template_name = "protocoloadm/protocolo_mostrar.html"
permission_required = permissoes_protocoloadm()
def get_context_data(self, **kwargs):
context = super(ProtocoloMostrarView, self).get_context_data(**kwargs)
@ -239,9 +280,10 @@ class ProtocoloMostrarView(TemplateView):
return context
class ComprovanteProtocoloView(TemplateView):
class ComprovanteProtocoloView(PermissionRequiredMixin, TemplateView):
template_name = "protocoloadm/comprovante.html"
permission_required = permissoes_protocoloadm()
def get_context_data(self, **kwargs):
context = super(ComprovanteProtocoloView, self).get_context_data(
@ -267,11 +309,12 @@ class ComprovanteProtocoloView(TemplateView):
return context
class ProtocoloMateriaView(CreateView):
class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
template_name = "protocoloadm/protocolar_materia.html"
form_class = ProtocoloMateriaForm
form_valid_message = _('Matéria cadastrada com sucesso!')
permission_required = permissoes_protocoloadm()
def get_success_url(self):
return reverse('sapl.protocoloadm:protocolo')
@ -306,10 +349,12 @@ class ProtocoloMateriaView(CreateView):
return redirect(self.get_success_url())
class PesquisarDocumentoAdministrativoView(FilterView):
class PesquisarDocumentoAdministrativoView(PermissionRequiredMixin,
FilterView):
model = DocumentoAdministrativo
filterset_class = DocumentoAdministrativoFilterSet
paginate_by = 10
permission_required = permissoes_adm()
def get_filterset_kwargs(self, filterset_class):
super(PesquisarDocumentoAdministrativoView,
@ -365,8 +410,9 @@ class PesquisarDocumentoAdministrativoView(FilterView):
return self.render_to_response(context)
class DetailDocumentoAdministrativo(DetailView):
class DetailDocumentoAdministrativo(PermissionRequiredMixin, DetailView):
template_name = "protocoloadm/detail_doc_adm.html"
permission_required = permissoes_adm()
def get(self, request, *args, **kwargs):
documento = DocumentoAdministrativo.objects.get(
@ -405,8 +451,10 @@ class DetailDocumentoAdministrativo(DetailView):
'pk': self.kwargs['pk']})
class DocumentoAcessorioAdministrativoEditView(FormView):
class DocumentoAcessorioAdministrativoEditView(PermissionRequiredMixin,
FormView):
template_name = "protocoloadm/documento_acessorio_administrativo_edit.html"
permission_required = permissoes_adm()
def get(self, request, *args, **kwargs):
doc = DocumentoAdministrativo.objects.get(
@ -452,8 +500,9 @@ class DocumentoAcessorioAdministrativoEditView(FormView):
return reverse('sapl.protocoloadm:doc_ace_adm', kwargs={'pk': pk})
class DocumentoAcessorioAdministrativoView(FormView):
class DocumentoAcessorioAdministrativoView(PermissionRequiredMixin, FormView):
template_name = "protocoloadm/documento_acessorio_administrativo.html"
permission_required = permissoes_adm()
def get(self, request, *args, **kwargs):
form = DocumentoAcessorioAdministrativoForm()
@ -463,8 +512,8 @@ class DocumentoAcessorioAdministrativoView(FormView):
doc_acessorio = DocumentoAcessorioAdministrativo.objects.filter(
documento_id=kwargs['pk'])
if not doc_acessorio:
doc_ace_null = _('Nenhum documento acessório \
cadastrado para este processo.')
doc_ace_null = _('Nenhum documento acessório' +
'cadastrado para este processo.')
return self.render_to_response({'pk': kwargs['pk'],
'doc': doc,
@ -491,90 +540,30 @@ class DocumentoAcessorioAdministrativoView(FormView):
return reverse('sapl.protocoloadm:doc_ace_adm', kwargs={'pk': pk})
class TramitacaoAdmView(FormView):
template_name = "protocoloadm/tramitacao.html"
def get(self, request, *args, **kwargs):
pk = kwargs['pk']
documento = DocumentoAdministrativo.objects.get(id=pk)
tramitacoes = TramitacaoAdministrativo.objects.filter(
documento=documento).order_by('-data_tramitacao')
return self.render_to_response({'documento': documento,
'tramitacoes': tramitacoes})
class TramitacaoAdmIncluirView(FormView):
template_name = "protocoloadm/tramitacao_incluir.html"
def get(self, request, *args, **kwargs):
pk = kwargs['pk']
documento = DocumentoAdministrativo.objects.get(id=pk)
data = {'documento': documento}
form = TramitacaoAdmForm(initial=data)
return self.render_to_response({'documento': documento, 'form': form})
def post(self, request, *args, **kwargs):
pk = kwargs['pk']
form = TramitacaoAdmForm(request.POST or None)
if form.is_valid():
tramitacao = form.save(commit=False)
tramitacao.ultima = False
tramitacao.save()
return HttpResponseRedirect(reverse(
'sapl.protocoloadm:tramitacao_adm', kwargs={'pk': pk}))
else:
return self.form_invalid(form)
class TramitacaoAdmEditView(FormView):
template_name = "protocoloadm/tramitacao_edit.html"
def get(self, request, *args, **kwargs):
pk = kwargs['pk']
tramitacao = TramitacaoAdministrativo.objects.get(id=pk)
documento = tramitacao.documento
form = TramitacaoAdmForm(instance=tramitacao)
return self.render_to_response({'documento': documento, 'form': form})
def post(self, request, *args, **kwargs):
pk = kwargs['pk']
tramitacao = TramitacaoAdministrativo.objects.get(id=pk)
form = TramitacaoAdmForm(request.POST, instance=tramitacao)
if form.is_valid():
tramitacao = form.save(commit=False)
tramitacao.ultima = False
tramitacao.save()
return HttpResponseRedirect(
reverse('sapl.protocoloadm:tramitacao_adm',
kwargs={'pk': tramitacao.documento.id}))
else:
return self.form_invalid(form)
class TramitacaoAdmCrud(MasterDetailCrud):
model = TramitacaoAdministrativo
parent_field = 'documento'
help_path = ''
class TramitacaoAdmDeleteView(DetailView):
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['data_tramitacao', 'unidade_tramitacao_local',
'unidade_tramitacao_destino', 'status']
template_name = "protocoloadm/tramitacao.html"
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
form_class = TramitacaoAdmForm
permission_required = permissoes_adm()
def get(self, request, *args, **kwargs):
pk = kwargs['pk']
oid = kwargs['oid']
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
form_class = TramitacaoAdmEditForm
permission_required = permissoes_adm()
documento = DocumentoAdministrativo.objects.get(id=pk)
class ListView(PermissionRequiredMixin, MasterDetailCrud.ListView):
permission_required = permissoes_adm()
tramitacao = TramitacaoAdministrativo.objects.get(id=oid)
tramitacao.delete()
tramitacoes = TramitacaoAdministrativo.objects.filter(
documento=documento)
return self.render_to_response({'documento': documento,
'tramitacoes': tramitacoes})
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('-id')
def get_nome_autor(request):

261
sapl/sessao/views.py

@ -2,6 +2,7 @@ from datetime import datetime
from re import sub
from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.urlresolvers import reverse
from django.forms.utils import ErrorList
@ -15,8 +16,8 @@ from django_filters.views import FilterView
from rest_framework import generics
from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView,
CrudDetailView, CrudListView, CrudUpdateView,
make_pagination)
CrudDeleteView, CrudDetailView, CrudListView,
CrudUpdateView, make_pagination)
from sapl.crud.masterdetail import MasterDetailCrud
from sapl.materia.forms import pega_ultima_tramitacao
from sapl.materia.models import (Autoria, DocumentoAcessorio,
@ -25,6 +26,7 @@ from sapl.materia.views import MateriaLegislativaPesquisaView
from sapl.norma.models import NormaJuridica
from sapl.parlamentares.models import Parlamentar
from sapl.sessao.serializers import SessaoPlenariaSerializer
from sapl.utils import permissao_tb_aux, permissoes_painel, permissoes_sessao
from .forms import (AdicionarVariasMateriasFilterSet,
BancadaForm, ExpedienteForm, ExpedienteMateriaForm,
@ -39,13 +41,8 @@ from .models import (Bancada, CargoBancada, CargoMesa, ExpedienteMateria,
TipoExpediente, TipoResultadoVotacao, TipoSessaoPlenaria,
VotoParlamentar)
TipoSessaoCrud = Crud.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria')
OrdemDiaCrud = Crud.build(OrdemDia, '')
TipoResultadoVotacaoCrud = Crud.build(
TipoResultadoVotacao, 'tipo_resultado_votacao')
TipoExpedienteCrud = Crud.build(TipoExpediente, 'tipo_expediente')
RegistroVotacaoCrud = Crud.build(RegistroVotacao, '')
CargoBancadaCrud = Crud.build(CargoBancada, '')
def reordernar_materias_expediente(request, pk):
@ -78,9 +75,12 @@ class BancadaCrud(Crud):
model = Bancada
help_path = ''
class BaseMixin(CrudBaseMixin):
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
list_field_names = ['nome', 'legislatura']
def has_permission(self):
return permissao_tb_aux(self)
class ListView(CrudListView):
ordering = 'legislatura'
@ -91,6 +91,42 @@ class BancadaCrud(Crud):
form_class = BancadaForm
class TipoSessaoCrud(Crud):
model = TipoSessaoPlenaria
help_path = 'tipo_sessao_plenaria'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class TipoResultadoVotacaoCrud(Crud):
model = TipoResultadoVotacao
help_path = 'tipo_resultado_votacao'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class TipoExpedienteCrud(Crud):
model = TipoExpediente
help_path = 'tipo_expediente'
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
class CargoBancadaCrud(Crud):
model = CargoBancada
help_path = ''
class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
def has_permission(self):
return permissao_tb_aux(self)
def abrir_votacao_expediente_view(request, pk, spk):
existe_votacao_aberta = ExpedienteMateria.objects.filter(
sessao_plenaria_id=spk, votacao_aberta=True
@ -289,11 +325,13 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
obj.resultado)
return [self._as_row(obj) for obj in object_list]
class CreateView(MasterDetailCrud.CreateView):
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
form_class = ExpedienteMateriaForm
permission_required = permissoes_sessao()
class UpdateView(MasterDetailCrud.UpdateView):
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
form_class = ExpedienteMateriaForm
permission_required = permissoes_sessao()
def get_initial(self):
self.initial['tipo_materia'] = self.object.materia.tipo.id
@ -301,6 +339,9 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
self.initial['ano_materia'] = self.object.materia.ano
return self.initial
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_sessao()
class DetailView(MasterDetailCrud.DetailView):
@property
@ -316,14 +357,41 @@ class OradorCrud(MasterDetailCrud):
class ListView(MasterDetailCrud.ListView):
ordering = ['numero_ordem', 'parlamentar']
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
permission_required = permissoes_sessao()
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
permission_required = permissoes_sessao()
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_sessao()
class OradorExpedienteCrud(OradorCrud):
model = OradorExpediente
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
permission_required = permissoes_sessao()
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
permission_required = permissoes_sessao()
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_sessao()
class OradorCrud(OradorCrud):
model = Orador
class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
permission_required = permissoes_sessao()
class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
permission_required = permissoes_sessao()
class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
permission_required = permissoes_sessao()
class SessaoCrud(Crud):
model = SessaoPlenaria
@ -342,6 +410,15 @@ class SessaoCrud(Crud):
class ListView(CrudListView):
ordering = ['-data_inicio']
class CreateView(PermissionRequiredMixin, CrudCreateView):
permission_required = permissoes_sessao()
class UpdateView(PermissionRequiredMixin, CrudUpdateView):
permission_required = permissoes_sessao()
class DeleteView(PermissionRequiredMixin, CrudDeleteView):
permission_required = permissoes_sessao()
class PresencaMixin:
@ -360,10 +437,14 @@ class PresencaMixin:
yield (parlamentar, False)
class PresencaView(FormMixin, PresencaMixin, SessaoCrud.DetailView):
class PresencaView(PermissionRequiredMixin,
FormMixin,
PresencaMixin,
SessaoCrud.CrudDetailView):
template_name = 'sessao/presenca.html'
form_class = PresencaForm
model = SessaoPlenaria
permission_required = permissoes_sessao()
def post(self, request, *args, **kwargs):
self.object = self.get_object()
@ -401,15 +482,18 @@ class PresencaView(FormMixin, PresencaMixin, SessaoCrud.DetailView):
return reverse('sapl.sessao:presenca', kwargs={'pk': pk})
class PainelView(TemplateView):
class PainelView(PermissionRequiredMixin, TemplateView):
template_name = 'sessao/painel.html'
permission_required = permissoes_painel()
class PresencaOrdemDiaView(FormMixin,
class PresencaOrdemDiaView(PermissionRequiredMixin,
FormMixin,
PresencaMixin,
SessaoCrud.CrudDetailView):
template_name = 'sessao/presenca_ordemdia.html'
form_class = PresencaForm
permission_required = permissoes_sessao()
def post(self, request, *args, **kwargs):
@ -450,9 +534,113 @@ class PresencaOrdemDiaView(FormMixin,
return reverse('sapl.sessao:presencaordemdia', kwargs={'pk': pk})
class MesaView(FormMixin, SessaoCrud.CrudDetailView):
class ListMateriaOrdemDiaView(FormMixin, SessaoCrud.CrudDetailView):
template_name = 'sessao/materia_ordemdia_list.html'
form_class = ListMateriaForm
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
pk = self.kwargs['pk']
ordem = OrdemDia.objects.filter(sessao_plenaria_id=pk)
materias_ordem = []
for o in ordem:
ementa = o.observacao
titulo = o.materia
numero = o.numero_ordem
autoria = Autoria.objects.filter(materia_id=o.materia_id)
autor = [str(a.autor) for a in autoria]
mat = {'pk': pk,
'oid': o.materia_id,
'ordem_id': o.id,
'ementa': ementa,
'titulo': titulo,
'numero': numero,
'resultado': o.resultado,
'autor': autor,
'votacao_aberta': o.votacao_aberta,
'tipo_votacao': o.tipo_votacao
}
materias_ordem.append(mat)
sorted(materias_ordem, key=lambda x: x['numero'])
context.update({'materias_ordem': materias_ordem})
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
pk = self.kwargs['pk']
form = ListMateriaForm(request.POST)
# TODO: Existe uma forma de atualizar em lote de acordo
# com a forma abaixo, mas como setar o primeiro para "1"?
# OrdemDia.objects.filter(sessao_plenaria_id=pk)
# .order_by('numero_ordem').update(numero_ordem=3)
if 'materia_reorder' in request.POST:
ordens = OrdemDia.objects.filter(sessao_plenaria_id=pk)
ordem_num = 1
for o in ordens:
o.numero_ordem = ordem_num
o.save()
ordem_num += 1
elif 'abrir-votacao' in request.POST:
existe_votacao_aberta = OrdemDia.objects.filter(
sessao_plenaria_id=pk, votacao_aberta=True).exists()
if existe_votacao_aberta:
context = self.get_context_data(object=self.object)
form._errors = {'error_message': 'error_message'}
context.update({'form': form})
pk = self.kwargs['pk']
ordem = OrdemDia.objects.filter(sessao_plenaria_id=pk)
materias_ordem = []
for o in ordem:
ementa = o.observacao
titulo = o.materia
numero = o.numero_ordem
autoria = Autoria.objects.filter(materia_id=o.materia_id)
autor = [str(a.autor) for a in autoria]
mat = {'pk': pk,
'oid': o.materia_id,
'ordem_id': o.id,
'ementa': ementa,
'titulo': titulo,
'numero': numero,
'resultado': o.resultado,
'autor': autor,
'votacao_aberta': o.votacao_aberta,
'tipo_votacao': o.tipo_votacao
}
materias_ordem.append(mat)
sorted(materias_ordem, key=lambda x: x['numero'])
context.update({'materias_ordem': materias_ordem})
return self.render_to_response(context)
else:
ordem_id = request.POST['ordem_id']
ordem = OrdemDia.objects.get(id=ordem_id)
ordem.votacao_aberta = True
ordem.save()
return self.get(self, request, args, kwargs)
class MesaView(PermissionRequiredMixin, FormMixin, SessaoCrud.CrudDetailView):
template_name = 'sessao/mesa.html'
form_class = MesaForm
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -720,9 +908,12 @@ class ResumoView(SessaoCrud.CrudDetailView):
return self.render_to_response(context)
class ExpedienteView(FormMixin, SessaoCrud.CrudDetailView):
class ExpedienteView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
template_name = 'sessao/expediente.html'
form_class = ExpedienteForm
permission_required = permissoes_sessao()
def post(self, request, *args, **kwargs):
self.object = self.get_object()
@ -784,13 +975,16 @@ class ExpedienteView(FormMixin, SessaoCrud.CrudDetailView):
return reverse('sapl.sessao:expediente', kwargs={'pk': pk})
class VotacaoEditView(FormMixin, SessaoCrud.CrudDetailView):
class VotacaoEditView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
'''
Votação Simbólica e Secreta
'''
template_name = 'sessao/votacao/votacao_edit.html'
permission_required = permissoes_sessao()
def post(self, request, *args, **kwargs):
@ -857,7 +1051,9 @@ class VotacaoEditView(FormMixin, SessaoCrud.CrudDetailView):
kwargs={'pk': pk})
class VotacaoView(FormMixin, SessaoCrud.CrudDetailView):
class VotacaoView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
'''
Votação Simbólica e Secreta
@ -865,6 +1061,7 @@ class VotacaoView(FormMixin, SessaoCrud.CrudDetailView):
template_name = 'sessao/votacao/votacao.html'
form_class = VotacaoForm
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -976,8 +1173,11 @@ class VotacaoView(FormMixin, SessaoCrud.CrudDetailView):
kwargs={'pk': pk})
class VotacaoNominalView(FormMixin, SessaoCrud.CrudDetailView):
class VotacaoNominalView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
template_name = 'sessao/votacao/nominal.html'
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
ordem_id = kwargs['mid']
@ -1101,8 +1301,11 @@ class VotacaoNominalView(FormMixin, SessaoCrud.CrudDetailView):
kwargs={'pk': pk})
class VotacaoNominalEditView(FormMixin, SessaoCrud.CrudDetailView):
class VotacaoNominalEditView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
template_name = 'sessao/votacao/nominal_edit.html'
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
context = {}
@ -1178,8 +1381,11 @@ class VotacaoNominalEditView(FormMixin, SessaoCrud.CrudDetailView):
kwargs={'pk': pk})
class VotacaoNominalExpedienteView(FormMixin, SessaoCrud.CrudDetailView):
class VotacaoNominalExpedienteView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
template_name = 'sessao/votacao/nominal.html'
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
expediente_id = kwargs['mid']
@ -1301,8 +1507,11 @@ class VotacaoNominalExpedienteView(FormMixin, SessaoCrud.CrudDetailView):
kwargs={'pk': pk})
class VotacaoNominalExpedienteEditView(FormMixin, SessaoCrud.CrudDetailView):
class VotacaoNominalExpedienteEditView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
template_name = 'sessao/votacao/nominal_edit.html'
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
context = {}
@ -1377,7 +1586,9 @@ class VotacaoNominalExpedienteEditView(FormMixin, SessaoCrud.CrudDetailView):
kwargs={'pk': pk})
class VotacaoExpedienteView(FormMixin, SessaoCrud.CrudDetailView):
class VotacaoExpedienteView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
'''
Votação Simbólica e Secreta
@ -1385,6 +1596,7 @@ class VotacaoExpedienteView(FormMixin, SessaoCrud.CrudDetailView):
template_name = 'sessao/votacao/votacao.html'
form_class = VotacaoForm
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -1498,7 +1710,9 @@ class VotacaoExpedienteView(FormMixin, SessaoCrud.CrudDetailView):
kwargs={'pk': pk})
class VotacaoExpedienteEditView(FormMixin, SessaoCrud.CrudDetailView):
class VotacaoExpedienteEditView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
'''
Votação Simbólica e Secreta
@ -1506,6 +1720,7 @@ class VotacaoExpedienteEditView(FormMixin, SessaoCrud.CrudDetailView):
template_name = 'sessao/votacao/votacao_edit.html'
form_class = VotacaoEditForm
permission_required = permissoes_sessao()
def get_success_url(self):
pk = self.kwargs['pk']

2
sapl/settings.py

@ -38,6 +38,7 @@ LOGIN_URL = '/login/?next='
# SAPL business apps in dependency order
SAPL_APPS = (
'sapl.base',
'sapl.crud',
'sapl.parlamentares',
'sapl.comissoes',
'sapl.materia',
@ -129,6 +130,7 @@ EMAIL_PORT = config('EMAIL_PORT', cast=int, default=587)
EMAIL_HOST_USER = config('EMAIL_HOST_USER', default='')
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', default='')
EMAIL_USE_TLS = config('EMAIL_USE_TLS', cast=bool, default=True)
EMAIL_SEND_USER = config('EMAIL_SEND_USER', cast=str, default='')
MAX_DOC_UPLOAD_SIZE = 5 * 1024 * 1024 # 5MB
MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB

19
sapl/templates/base.html

@ -1,4 +1,5 @@
{% 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]><!-->
@ -45,18 +46,19 @@
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Institucional <span class="caret"></span></a>
<ul class="dropdown-menu">
{% if user.is_authenticated %}
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'sapl.parlamentares:mesa_diretora' %}">Mesa Diretora</a></li>
{% endif %}
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'sapl.comissoes:comissao_list' %}">Comissões</a></li>
<!-- <li class="nav__sub-item"><a class="nav__sub-link" href="#">Bancadas</a></li> -->
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'sapl.parlamentares:parlamentar_list' %}">Parlamentares</a></li>
</ul>
</li>
{% if perms.protocoloadm %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Protocolo <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'sapl.protocoloadm:protocolo' %}">Pesquisar Protocolo</a></li>
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'sapl.protocoloadm:pesq_doc_adm' %}">Pesquisar Documento Administrativo</a></li>
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'sapl.materia:receber-proposicao' %}">Receber Proposições</a></li>
<!-- <li class="nav__sub-item"><a class="nav__sub-link" href="/materia">Protocolo Legislativo</a></li> -->
{# <li class="nav__sub-item"><a class="nav__sub-link" href="">Protocolo Geral</a></li> #}
@ -64,6 +66,16 @@
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Documentos Administrativos <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'sapl.protocoloadm:pesq_doc_adm' %}">Pesquisar Documento Administrativo</a></li>
</ul>
</li>
<li class="dropdown">
{% endif %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Atividade Legislativa <span class="caret"></span></a>
<ul class="dropdown-menu">
@ -86,7 +98,7 @@
<!-- <li class="nav__sub-item"><a class="nav__sub-link" href="#">Índice de Assuntos</a></li> -->
</ul>
</li>
{% if user|ver_menu_sistema_perm %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Sistema <span class="caret"></span></a>
<ul class="dropdown-menu">
@ -101,6 +113,7 @@
<li class="nav__sub-item"><a class="nav__sub-link" href="#">Troca de Senha</a></li> -->
</ul>
</li>
{% endif %}
</ul>
<ul class="nav navbar-nav navbar-right" id="autenticacao">

7
sapl/templates/confirma_email.html

@ -0,0 +1,7 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% block detail_content %}
Sua conta foi confirmada via e-mail. Clique <a href="{% url 'base:login' %}">aqui</a> para fazer seu login.
{% endblock %}

6
sapl/templates/crud/detail.html

@ -1,13 +1,19 @@
{% extends "base.html" %}
{% load i18n %}
{% load common_tags %}
{% block base_content %}
<div class="clearfix">
{% block actions %}
<div class="actions btn-group pull-right" role="group">
{% if perms|get_change_perm:view %}
<a href="{{ view.update_url }}" class="btn btn-default">{% trans 'Editar' %}</a>
{% endif %}
{% if perms|get_delete_perm:view %}
<a href="{{ view.delete_url }}" class="btn btn-default">{% trans 'Excluir' %}</a>
{% endif %}
</div>
{% endblock actions %}
</div>

7
sapl/templates/crud/list.html

@ -1,14 +1,17 @@
{% extends "base.html" %}
{% load i18n %}
{% load common_tags %}
{% block base_content %}
<div class="actions btn-group pull-right" role="group">
<div class="actions btn-group pull-right" role="group">
{% if perms|get_add_perm:view %}
<a href="{{ view.create_url }}" class="btn btn-default">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar {{ verbose_name }} {% endblocktrans %}
</a>
{% endif %}
{% block more_buttons %}{% endblock more_buttons %}
</div>
</div>
<br/><br/>
{% block extra_content %} {% endblock %}

12
sapl/templates/materia/layouts.yaml

@ -54,7 +54,14 @@ TipoAutor:
Autor:
{% trans 'Autor' %}:
- tipo:3 nome
- username
- username:6 cargo
AutorCreate:
Autor:
- tipo:3 nome
- username:4 senha:4 senha_confirma:4
- email:6 confirma_email:6
- cargo:4 parlamentar:4 comissao:4
Autoria:
{% trans 'Autoria' %}:
@ -91,8 +98,7 @@ ProposicaoCreate:
{% trans 'Proposição' %}:
- tipo data_envio
- descricao
{% trans 'Materia' %}:
- tipo_materia numero_materia ano_materia
{% trans 'Complemento' %}:
- texto_original

4
sapl/templates/materia/materialegislativa_filter.html

@ -9,7 +9,7 @@
{% block detail_content %}
{% if filter_url %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'sapl.materia:pesquisar_materia' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
<a href="{% url 'materia:pesquisar_materia' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
{% endif %}
@ -33,7 +33,7 @@
{% for m in page_obj %}
<tr>
<td>
<strong><a href="{% url 'sapl.materia:materialegislativa_detail' m.id %}">{{m.tipo.sigla}} {{m.numero}}/{{m.ano}} - {{m.tipo}}</strong></a></br>
<strong><a href="{% url 'materia:materialegislativa_detail' m.id %}">{{m.tipo.sigla}} {{m.numero}}/{{m.ano}} - {{m.tipo}}</strong></a></br>
<strong>Autores:</strong>
{% for a in m.autoria_set.all %}
{% if not forloop.first %}

20
sapl/templates/materia/proposicao_detail.html

@ -1,14 +1,28 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% load common_tags %}
{% block actions %}
<div class="actions btn-group pull-right" role="group">
{% if proposicao.data_envio and not proposicao.data_recebimento %}
<<<<<<< HEAD
{% if proposicao.data_envio %}
{% if perms|get_change_perm:view %}
<a href="{{ view.update_url }}" class="btn btn-default">{% trans 'Editar Proposição' %}</a>
{% endif %}
{% if perms|get_delete_perm:view %}
<a href="{{ view.delete_url }}" class="btn btn-default">{% trans 'Retornar Proposição Enviada' %}</a>
{% elif not proposicao.data_envio %}
<a href="{{ view.update_url }}" class="btn btn-default">{% trans 'Enviar Proposição' %}</a>
{% endif %}
{% else %}
{% if perms|get_change_perm:view %}
<a href="{{ view.update_url }}" class="btn btn-default">{% trans 'Enviar/Editar Proposição' %}</a>
{% endif %}
{% if perms|get_delete_perm:view %}
<a href="{{ view.delete_url }}" class="btn btn-default">{% trans 'Excluir Proposição' %}</a>
{% endif %}
{% endif %}
</div>
{% endblock actions %}
{% block extra_msg %}

8
sapl/templates/mesa_diretora/mesa_diretora.html

@ -47,10 +47,16 @@
<div class="col-md-4" align="center">
<br /><br />
{% if cargos_vagos %} <input type="submit" name="Incluir" Value="Incluir" class="btn btn-primary" /> {% endif %}
{% if cargos_vagos %}
{% if perms.parlamentares.add_cargomesa or perms.parlamentares.add_composicaomesa %}
<input type="submit" name="Incluir" Value="Incluir" class="btn btn-primary" />
{% endif %}
{% endif %}
<br />
<br />
{% if perms.parlamentares.add_cargomesa or perms.parlamentares.add_composicaomesa %}
<input type="submit" name="Excluir" Value="Excluir" class="btn btn-danger" />
{% endif %}
</div>
{% if cargos_vagos %}

4
sapl/templates/norma/list_pesquisa.html

@ -1,10 +1,14 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% load common_tags %}
{% block actions %}{% endblock %}
{% block detail_content %}
<div class="actions btn-group pull-right" role="group">
{% if perms.norma.add_normajuridica %}
<a href="{% url 'sapl.norma:normajuridica_create' %}" class="btn btn-default">Adicionar Norma Jurídica</a>
{% endif %}
</div>
<br /><br /><br />
{% if object_list %}

3
sapl/templates/norma/pesquisa.html

@ -1,12 +1,15 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% load common_tags %}
{% block base_content %}
{% block actions %}
<div class="actions btn-group pull-right" role="group">
{% if perms.norma.add_normajuridica %}
<a href="{% url 'sapl.norma:normajuridica_create' %}" class="btn btn-default">{% trans 'Adicionar Norma Juridica' %}</a>
{% endif %}
</div>
<br /><br />
{% endblock %}

73
sapl/templates/parlamentares/parlamentar_perfil_publico.html

@ -0,0 +1,73 @@
{% extends "base.html" %}
{% load i18n %}
{% load common_tags %}
{% block base_content %}
<div class="clearfix">
{% block actions %}
{% endblock actions %}
</div>
{% block detail_content %}
<p class="legend"></p>
<div class="row-fluid">
{% if parlamentar.fotografia %}
<div class="col-sm-3">
<div id="div_fotografia" class="form-group">
<div class="controls">
<img class="img-responsive" src="{{ object.fotografia.url }}">
</div>
</div>
</div>
{% endif %}
<div class="col-sm-8">
<div id="div_nome" class="form-group">
<p><b>Nome Completo: </b> &nbsp {{object.nome_completo}}</p>
</div>
</div>
<div class="col-sm-8">
<div id="div_data_nascimento" class="form-group">
<p><b>Partido: </b> &nbsp {{object.filiacao_set.first.partido|default_if_none:"Não informado"}}</p>
</div>
</div>
<div class="col-sm-8">
<div id="div_data_nascimento" class="form-group">
<p><b>Data de Nascimento: </b> &nbsp {{object.data_nascimento|default_if_none:"Não informado"}}</p>
</div>
</div>
<div class="col-sm-8">
<div id="div_data_nascimento" class="form-group">
<p><b>Telefone: </b> &nbsp {{object.telefone|default_if_none:"Não informado"}}</p>
</div>
</div>
<div class="col-sm-8">
<div id="div_data_nascimento" class="form-group">
<p><b>E-mail: </b> &nbsp {{object.email|default_if_none:"Não informado"}}</p>
</div>
</div>
<div class="col-sm-8">
<div id="div_data_nascimento" class="form-group">
<p><b>Número do Gabinete: </b> &nbsp {{object.numero_gab_parlamentar|default_if_none:"Não informado"}}</p>
</div>
</div>
<div class="col-sm-8">
<div id="div_data_nascimento" class="form-group">
<p><b>Fax: </b> &nbsp {{object.numero_gab_parlamentar|default_if_none:"Não informado"}}</p>
</div>
</div>
</div>
{% endblock detail_content %}
{% endblock base_content %}

9
sapl/templates/protocoloadm/documentoadministrativo_detail.html

@ -0,0 +1,9 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% block actions %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'protocoloadm:tramitacaoadministrativo_list' object.pk %}" class="btn btn-default">{% trans 'Tramitações' %}</a>
<a href="{{ view.update_url }}" class="btn btn-default">{% trans 'Editar' %}</a>
<a href="{{ view.delete_url }}" class="btn btn-default">{% trans 'Excluir' %}</a>
</div>
{% endblock actions %}

26
sapl/templates/protocoloadm/documentoadministrativo_filter.html

@ -1,16 +1,34 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block actions %}{% endblock %}
{% load common_tags %}
{% block sections_nav %} {% endblock %}
{% block actions %}
<h1><b>Documentos Administrativos</b></h1>
<div class="actions btn-group pull-right" role="group">
{% if perms|get_add_perm:view %}
<a href="docadm/create" class="btn btn-default">{% trans 'Adicionar Documento Administrativo' %}</a>
{% endif %}
</div>
{% if filter_url %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'protocoloadm:pesq_doc_adm' %}" class="btn btn-default">{% trans 'Fazer Nova Pesquisa' %}</a>
</div>
{% endif %}
{% endblock actions %}
{% block detail_content %}
<h1><b>Pesquisar Documento Administrativo</b></h1>
<br></br>
{% if not filter_url %}
{% crispy filter.form %}
{% endif %}
{% if filter_url %}
<p></p>
<table class="table table-striped table-bordered">
@ -28,7 +46,7 @@
<tr>
<td>
<strong><a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' d.id %}">{{d.tipo.sigla}} {{d.numero}}/{{d.ano}} - {{d.tipo}}</strong></a></br>
<strong><a href="{% url 'protocoloadm:documentoadministrativo_detail' d.id %}">{{d.tipo.sigla}} {{d.numero}}/{{d.ano}} - {{d.tipo}}</strong></a></br>
<strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não Informado"}}</br>
<strong>Assunto:</strong>&nbsp;{{ d.assunto|safe }}</br>
<p></p>

6
sapl/templates/protocoloadm/protocolo_filter.html

@ -10,7 +10,7 @@
<br></br>
{% if filter_url %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'sapl.protocoloadm:protocolo' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
<a href="{% url 'protocoloadm:protocolo' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
{% endif %}
@ -37,12 +37,12 @@
<tr>
<td>
<strong>Protocolo:
<a href="{% url 'sapl.protocoloadm:protocolo_mostrar' p.numero p.ano %}">
<a href="{% url 'protocoloadm:protocolo_mostrar' p.numero p.ano %}">
{{ p.numero|stringformat:'06d' }}/{{ p.ano }}
</a></strong>
&nbsp;&nbsp;<strong>-</strong>&nbsp;&nbsp;
<a href="{% url 'sapl.relatorios:relatorio_etiqueta_protocolo' p.numero p.ano %}">
<a href="{% url 'relatorios:relatorio_etiqueta_protocolo' p.numero p.ano %}">
<img src="{% static 'img/etiqueta.png' %}" alt="Etiqueta Individual">
</a></br>

9
sapl/templates/protocoloadm/protocolo_pesquisa.html

@ -1,9 +0,0 @@
{% extends "protocoloadm/protocoloadm_detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block detail_content %}
<legend>Pesquisa Avançada</legend>
{% crispy form %}
</fieldset>
{% endblock detail_content %}

6
sapl/templates/protocoloadm/protocoloadm_detail.html

@ -2,8 +2,8 @@
{% load i18n %}
{% block actions %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'sapl.protocoloadm:protocolar_doc' %}" class="btn btn-default">{% trans 'Protocolar Documento' %}</a>
<a href="{% url 'sapl.protocoloadm:protocolar_mat' %}" class="btn btn-default">{% trans 'Protocolar Matéria' %}</a>
<a href="{% url 'sapl.protocoloadm:anular_protocolo' %}" class="btn btn-default">{% trans 'Anular Protocolo' %}</a>
<a href="{% url 'protocoloadm:protocolar_doc' %}" class="btn btn-default">{% trans 'Protocolar Documento' %}</a>
<a href="{% url 'protocoloadm:protocolar_mat' %}" class="btn btn-default">{% trans 'Protocolar Matéria' %}</a>
<a href="{% url 'protocoloadm:anular_protocolo' %}" class="btn btn-default">{% trans 'Anular Protocolo' %}</a>
</div>
{% endblock actions %}

40
sapl/templates/protocoloadm/tramitacao.html

@ -1,40 +0,0 @@
{% extends "protocoloadm/protocoloadm_detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block detail_content %}
<fieldset>
Tipo: {{documento.tipo.sigla}} Número: {{documento.numero}} Ano: {{documento.ano}}</br>
Assunto: {{documento.assunto}}
</fieldset>
<fieldset>
<h2>Tramitação</h2>
{% if tramitacoes %}
<table>
<tr>
<td>Data Ação</td>
<td>Origem</td>
<td>Destino</td>
<td>Status</td>
<td>Excluir</td>
</tr>
{% for t in tramitacoes %}
<tr>
<td><a href="{% url 'sapl.protocoloadm:tramitacao_edit' t.id %}">{{t.data_encaminhamento|date:"d/m/Y"}}</a></td>
<td>{{t.unidade_tramitacao_local}}</td>
<td>{{t.unidade_tramitacao_destino}}</td>
<td>{{t.status.sigla}}</td>
<td><a href="{% url 'sapl.protocoloadm:tramitacao_delete' documento.id t.id %}">Excluir</ad></td>
</tr>
{% endfor %}
</table>
{% else %}
<strong>Nenhuma tramitação cadastrada para este documento.</strong>
{% endif %}
</br>
<a href="{% url 'sapl.protocoloadm:tramitacao_incluir' documento.id %}" class="button primary">Incluir Tramitação</a>
</fieldset>
{% endblock detail_content %}

15
sapl/templates/protocoloadm/tramitacao_edit.html

@ -1,15 +0,0 @@
{% extends "protocoloadm/protocoloadm_detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block detail_content %}
<fieldset>
Tipo: {{documento.tipo.sigla}} Número: {{documento.numero}} Ano: {{documento.ano}}</br>
Assunto: {{documento.assunto}}
</fieldset>
<h2>Tramitação Edit</h2>
{% crispy form %}
{% endblock detail_content %}

14
sapl/templates/protocoloadm/tramitacao_incluir.html

@ -1,14 +0,0 @@
{% extends "protocoloadm/protocoloadm_detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block detail_content %}
<fieldset>
Tipo: {{documento.tipo.sigla}} Número: {{documento.numero}} Ano: {{documento.ano}}</br>
Assunto: {{documento.assunto}}
</fieldset>
<h2>Tramitação</h2>
{% crispy form %}
{% endblock detail_content %}

9
sapl/templates/protocoloadm/tramitacaoadministrativo_detail.html

@ -0,0 +1,9 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% block actions %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'protocoloadm:documentoadministrativo_detail' root_pk %}" class="btn btn-default">{% trans 'Início' %}</a>
<a href="{{ view.update_url }}" class="btn btn-default">{% trans 'Editar' %}</a>
<a href="{{ view.delete_url }}" class="btn btn-default">{% trans 'Excluir' %}</a>
</div>
{% endblock actions %}

84
sapl/templates/sessao/materia_ordemdia_list.html

@ -1,84 +0,0 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% block detail_content %}
{% if form.errors %}
<div class="alert-box alert">
<ul>
{% for field in form %}
{% if field.errors %}
{% if field.label == 'votacao_aberta' %}
<li>Já existe uma matéria com a votação aberta!<br />
Para abrir outra, termine ou feche a votação existente!</li>
{% endif %}
{% endif %}
{% endfor %}
</ul>
</div>
{% endif %}
Matérias da Ordem do Dia
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr>
<th>Matéria</th>
<th>Ementa</th>
<th>Resultado da Votação</th>
</tr>
</thead>
{% for m in materias_ordem %}
<tr>
<td>
{{m.numero}} - <a href="{% url 'sapl.sessao:materiaordemdia_edit' m.pk m.oid %}">{{m.titulo}}</a>
&nbsp;
</br>
<strong>Autor{{m.autor|length|pluralize:"es"}}</strong>: {{m.autor|join:', '}}
</td>
<td>{{m.ementa|safe}}</td>
<td>
{% if m.resultado %}
{% if m.tipo_votacao == 1 %}
<b><a href="{% url 'sapl.sessao:votacaosimbolicaedit' m.pk m.oid m.ordem_id %}">{{m.resultado}}</a></b>
{% elif m.tipo_votacao == 2 %}
<b><a href="{% url 'sapl.sessao:votacaonominaledit' m.pk m.oid m.ordem_id %}">{{m.resultado}}</a></b>
{% elif m.tipo_votacao == 3%}
<b><a href="{% url 'sapl.sessao:votacaosecretaedit' m.pk m.oid m.ordem_id %}">{{m.resultado}}</a></b>
{% endif %}
{% else %}
Matéria não votada <br />
{% if m.votacao_aberta %}
{% if m.tipo_votacao == 1 %}
<b><a href="{% url 'sapl.sessao:votacaosimbolica' m.pk m.oid m.ordem_id %}">Registrar Votação</a></b>
{% elif m.tipo_votacao == 2 %}
<b><a href="{% url 'sapl.sessao:votacaonominal' m.pk m.oid m.ordem_id %}">Registrar Votação</a></b>
{% elif m.tipo_votacao == 3%}
<b><a href="{% url 'sapl.sessao:votacaosecreta' m.pk m.oid m.ordem_id %}">Registrar Votação</a></b>
{% endif %}
{% else %}
<form method="POST" action="{% url 'sapl.sessao:materiaordemdia_list' object.pk %}">
{% csrf_token %}
<input type="hidden" id="ordem_id" name="ordem_id" value="{{ m.ordem_id }}">
<input type="submit" id="abrir-votacao" name="abrir-votacao" value="Abrir Votação" class="btn btn-primary">
</form>
{% endif %}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</br>
<form method="POST" action="{% url 'sapl.sessao:materiaordemdia_list' object.pk %}">
{% csrf_token %}
<input type="hidden" name="error_message" id="error_message" />
<a href="{% url 'sapl.sessao:materiaordemdia_create' object.pk %}" class="btn btn-primary">{% trans 'Adicionar Matérias' %}</a>
&nbsp;&nbsp;&nbsp;
<input type="submit" id="materia_reorder" name="materia_reorder" value="Reordenar Matérias da Ordem do Dia" class="btn btn-primary" />
&nbsp;&nbsp;&nbsp;
<a href="{% url 'sapl.sessao:adicionar_varias_materias_ordem_dia' object.pk %}" value="Incluir Várias Matérias" class="btn btn-primary">{% trans 'Adicionar Várias Matérias' %}</a>
</form>
{% endblock detail_content %}

92
sapl/utils.py

@ -6,6 +6,8 @@ import magic
from django.apps import apps
from django.conf import settings
from django.contrib import admin
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from floppyforms import ClearableFileInput
@ -202,7 +204,6 @@ def fabrica_validador_de_tipos_de_arquivo(lista, nome):
def restringe_tipos_de_arquivo(value):
mime = magic.from_buffer(value.read(), mime=True)
mime = mime.decode()
if mime not in lista:
raise ValidationError(_('Tipo de arquivo não suportado'))
# o nome é importante para as migrations
@ -221,6 +222,95 @@ def intervalos_tem_intersecao(a_inicio, a_fim, b_inicio, b_fim):
return maior_inicio <= menor_fim
def permissoes_materia():
lista_permissoes = []
cts = ContentType.objects.filter(app_label='materia')
perms_materia = list(Permission.objects.filter(content_type__in=cts))
for p in perms_materia:
lista_permissoes.append('materia.' + p.codename)
return set(lista_permissoes)
def permissoes_comissoes():
lista_permissoes = []
cts = ContentType.objects.filter(app_label='comissoes')
perms_comissoes = list(Permission.objects.filter(content_type__in=cts))
for p in perms_comissoes:
lista_permissoes.append('comissoes.' + p.codename)
return set(lista_permissoes)
def permissoes_norma():
lista_permissoes = []
cts = ContentType.objects.filter(app_label='norma')
perms_norma = list(Permission.objects.filter(content_type__in=cts))
for p in perms_norma:
lista_permissoes.append('norma.' + p.codename)
return set(lista_permissoes)
def permissoes_parlamentares():
lista_permissoes = []
cts = ContentType.objects.filter(app_label='parlamentares')
perms_parlamentares = list(Permission.objects.filter(content_type__in=cts))
for p in perms_parlamentares:
lista_permissoes.append('parlamentares.' + p.codename)
return set(lista_permissoes)
def permissoes_protocoloadm():
lista_permissoes = []
perms_protocolo = Permission.objects.filter(
group__name='Operador de Protocolo Administrativo')
for p in perms_protocolo:
lista_permissoes.append('protocoloadm.' + p.codename)
return set(lista_permissoes)
def permissoes_adm():
lista_permissoes = []
perms_adm = Permission.objects.filter(
group__name='Operador Administrativo')
for p in perms_adm:
lista_permissoes.append('protocoloadm.' + p.codename)
return set(lista_permissoes)
def permissoes_sessao():
lista_permissoes = []
perms_sessao = list(Permission.objects.filter(
group__name='Operador de Sessão Plenária'))
for p in perms_sessao:
lista_permissoes.append('sessao.' + p.codename)
return set(lista_permissoes)
def permissoes_painel():
lista_permissoes = []
perms_painel = list(Permission.objects.filter(
group__name='Operador de Painel Eletrônico'))
for p in perms_painel:
lista_permissoes.append('painel.' + p.codename)
return set(lista_permissoes)
def permissao_tb_aux(self):
u = self.request.user
if u.groups.filter(name='Operador Geral').exists() or u.is_superuser:
return True
else:
return False
def permissoes_autor():
lista_permissoes = []
perms_autor = list(Permission.objects.filter(
group__name='Autor'))
for p in perms_autor:
lista_permissoes.append('materia.' + p.codename)
return set(lista_permissoes)
def gerar_hash_arquivo(arquivo, pk, block_size=2**20):
md5 = hashlib.md5()
arq = open(arquivo, 'rb')

114
scripts/inicializa_grupos_autorizacoes.py

@ -0,0 +1,114 @@
from django.apps import apps
from django.contrib.auth.models import Group, Permission, User
from django.contrib.contenttypes.models import ContentType
def cria_ou_reseta_grupo(nome):
grupo = Group.objects.get_or_create(name=nome)[0]
for p in list(grupo.permissions.all()):
grupo.permissions.remove(p)
return grupo
def cria_usuario(nome, grupo):
nome_usuario = nome
usuario = User.objects.get_or_create(username=nome_usuario)[0]
usuario.set_password('interlegis')
usuario.save()
grupo.user_set.add(usuario)
def cria_grupos_permissoes():
nomes_apps = ['base', 'parlamentares', 'comissoes',
'materia', 'norma', 'sessao', 'painel']
permissoes = {app: list(Permission.objects.filter(
content_type__in=ContentType.objects.filter(app_label=app)))
for app in nomes_apps}
# permissoes específicas para protocolo e documento administrativo
cts = ContentType.objects.filter(app_label='protocoloadm')
# documento administrativo
permissoes['documento_administrativo'] = list(
Permission.objects.filter(content_type__in=cts))
nome_grupo = 'Operador Administrativo'
grupo = cria_ou_reseta_grupo(nome_grupo)
for p in permissoes['documento_administrativo']:
grupo.permissions.add(p)
nome_usuario = 'operador_administrativo'
cria_usuario(nome_usuario, grupo)
# prolocolo administrativo
cts = cts.exclude(model__icontains='tramitacao').exclude(
model__icontains='documentoadministrativo')
permissoes['protocoloadm'] = list(
Permission.objects.filter(content_type__in=cts))
nome_grupo = 'Operador de Protocolo Administrativo'
grupo = cria_ou_reseta_grupo(nome_grupo)
for p in permissoes['protocoloadm']:
grupo.permissions.add(p)
nome_usuario = 'operador_protocoloadm'
cria_usuario(nome_usuario, grupo)
# permissoes do base
cts = ContentType.objects.filter(app_label='base')
permissoes['base'] = list(
Permission.objects.filter(content_type__in=cts))
for nome_app in nomes_apps:
if nome_app not in {'base', 'parlamentares'}:
# Elimina casos especificos
# Cria Grupo
nome_grupo = 'Operador de %s' % apps.get_app_config(
nome_app).verbose_name
grupo = cria_ou_reseta_grupo(nome_grupo)
# Elimina o acesso a proposicoes pelo Operador de Matérias
if nome_app == 'materia':
cts = ContentType.objects.filter(
app_label='materia').exclude(model='proposicao')
permissoes['materia'] = list(
Permission.objects.filter(content_type__in=cts))
# Configura as permissoes
for p in permissoes[nome_app]:
grupo.permissions.add(p)
# Cria o Usuario
nome_usuario = 'operador_%s' % nome_app
usuario = User.objects.get_or_create(username=nome_usuario)[0]
usuario.set_password('interlegis')
usuario.save()
grupo.user_set.add(usuario)
# Operador Geral
grupo_geral = cria_ou_reseta_grupo('Operador Geral')
for lista in permissoes.values():
for p in lista:
grupo_geral.permissions.add(p)
nome_usuario = 'operador_geral'
cria_usuario(nome_usuario, grupo_geral)
# Autor
perms_autor = []
perms_autor.append(Permission.objects.get(name='Can add Proposição'))
perms_autor.append(Permission.objects.get(name='Can change Proposição'))
perms_autor.append(Permission.objects.get(name='Can delete Proposição'))
# Configura Permissoes Autor
grupo = cria_ou_reseta_grupo('Autor')
for p in perms_autor:
grupo.permissions.add(p)
nome_usuario = 'operador_autor'
cria_usuario(nome_usuario, grupo_geral)
if __name__ == '__main__':
cria_grupos_permissoes()

47
scripts/test_inicializa_grupos_autorizacoes.py

@ -0,0 +1,47 @@
import pytest
from django.apps import apps
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from inicializa_grupos_autorizacoes import cria_grupos_permissoes
pytestmark = pytest.mark.django_db
apps_com_permissao_padrao = [
'comissoes', 'norma', 'sessao', 'painel']
@pytest.mark.parametrize('app_label', apps_com_permissao_padrao)
def test_grupo_padrao_tem_permissoes_sobre_todo_o_app(app_label):
app = apps.get_app_config(app_label)
# código testado
cria_grupos_permissoes()
def gerar_permissoes(app):
for model in app.get_models():
for op in ['add', 'change', 'delete']:
yield model, 'Can %s %s' % (op, model._meta.verbose_name)
grupo = Group.objects.get(name='Operador de %s' % app.verbose_name)
esperado = set(gerar_permissoes(app))
real = set((p.content_type.model_class(), p.name)
for p in grupo.permissions.all())
assert real == esperado
@pytest.mark.parametrize('app_label', apps_com_permissao_padrao)
def test_permissoes_extras_sao_apagadas(app_label):
app = apps.get_app_config(app_label)
grupo = Group.objects.create(name='Operador de %s' % app.verbose_name)
permissao_errada = Permission.objects.create(
name='STUB', content_type=ContentType.objects.first())
grupo.permissions.add(permissao_errada)
# código testado
cria_grupos_permissoes()
assert not grupo.permissions.filter(id=permissao_errada.id).exists()
Loading…
Cancel
Save