diff --git a/sapl/base/migrations/0019_auto_20160928_1951.py b/sapl/base/migrations/0019_auto_20160928_1951.py
new file mode 100644
index 000000000..9c61f7062
--- /dev/null
+++ b/sapl/base/migrations/0019_auto_20160928_1951.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.7 on 2016-09-28 22:51
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('base', '0018_auto_20160919_1333'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='appconfig',
+ options={'permissions': (('menu_sistemas', 'Renderizar Menu Sistemas'), ('view_tabelas_auxiliares', 'Visualizar Tabelas Auxiliares')), 'verbose_name': 'Configurações da Aplicação', 'verbose_name_plural': 'Configurações da Aplicação'},
+ ),
+ ]
diff --git a/sapl/base/models.py b/sapl/base/models.py
index 86a685ef4..cc2004455 100644
--- a/sapl/base/models.py
+++ b/sapl/base/models.py
@@ -1,10 +1,18 @@
+from builtins import LookupError
+
+from django.apps import apps
+from django.contrib.auth.management import _get_all_permissions
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
-from django.db import models
+from django.core import exceptions
+from django.db import models, router
+from django.db.utils import DEFAULT_DB_ALIAS
+from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _
from sapl.utils import UF, YES_NO_CHOICES
+
TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensivo')),
('R', _('Restritivo')))
@@ -94,7 +102,106 @@ class AppConfig(models.Model):
class Meta:
verbose_name = _('Configurações da Aplicação')
verbose_name_plural = _('Configurações da Aplicação')
+ permissions = (
+ ('menu_sistemas', _('Renderizar Menu Sistemas')),
+ ('view_tabelas_auxiliares', _('Visualizar Tabelas Auxiliares')),
+ )
def __str__(self):
return _('Configurações da Aplicação - %(id)s') % {
'id': self.id}
+
+
+def create_proxy_permissions(
+ app_config, verbosity=2, interactive=True,
+ using=DEFAULT_DB_ALIAS, **kwargs):
+ if not app_config.models_module:
+ return
+
+ # print(app_config)
+
+ try:
+ Permission = apps.get_model('auth', 'Permission')
+ except LookupError:
+ return
+
+ if not router.allow_migrate_model(using, Permission):
+ return
+
+ from django.contrib.contenttypes.models import ContentType
+
+ permission_name_max_length = Permission._meta.get_field('name').max_length
+
+ # This will hold the permissions we're looking for as
+ # (content_type, (codename, name))
+ searched_perms = list()
+ # The codenames and ctypes that should exist.
+ ctypes = set()
+ for klass in list(app_config.get_models()):
+ opts = klass._meta
+ permissions = (
+ ("list_" + opts.model_name,
+ string_concat(
+ _('Visualizaçao da lista de'), ' ',
+ opts.verbose_name_plural)),
+ ("detail_" + opts.model_name,
+ string_concat(
+ _('Visualização dos detalhes de'), ' ',
+ opts.verbose_name_plural)),
+ )
+ opts.permissions = tuple(
+ set(list(permissions) + list(opts.permissions)))
+
+ if opts.proxy:
+ # Force looking up the content types in the current database
+ # before creating foreign keys to them.
+ app_label, model = opts.app_label, opts.model_name
+
+ try:
+ ctype = ContentType.objects.db_manager(
+ using).get_by_natural_key(app_label, model)
+ except:
+ ctype = ContentType.objects.db_manager(
+ using).create(app_label=app_label, model=model)
+ else:
+ ctype = ContentType.objects.db_manager(using).get_for_model(klass)
+
+ ctypes.add(ctype)
+ for perm in _get_all_permissions(klass._meta, ctype):
+ searched_perms.append((ctype, perm))
+
+ # Find all the Permissions that have a content_type for a model we're
+ # looking for. We don't need to check for codenames since we already have
+ # a list of the ones we're going to create.
+ all_perms = set(Permission.objects.using(using).filter(
+ content_type__in=ctypes,
+ ).values_list(
+ "content_type", "codename"
+ ))
+
+ perms = [
+ Permission(codename=codename, name=name, content_type=ct)
+ for ct, (codename, name) in searched_perms
+ if (ct.pk, codename) not in all_perms
+ ]
+ # Validate the permissions before bulk_creation to avoid cryptic database
+ # error when the name is longer than 255 characters
+ for perm in perms:
+ if len(perm.name) > permission_name_max_length:
+ raise exceptions.ValidationError(
+ 'The permission name %s of %s.%s '
+ 'is longer than %s characters' % (
+ perm.name,
+ perm.content_type.app_label,
+ perm.content_type.model,
+ permission_name_max_length,
+ )
+ )
+ Permission.objects.using(using).bulk_create(perms)
+ if verbosity >= 2:
+ for perm in perms:
+ print("Adding permission '%s'" % perm)
+
+models.signals.post_migrate.connect(
+ receiver=create_proxy_permissions,
+ dispatch_uid="django.contrib.auth.management.create_permissions")
\ No newline at end of file
diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py
index 30db1a92f..c926a485d 100644
--- a/sapl/base/templatetags/common_tags.py
+++ b/sapl/base/templatetags/common_tags.py
@@ -126,3 +126,15 @@ def get_config_not_exists(user):
return True
else:
return False
+
+
+@register.filter
+def str2intabs(value):
+ if not isinstance(value, str):
+ return ''
+ try:
+ v = int(value)
+ v = abs(v)
+ return v
+ except:
+ return ''
diff --git a/sapl/base/templatetags/menus.py b/sapl/base/templatetags/menus.py
index 2f121d3c7..d5a398faf 100644
--- a/sapl/base/templatetags/menus.py
+++ b/sapl/base/templatetags/menus.py
@@ -32,8 +32,6 @@ def subnav(context, path=None):
execução deste subnav. Inicialmente, a maneira mais prática encontrada
de isolar foi com o teste abaixo.
"""
- if 'sistema' in request.path:
- return
rm = request.resolver_match
app_template = rm.app_name.rsplit('.', 1)[-1]
@@ -45,6 +43,9 @@ def subnav(context, path=None):
else:
yaml_path = '%s/%s' % (app_template, 'subnav.yaml')
+ if not yaml_path:
+ return
+
try:
"""
Por padrão, são carragados dois Loaders,
diff --git a/sapl/base/urls.py b/sapl/base/urls.py
index 784649cfd..1cfb5a395 100644
--- a/sapl/base/urls.py
+++ b/sapl/base/urls.py
@@ -1,5 +1,6 @@
from django.conf.urls import include, url
from django.contrib.auth import views
+from django.contrib.auth.decorators import permission_required
from django.views.generic.base import TemplateView
from .apps import AppConfig
@@ -15,7 +16,9 @@ app_name = AppConfig.name
urlpatterns = [
- url(r'^sistema/', TemplateView.as_view(template_name='sistema.html')),
+ url(r'^sistema/', permission_required('base.view_tabelas_auxiliares')
+ (TemplateView.as_view(template_name='sistema.html'))),
+
url(r'^ajuda/', TemplateView.as_view(template_name='ajuda.html')),
url(r'^relatorios/', TemplateView.as_view(
template_name='base/relatorios_list.html')),
diff --git a/sapl/base/views.py b/sapl/base/views.py
index 4cb3a5c52..fa3475a8d 100644
--- a/sapl/base/views.py
+++ b/sapl/base/views.py
@@ -1,18 +1,16 @@
-from django.contrib.auth.mixins import PermissionRequiredMixin
+
+from braces.views import PermissionRequiredMixin
from django.core.urlresolvers import reverse
from django.db.models import Count, Q
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateView
-from django.views.generic.edit import BaseCreateView
from django_filters.views import FilterView
-from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView,
- CrudDetailView, CrudUpdateView)
+from sapl.crud.base import CrudAux
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.parlamentares.models import Parlamentar
from sapl.sessao.models import OrdemDia, SessaoPlenaria
-from sapl.utils import permissao_tb_aux
from .forms import (CasaLegislativaForm, ConfiguracoesAppForm,
RelatorioAtasFilterSet,
@@ -225,24 +223,14 @@ class RelatorioMateriasPorAutorView(FilterView):
return context
-class CasaLegislativaCrud(Crud):
+class CasaLegislativaCrud(CrudAux):
model = CasaLegislativa
- help_path = ''
- class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
+ class BaseMixin(CrudAux.BaseMixin):
list_field_names = ['codigo', 'nome', 'sigla']
-
- def has_permission(self):
- return permissao_tb_aux(self)
-
- class CreateView(PermissionRequiredMixin, CrudCreateView):
form_class = CasaLegislativaForm
- class UpdateView(PermissionRequiredMixin, CrudUpdateView):
- form_class = CasaLegislativaForm
-
- class DetailView(CrudDetailView):
- form_class = CasaLegislativaForm
+ class DetailView(CrudAux.DetailView):
def get(self, request, *args, **kwargs):
return HttpResponseRedirect(
@@ -257,28 +245,21 @@ class HelpView(PermissionRequiredMixin, TemplateView):
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)
-
-
-class AppConfigCrud(Crud):
+class AppConfigCrud(CrudAux):
model = AppConfig
- help_path = ''
- class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
- list_field_names = ['documentos_administrativos',
- 'sequencia_numeracao',
- 'painel_aberto']
+ class BaseMixin(CrudAux.BaseMixin):
+ form_class = ConfiguracoesAppForm
- def has_permission(self):
- return permissao_tb_aux(self)
+ @property
+ def list_url(self):
+ return ''
- class CreateView(PermissionRequiredMixin, CrudCreateView):
- form_class = ConfiguracoesAppForm
+ @property
+ def create_url(self):
+ return ''
+
+ class CreateView(CrudAux.CreateView):
def get(self, request, *args, **kwargs):
app_config = AppConfig.objects.last()
@@ -288,8 +269,20 @@ class AppConfigCrud(Crud):
kwargs={'pk': app_config.pk}))
else:
self.object = None
- return super(BaseCreateView, self).get(
+ return super(CrudAux.CreateView, self).get(
request, *args, **kwargs)
- class UpdateView(PermissionRequiredMixin, CrudUpdateView):
- form_class = ConfiguracoesAppForm
+ class ListView(CrudAux.ListView):
+
+ def get(self, request, *args, **kwargs):
+ return HttpResponseRedirect(reverse('sapl.base:appconfig_create'))
+
+ class DetailView(CrudAux.DetailView):
+
+ def get(self, request, *args, **kwargs):
+ return HttpResponseRedirect(reverse('sapl.base:appconfig_create'))
+
+ class DeleteView(CrudAux.DeleteView):
+
+ def get(self, request, *args, **kwargs):
+ return HttpResponseRedirect(reverse('sapl.base:appconfig_create'))
diff --git a/sapl/comissoes/migrations/0008_auto_20160929_1611.py b/sapl/comissoes/migrations/0008_auto_20160929_1611.py
new file mode 100644
index 000000000..5e90c95b4
--- /dev/null
+++ b/sapl/comissoes/migrations/0008_auto_20160929_1611.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.7 on 2016-09-29 19:11
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('comissoes', '0007_merge'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='participacao',
+ name='composicao',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='participacao_set', to='comissoes.Composicao'),
+ ),
+ ]
diff --git a/sapl/comissoes/models.py b/sapl/comissoes/models.py
index 579b95f2a..ee3f72e6f 100644
--- a/sapl/comissoes/models.py
+++ b/sapl/comissoes/models.py
@@ -1,4 +1,3 @@
-import datetime
from django.db import models
from django.utils.translation import ugettext_lazy as _
@@ -131,7 +130,7 @@ class Composicao(models.Model): # IGNORE
class Participacao(models.Model): # ComposicaoComissao
- composicao = models.ForeignKey(Composicao)
+ composicao = models.ForeignKey(Composicao, related_name='participacao_set')
parlamentar = models.ForeignKey(Parlamentar)
cargo = models.ForeignKey(CargoComissao)
titular = models.BooleanField(verbose_name=_('Titular'))
diff --git a/sapl/comissoes/views.py b/sapl/comissoes/views.py
index e472a69cc..9d7208f62 100644
--- a/sapl/comissoes/views.py
+++ b/sapl/comissoes/views.py
@@ -1,12 +1,9 @@
-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, CrudCreateView,
- CrudDeleteView, CrudListView, CrudUpdateView)
-from sapl.crud.masterdetail import MasterDetailCrud
-from sapl.materia.models import MateriaLegislativa, Tramitacao
-from sapl.utils import permissao_tb_aux, permissoes_comissoes
+from sapl.crud.base import Crud, CrudAux, MasterDetailCrud
+from sapl.materia.models import MateriaLegislativa
from .models import (CargoComissao, Comissao, Composicao, Participacao,
Periodo, TipoComissao)
@@ -18,130 +15,50 @@ def pegar_url_composicao(pk):
url = reverse('sapl.comissoes:composicao_detail', kwargs={'pk': comp_pk})
return url
+CargoCrud = CrudAux.build(CargoComissao, 'cargo_comissao')
+PeriodoComposicaoCrud = CrudAux.build(Periodo, 'periodo_composicao_comissao')
-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)
+TipoComissaoCrud = CrudAux.build(
+ TipoComissao, 'tipo_comissao', list_field_names=[
+ 'sigla', 'nome', 'natureza', 'dispositivo_regimental'])
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)
- context['root_pk'] = self.object.composicao.comissao.pk
- return self.render_to_response(context)
-
- class CreateView(MasterDetailCrud.CreateView):
-
- def get_success_url(self):
- return reverse(
- 'sapl.comissoes:composicao_detail',
- kwargs={'pk': self.kwargs['pk']}
- )
-
- def cancel_url(self):
- return reverse(
- 'sapl.comissoes:composicao_detail',
- kwargs={'pk': self.kwargs['pk']}
- )
-
- class UpdateView(MasterDetailCrud.UpdateView):
+ parent_field = 'composicao__comissao'
- def get_success_url(self):
- return pegar_url_composicao(self.kwargs['pk'])
-
- def cancel_url(self):
- return pegar_url_composicao(self.kwargs['pk'])
-
- class DeleteView(MasterDetailCrud.DeleteView):
-
- def get_success_url(self):
- return pegar_url_composicao(self.kwargs['pk'])
-
- def cancel_url(self):
- return pegar_url_composicao(self.kwargs['pk'])
-
- class BaseMixin(PermissionRequiredMixin, MasterDetailCrud.BaseMixin):
- permission_required = permissoes_comissoes()
+ class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['composicao', 'parlamentar', 'cargo']
+ class DetailView(MasterDetailCrud.DetailView):
+ permission_required = []
+
class ComposicaoCrud(MasterDetailCrud):
model = Composicao
parent_field = 'comissao'
- 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)
- composicao = Composicao.objects.get(id=self.kwargs['pk'])
- context['participacoes'] = composicao.participacao_set.all()
- return self.render_to_response(context)
+ model_set = 'participacao_set'
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- permission_required = permissoes_comissoes()
+ class ListView(MasterDetailCrud.ListView):
+ permission_required = []
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
- permission_required = permissoes_comissoes()
-
- class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
- permission_required = permissoes_comissoes()
+ class DetailView(MasterDetailCrud.DetailView):
+ permission_required = []
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(Crud.BaseMixin):
+ list_field_names = ['nome', 'sigla', 'tipo', 'data_criacao', 'ativa']
+ ordering = '-ativa', 'sigla'
- class ListView(CrudListView):
- ordering = ['-ativa', 'sigla']
+ class ListView(Crud.ListView):
+ permission_required = []
- class BaseMixin(CrudBaseMixin):
- list_field_names = ['nome', 'sigla', 'tipo', 'data_criacao', 'ativa']
+ class DetailView(Crud.DetailView):
+ permission_required = []
class MateriasTramitacaoListView(ListView):
@@ -154,7 +71,7 @@ class MateriasTramitacaoListView(ListView):
materias = MateriaLegislativa.objects.filter(tramitacao__isnull=False)
for materia in materias:
comissao = materia.tramitacao_set.last(
- ).unidade_tramitacao_local.comissao
+ ).unidade_tramitacao_local.comissao
if comissao:
if comissao.pk == int(self.kwargs['pk']):
lista.append(materia)
diff --git a/sapl/crispy_layout_mixin.py b/sapl/crispy_layout_mixin.py
index 6ac4a2e22..5ffc2533c 100644
--- a/sapl/crispy_layout_mixin.py
+++ b/sapl/crispy_layout_mixin.py
@@ -49,7 +49,12 @@ class SaplFormLayout(Layout):
def get_field_display(obj, fieldname):
- field = obj._meta.get_field(fieldname)
+ field = ''
+ try:
+ field = obj._meta.get_field(fieldname)
+ except:
+ value = getattr(obj, fieldname)
+ return '', value
verbose_name = str(field.verbose_name)\
if hasattr(field, 'verbose_name') else ''
if hasattr(field, 'choices') and field.choices:
@@ -97,10 +102,25 @@ class CrispyLayoutFormMixin:
else:
return self.model.__name__
+ @property
+ def layout_key_set(self):
+ if hasattr(super(CrispyLayoutFormMixin, self), 'layout_key_set'):
+ return super(CrispyLayoutFormMixin, self).layout_key_set
+ else:
+ obj = self.crud if hasattr(self, 'crud') else self
+ return getattr(obj.model,
+ obj.model_set).field.model.__name__
+
def get_layout(self):
yaml_layout = '%s/layouts.yaml' % self.model._meta.app_config.label
return read_layout_from_yaml(yaml_layout, self.layout_key)
+ def get_layout_set(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ yaml_layout = '%s/layouts.yaml' % getattr(
+ obj.model, obj.model_set).field.model._meta.app_config.label
+ return read_layout_from_yaml(yaml_layout, self.layout_key_set)
+
@property
def fields(self):
if hasattr(self, 'form_class') and self.form_class:
@@ -129,9 +149,22 @@ class CrispyLayoutFormMixin:
This base implementation returns the field names
in the first fieldset of the layout.
'''
+ obj = self.crud if hasattr(self, 'crud') else self
+ if hasattr(obj, 'list_field_names') and obj.list_field_names:
+ return obj.list_field_names
rows = self.get_layout()[0][1:]
return [fieldname for row in rows for fieldname, __ in row]
+ @property
+ def list_field_names_set(self):
+ '''The list of field names to display on table
+
+ This base implementation returns the field names
+ in the first fieldset of the layout.
+ '''
+ rows = self.get_layout_set()[0][1:]
+ return [fieldname for row in rows for fieldname, __ in row]
+
def get_column(self, fieldname, span):
obj = self.get_object()
verbose_name, text = get_field_display(obj, fieldname)
diff --git a/sapl/crud/base.py b/sapl/crud/base.py
index 289bd21e1..6f67af03e 100644
--- a/sapl/crud/base.py
+++ b/sapl/crud/base.py
@@ -1,26 +1,48 @@
+import logging
+
from braces.views import FormMessagesMixin
+from compressor.utils.decorators import cached_property
+from crispy_forms.bootstrap import FieldWithButtons, StrictButton
+from crispy_forms.helper import FormHelper
+from crispy_forms.layout import Field, Layout
+from django import forms
from django.conf.urls import url
+from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.urlresolvers import reverse
+from django.db import models
+from django.http.response import Http404
from django.utils.decorators import classonlymethod
+from django.utils.encoding import force_text
+from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _
from django.views.generic import (CreateView, DeleteView, DetailView, ListView,
UpdateView)
+from django.views.generic.base import ContextMixin
+from django.views.generic.list import MultipleObjectMixin
from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display
+from sapl.utils import normalize
+
+
+logger = logging.getLogger(__name__)
-LIST, CREATE, DETAIL, UPDATE, DELETE = \
+ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \
'list', 'create', 'detail', 'update', 'delete'
+# RP - Radical das permissões para "..."
+RP_LIST, RP_DETAIL, RP_ADD, RP_CHANGE, RP_DELETE =\
+ '.list_', '.detail_', '.add_', '.change_', '.delete_',
+
def _form_invalid_message(msg):
return '%s %s' % (_('Formulário inválido.'), msg)
-FORM_MESSAGES = {CREATE: (_('Registro criado com sucesso!'),
- _('O registro não foi criado.')),
- UPDATE: (_('Registro alterado com sucesso!'),
- _('Suas alterações não foram salvas.')),
- DELETE: (_('Registro excluído com sucesso!'),
- _('O registro não foi excluído.'))}
+FORM_MESSAGES = {ACTION_CREATE: (_('Registro criado com sucesso!'),
+ _('O registro não foi criado.')),
+ ACTION_UPDATE: (_('Registro alterado com sucesso!'),
+ _('Suas alterações não foram salvas.')),
+ ACTION_DELETE: (_('Registro excluído com sucesso!'),
+ _('O registro não foi excluído.'))}
FORM_MESSAGES = {k: (a, _form_invalid_message(b))
for k, (a, b) in FORM_MESSAGES.items()}
@@ -55,37 +77,236 @@ def make_pagination(index, num_pages):
head = from_to(1, PAGINATION_LENGTH - len(tail) - 1)
return head + [None] + tail
+"""
+variáveis do crud:
+ help_path
+ container_field
+ container_field_set
+ is_m2m
+ model
+ model_set
+ form_search_class -> depende de o model relativo implementar SearchMixin
+ list_field_names
+ list_field_names_set -> lista reversa em details
+ permission_required -> este atributo ser vazio não nulo torna a view publ
+ layout_key_set
+ layout_key
+ ordered_list = False desativa os clicks e controles de ord da listagem
+ parent_field = parentesco reverso separado por '__'
+ namespace
+"""
+
+
+class SearchMixin(models.Model):
+
+ search = models.TextField(blank=True, default='')
+
+ class Meta:
+ abstract = True
+
+ def save(self, force_insert=False, force_update=False, using=None,
+ update_fields=None, auto_update_search=True):
+
+ if auto_update_search and hasattr(self, 'fields_search'):
+ search = ''
+ for str_field in self.fields_search:
+ fields = str_field.split('__')
+ if len(fields) == 1:
+ try:
+ search += str(getattr(self, str_field)) + ' '
+ except:
+ pass
+ else:
+ _self = self
+ for field in fields:
+ _self = getattr(_self, field)
+ search += str(_self) + ' '
+ self.search = search
+ self.search = normalize(self.search)
+
+ return super(SearchMixin, self).save(
+ force_insert=force_insert, force_update=force_update,
+ using=using, update_fields=update_fields)
+
+
+class ListWithSearchForm(forms.Form):
+ q = forms.CharField(required=False, label='',
+ widget=forms.TextInput(
+ attrs={'type': 'search'}))
+
+ o = forms.CharField(required=False, label='',
+ widget=forms.HiddenInput())
+
+ class Meta:
+ fields = ['q', 'o']
+
+ def __init__(self, *args, **kwargs):
+ super(ListWithSearchForm, self).__init__(*args, **kwargs)
+
+ self.helper = FormHelper()
+ self.form_class = 'form-inline'
+ self.helper.form_method = 'GET'
+ self.helper.layout = Layout(
+ Field('o'),
+ FieldWithButtons(
+ Field('q',
+ placeholder=_('Filtrar Lista'),
+ css_class='input-lg'),
+ StrictButton(
+ _('Filtrar'), css_class='btn-default btn-lg',
+ type='submit'))
+ )
+
+
+class PermissionRequiredContainerCrudMixin(PermissionRequiredMixin):
+
+ def has_permission(self):
+ perms = self.get_permission_required()
+ # Torna a view pública se não possuir o atributo permission_required
+ return self.request.user.has_perms(perms) if len(perms) else True
+
+ def dispatch(self, request, *args, **kwargs):
+ if not self.has_permission():
+ return self.handle_no_permission()
+
+ if 'pk' in kwargs:
+ params = {'pk': kwargs['pk']}
+
+ if self.container_field:
+ params[self.container_field] = request.user.pk
+
+ if not self.model.objects.filter(**params).exists():
+ raise Http404()
+
+ return super(PermissionRequiredMixin, self).dispatch(
+ request, *args, **kwargs)
+
+ @cached_property
+ def container_field(self):
+ if hasattr(self, 'crud') and not hasattr(self.crud, 'container_field'):
+ self.crud.container_field = ''
+ if hasattr(self, 'crud'):
+ return self.crud.container_field
+
+ @cached_property
+ def container_field_set(self):
+ if hasattr(self, 'crud') and\
+ not hasattr(self.crud, 'container_field_set'):
+ self.crud.container_field_set = ''
+ if hasattr(self, 'crud'):
+ return self.crud.container_field_set
+
+ @cached_property
+ def is_contained(self):
+ return self.container_field_set or self.container_field
+
class CrudBaseMixin(CrispyLayoutFormMixin):
+ def __init__(self, **kwargs):
+ super(CrudBaseMixin, self).__init__(**kwargs)
+ obj = self.crud if hasattr(self, 'crud') else self
+ self.app_label = obj.model._meta.app_label
+ self.model_name = obj.model._meta.model_name
+
+ if hasattr(obj, 'model_set') and obj.model_set:
+ self.app_label_set = getattr(
+ obj.model, obj.model_set).field.model._meta.app_label
+ self.model_name_set = getattr(
+ obj.model, obj.model_set).field.model._meta.model_name
+
+ if hasattr(self, 'permission_required') and self.permission_required:
+ if hasattr(obj, 'public'):
+ self.permission_required = list(
+ set(self.permission_required) - set(obj.public))
+
+ self.permission_required = tuple((
+ self.permission(pr) for pr in self.permission_required))
+
@classmethod
def url_name(cls, suffix):
return '%s_%s' % (cls.model._meta.model_name, suffix)
+ def url_name_set(self, suffix):
+ obj = self.crud if hasattr(self, 'crud') else self
+ return '%s_%s' % (getattr(obj.model, obj.model_set
+ ).field.model._meta.model_name, suffix)
+
+ def permission(self, rad):
+ return '%s%s%s' % (self.app_label if rad.endswith('_') else '',
+ rad,
+ self.model_name if rad.endswith('_') else '')
+
+ def permission_set(self, rad):
+ return '%s%s%s' % (self.app_label_set if rad.endswith('_') else '',
+ rad,
+ self.model_name_set if rad.endswith('_') else '')
+
def resolve_url(self, suffix, args=None):
namespace = self.model._meta.app_config.name
return reverse('%s:%s' % (namespace, self.url_name(suffix)),
args=args)
+ def resolve_url_set(self, suffix, args=None):
+ obj = self.crud if hasattr(self, 'crud') else self
+ namespace = getattr(
+ obj.model, obj.model_set).field.model._meta.app_config.name
+ return reverse('%s:%s' % (namespace, self.url_name_set(suffix)),
+ args=args)
+
+ @property
+ def ordered_list(self):
+ return True
+
@property
def list_url(self):
- return self.resolve_url(LIST)
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.ListView.permission_required:
+ return self.resolve_url(ACTION_LIST)
+ else:
+ return self.resolve_url(
+ ACTION_LIST) if self.request.user.has_perm(
+ self.permission(RP_LIST)) else ''
@property
def create_url(self):
- return self.resolve_url(CREATE)
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.CreateView.permission_required:
+ return self.resolve_url(ACTION_CREATE)
+ else:
+ return self.resolve_url(
+ ACTION_CREATE) if self.request.user.has_perm(
+ self.permission(RP_ADD)) else ''
@property
def detail_url(self):
- return self.resolve_url(DETAIL, args=(self.object.id,))
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.DetailView.permission_required:
+ return self.resolve_url(ACTION_DETAIL, args=(self.object.id,))
+ else:
+ return self.resolve_url(ACTION_DETAIL, args=(self.object.id,))\
+ if self.request.user.has_perm(
+ self.permission(RP_DETAIL)) else ''
@property
def update_url(self):
- return self.resolve_url(UPDATE, args=(self.object.id,))
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.UpdateView.permission_required:
+ return self.resolve_url(ACTION_UPDATE, args=(self.object.id,))
+ else:
+ return self.resolve_url(ACTION_UPDATE, args=(self.object.id,))\
+ if self.request.user.has_perm(
+ self.permission(RP_CHANGE)) else ''
@property
def delete_url(self):
- return self.resolve_url(DELETE, args=(self.object.id,))
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.DeleteView.permission_required:
+ return self.resolve_url(ACTION_DELETE)
+ else:
+ return self.resolve_url(ACTION_DELETE, args=(self.object.id,))\
+ if self.request.user.has_perm(
+ self.permission(RP_DELETE)) else ''
def get_template_names(self):
names = super(CrudBaseMixin, self).get_template_names()
@@ -93,6 +314,11 @@ class CrudBaseMixin(CrispyLayoutFormMixin):
self.template_name_suffix.lstrip('_'))
return names
+ @property
+ def verbose_name_set(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ return getattr(obj.model, obj.model_set).field.model._meta.verbose_name
+
@property
def verbose_name(self):
return self.model._meta.verbose_name
@@ -102,12 +328,12 @@ class CrudBaseMixin(CrispyLayoutFormMixin):
return self.model._meta.verbose_name_plural
-class CrudListView(ListView):
+class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
+ permission_required = (RP_LIST, )
@classmethod
def get_url_regex(cls):
return r'^$'
-
paginate_by = 10
no_entries_msg = _('Nenhum registro encontrado.')
@@ -115,18 +341,90 @@ class CrudListView(ListView):
return [self._as_row(obj) for obj in object_list]
def get_headers(self):
- return [self.model._meta.get_field(fieldname).verbose_name
- for fieldname in self.list_field_names]
+ """
+ Transforma o headers de fields de list_field_names
+ para junção de fields via tuplas.
+ list_field_names pode ser construido como
+ list_field_names=('nome', 'endereco', ('telefone', sexo'), 'dat_nasc')
+ ou ainda:
+ list_field_names = ['composicao__comissao__nome', 'cargo__nome', (
+ 'composicao__periodo__data_inicio', 'composicao__periodo__data_fim')]
+ """
+ r = []
+ for fieldname in self.list_field_names:
+ if not isinstance(fieldname, tuple):
+ fieldname = fieldname,
+
+ s = []
+ for fn in fieldname:
+ m = self.model
+ fn = fn.split('__')
+ for f in fn:
+ f = m._meta.get_field(f)
+ if hasattr(f, 'related_model') and f.related_model:
+ m = f.related_model
+ if m == self.model:
+ s.append(force_text(f.verbose_name))
+ else:
+ s.append(force_text(m._meta.verbose_name))
+ s = ' / '.join(s)
+ r.append(s)
+ return r
def _as_row(self, obj):
- return [
- (get_field_display(obj, name)[1],
- self.resolve_url(DETAIL, args=(obj.id,)) if i == 0 else None)
- for i, name in enumerate(self.list_field_names)]
+ """
+ FIXME: Refatorar função para capturar url correta em caso de uso de
+ campos foreignkey. getHeaders já faz isso para construir o título.
+ falta fazer com esta função
+ """
+ r = []
+ for i, name in enumerate(self.list_field_names):
+ url = self.resolve_url(
+ ACTION_DETAIL, args=(obj.id,)) if i == 0 else None
+
+ """Caso o crud list seja para uma relação ManyToManyField"""
+ if url and hasattr(self, 'crud') and\
+ hasattr(self.crud, 'is_m2m') and self.crud.is_m2m:
+ url = url + ('?pkk=' + self.kwargs['pk']
+ if 'pk' in self.kwargs else '')
+
+ """ se elemento de list_field_name for uma tupla, constrói a
+ informação com ' - ' se os campos forem simples,
+ ou com
se for m2m """
+ if isinstance(name, tuple):
+ s = ''
+ for j, n in enumerate(name):
+ ss = get_field_display(obj, n)[1]
+ ss = (
+ ('
' if '
' in ss else ' - ') + ss)\
+ if ss and j != 0 and s else ss
+ s += ss
+ r.append((s, url))
+ else:
+ r.append((get_field_display(obj, name)[1], url))
+ return r
def get_context_data(self, **kwargs):
- context = super(CrudListView, self).get_context_data(**kwargs)
+ """ Relevante se na implmentação do crud list, for informado
+ um formulário de pesquisa herdado ou o próprio ListWithSearchForm.
+ Só pode ser usado se o model relativo herdar de SearchMixin"""
+ if hasattr(self, 'form_search_class'):
+ q = str(self.request.GET.get('q'))\
+ if 'q' in self.request.GET else ''
+
+ o = self.request.GET['o'] if 'o' in self.request.GET else '1'
+
+ if 'form' not in kwargs:
+ initial = self.get_initial() if hasattr(
+ self, 'get_initial') else {}
+ initial.update({'q': q, 'o': o})
+ kwargs['form'] = self.form_search_class(
+ initial=initial)
+
+ count = self.object_list.count()
+ context = super().get_context_data(**kwargs)
context.setdefault('title', self.verbose_name_plural)
+ context['count'] = count
# pagination
if self.paginate_by:
@@ -142,16 +440,115 @@ class CrudListView(ListView):
context['NO_ENTRIES_MSG'] = self.no_entries_msg
+ qr = self.request.GET.copy()
+ if 'page' in qr:
+ del qr['page']
+ context['filter_url'] = (
+ '&' + qr.urlencode()) if len(qr) > 0 else ''
+
+ if self.ordered_list:
+ if 'o' in qr:
+ del qr['o']
+ context['ordering_url'] = (
+ '&' + qr.urlencode()) if len(qr) > 0 else ''
return context
-
-class CrudCreateView(FormMessagesMixin, CreateView):
+ def get_queryset(self):
+ queryset = super().get_queryset()
+
+ # form_search_class
+ # só pode ser usado em models que herdam de SearchMixin
+ if hasattr(self, 'form_search_class'):
+ request = self.request
+ if request.GET.get('q') is not None:
+ query = normalize(str(request.GET.get('q')))
+
+ query = query.split(' ')
+ if query:
+ q = models.Q()
+ for item in query:
+ if not item:
+ continue
+ q = q & models.Q(search__icontains=item)
+
+ if q:
+ queryset = queryset.filter(q)
+
+ if self.ordered_list:
+ list_field_names = self.list_field_names
+ o = '1'
+ desc = ''
+ if 'o' in self.request.GET:
+ o = self.request.GET['o']
+ desc = '-' if o.startswith('-') else ''
+
+ # Constroi a ordenação da listagem com base no que o usuário
+ # clicar
+ try:
+ fields_for_ordering = list_field_names[
+ (abs(int(o)) - 1) % len(list_field_names)]
+
+ if isinstance(fields_for_ordering, str):
+ fields_for_ordering = [fields_for_ordering, ]
+
+ ordering = ()
+ model = self.model
+ for fo in fields_for_ordering:
+
+ fm = None
+ try:
+ fm = model._meta.get_field(fo)
+ except:
+ pass
+
+ if fm and hasattr(fm, 'related_model')\
+ and fm.related_model:
+ rmo = fm.related_model._meta.ordering
+ if rmo:
+ rmo = rmo[0]
+ if not isinstance(rmo, str):
+ rmo = rmo[0]
+ fo = '%s__%s' % (fo, rmo)
+
+ fo = desc + fo
+ ordering += (fo,)
+
+ model = self.model
+ model_ordering = model._meta.ordering
+ if model_ordering:
+ if isinstance(model_ordering, str):
+ model_ordering = (model_ordering,)
+ for mo in model_ordering:
+ if mo not in ordering:
+ ordering = ordering + (mo, )
+ queryset = queryset.order_by(*ordering)
+
+ # print(ordering)
+ except Exception as e:
+ logger.error(string_concat(_(
+ 'ERRO: construção da tupla de ordenação.'), str(e)))
+
+ # print(queryset.query)
+ if not self.request.user.is_authenticated():
+ return queryset
+
+ if self.container_field:
+ params = {}
+ params[self.container_field] = self.request.user.pk
+ queryset = queryset.filter(**params)
+
+ return queryset
+
+
+class CrudCreateView(PermissionRequiredContainerCrudMixin,
+ FormMessagesMixin, CreateView):
+ permission_required = (RP_ADD, )
@classmethod
def get_url_regex(cls):
return r'^create$'
- form_valid_message, form_invalid_message = FORM_MESSAGES[CREATE]
+ form_valid_message, form_invalid_message = FORM_MESSAGES[ACTION_CREATE]
@property
def cancel_url(self):
@@ -165,21 +562,205 @@ class CrudCreateView(FormMessagesMixin, CreateView):
'verbose_name': self.verbose_name})
return super(CrudCreateView, self).get_context_data(**kwargs)
+ def form_valid(self, form):
+ self.object = form.save(commit=False)
+ try:
+ self.object.owner = self.request.user
+ self.object.modifier = self.request.user
+ except:
+ pass
+
+ if self.container_field:
+ container = self.container_field.split('__')
+
+ if len(container) > 1:
+ container_model = getattr(
+ self.model, container[0]).field.related_model
+
+ params = {}
+ params['__'.join(
+ container[1:])] = self.request.user.pk
+
+ if 'pk' in self.kwargs:
+ params['pk'] = self.kwargs['pk']
+
+ container_data = container_model.objects.filter(
+ **params).first()
-class CrudDetailView(DetailView):
+ if not container_data:
+ raise Exception(
+ _('Não é permitido adicionar um registro '
+ 'sem estar em um Container'))
+
+ if hasattr(self, 'crud') and\
+ hasattr(self.crud, 'is_m2m') and self.crud.is_m2m:
+ setattr(
+ self.object, container[1], getattr(
+ container_data, container[1]))
+ response = super().form_valid(form)
+ getattr(self.object, container[0]).add(container_data)
+ return response
+ else:
+ setattr(self.object, container[0], container_data)
+
+ return super().form_valid(form)
+
+
+class CrudDetailView(PermissionRequiredContainerCrudMixin,
+ DetailView, MultipleObjectMixin):
+
+ permission_required = (RP_DETAIL, )
+ no_entries_msg = _('Nenhum registro Associado.')
+ paginate_by = 10
@classmethod
def get_url_regex(cls):
return r'^(?P\d+)$'
+ def get_rows(self, object_list):
+ return [self._as_row(obj) for obj in object_list]
-class CrudUpdateView(FormMessagesMixin, UpdateView):
+ def get_headers(self):
+ if not self.object_list:
+ return []
+ try:
+ obj = self.crud if hasattr(self, 'crud') else self
+ return [
+ (getattr(
+ self.object, obj.model_set).model._meta.get_field(
+ fieldname).verbose_name
+ if hasattr(self.object, fieldname) else
+ getattr(
+ self.object, obj.model_set).model._meta.get_field(
+ fieldname).related_model._meta.verbose_name_plural)
+ for fieldname in self.list_field_names_set]
+ except:
+ obj = self.crud if hasattr(self, 'crud') else self
+ return [getattr(
+ self.object,
+ obj.model_set).model._meta.verbose_name_plural]
+
+ def url_model_set_name(self, suffix):
+ return '%s_%s' % (
+ getattr(self.object,
+ self.crud.model_set).model._meta.model_name,
+ suffix)
+
+ def resolve_model_set_url(self, suffix, args=None):
+ obj = self.crud if hasattr(self, 'crud') else self
+ namespace = getattr(
+ self.object, obj.model_set).model._meta.app_config.name
+ return reverse('%s:%s' % (
+ namespace, self.url_model_set_name(suffix)),
+ args=args)
+
+ def _as_row(self, obj):
+ try:
+ return [(
+ get_field_display(obj, name)[1],
+ self.resolve_model_set_url(ACTION_DETAIL, args=(obj.id,))
+ if i == 0 else None)
+ for i, name in enumerate(self.list_field_names_set)]
+ except:
+ return [(
+ getattr(obj, name),
+ self.resolve_model_set_url(ACTION_DETAIL, args=(obj.id,))
+ if i == 0 else None)
+ for i, name in enumerate(self.list_field_names_set)]
+
+ def get_object(self, queryset=None):
+ if hasattr(self, 'object'):
+ return self.object
+ return DetailView.get_object(self, queryset=queryset)
+
+ def get(self, request, *args, **kwargs):
+ self.object = self.model.objects.get(pk=kwargs.get('pk'))
+ obj = self.crud if hasattr(self, 'crud') else self
+ if hasattr(obj, 'model_set') and obj.model_set:
+ self.object_list = self.get_queryset()
+ context = self.get_context_data(object=self.object)
+ return self.render_to_response(context)
+
+ def get_queryset(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ if hasattr(obj, 'model_set') and obj.model_set:
+ queryset = getattr(self.object, obj.model_set).all()
+ else:
+ queryset = super().get_queryset()
+
+ if not self.request.user.is_authenticated():
+ return queryset
+
+ if self.container_field_set:
+ params = {}
+ params[self.container_field_set] = self.request.user.pk
+ return queryset.filter(**params)
+
+ return queryset
+
+ def get_context_data(self, **kwargs):
+ obj = self.crud if hasattr(self, 'crud') else self
+ if hasattr(obj, 'model_set') and obj.model_set:
+ count = self.object_list.count()
+ context = MultipleObjectMixin.get_context_data(self, **kwargs)
+ context['count'] = count
+ if self.paginate_by:
+ page_obj = context['page_obj']
+ paginator = context['paginator']
+ context['page_range'] = make_pagination(
+ page_obj.number, paginator.num_pages)
+
+ # rows
+ object_list = context['object_list']
+ context['headers'] = self.get_headers()
+ context['rows'] = self.get_rows(object_list)
+
+ context['NO_ENTRIES_MSG'] = self.no_entries_msg
+ else:
+ context = ContextMixin.get_context_data(self, **kwargs)
+ if self.object:
+ context['object'] = self.object
+ context_object_name = self.get_context_object_name(
+ self.object)
+ if context_object_name:
+ context[context_object_name] = self.object
+ context.update(kwargs)
+
+ return context
+
+ @property
+ def model_set_verbose_name(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ return getattr(
+ self.object,
+ obj.model_set).model._meta.verbose_name
+
+ @property
+ def model_set_verbose_name_plural(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ return getattr(
+ self.object,
+ obj.model_set).model._meta.verbose_name_plural
+
+
+class CrudUpdateView(PermissionRequiredContainerCrudMixin,
+ FormMessagesMixin, UpdateView):
+ permission_required = (RP_CHANGE, )
+
+ def form_valid(self, form):
+ self.object = form.save(commit=False)
+ try:
+ self.object.modifier = self.request.user
+ except:
+ pass
+
+ return super().form_valid(form)
@classmethod
def get_url_regex(cls):
return r'^(?P\d+)/edit$'
- form_valid_message, form_invalid_message = FORM_MESSAGES[UPDATE]
+ form_valid_message, form_invalid_message = FORM_MESSAGES[ACTION_UPDATE]
@property
def cancel_url(self):
@@ -189,13 +770,15 @@ class CrudUpdateView(FormMessagesMixin, UpdateView):
return self.detail_url
-class CrudDeleteView(FormMessagesMixin, DeleteView):
+class CrudDeleteView(PermissionRequiredContainerCrudMixin,
+ FormMessagesMixin, DeleteView):
+ permission_required = (RP_DELETE, )
@classmethod
def get_url_regex(cls):
return r'^(?P\d+)/delete$'
- form_valid_message, form_invalid_message = FORM_MESSAGES[DELETE]
+ form_valid_message, form_invalid_message = FORM_MESSAGES[ACTION_DELETE]
@property
def cancel_url(self):
@@ -214,16 +797,20 @@ class Crud:
DeleteView = CrudDeleteView
help_path = ''
+ class PublicMixin:
+ permission_required = []
+
@classonlymethod
def get_urls(cls):
def _add_base(view):
- class CrudViewWithBase(cls.BaseMixin, view):
- model = cls.model
- help_path = cls.help_path
- crud = cls
- CrudViewWithBase.__name__ = view.__name__
- return CrudViewWithBase
+ if view:
+ class CrudViewWithBase(cls.BaseMixin, view):
+ model = cls.model
+ help_path = cls.help_path
+ crud = cls
+ CrudViewWithBase.__name__ = view.__name__
+ return CrudViewWithBase
CrudListView = _add_base(cls.ListView)
CrudCreateView = _add_base(cls.CreateView)
@@ -231,21 +818,408 @@ class Crud:
CrudUpdateView = _add_base(cls.UpdateView)
CrudDeleteView = _add_base(cls.DeleteView)
+ cruds_base = [
+ (CrudListView.get_url_regex()
+ if CrudListView else None, CrudListView, ACTION_LIST),
+ (CrudCreateView.get_url_regex()
+ if CrudCreateView else None, CrudCreateView, ACTION_CREATE),
+ (CrudDetailView.get_url_regex()
+ if CrudDetailView else None, CrudDetailView, ACTION_DETAIL),
+ (CrudUpdateView.get_url_regex()
+ if CrudUpdateView else None, CrudUpdateView, ACTION_UPDATE),
+ (CrudDeleteView.get_url_regex()
+ if CrudDeleteView else None, CrudDeleteView, ACTION_DELETE)]
+
+ cruds = []
+ for crud in cruds_base:
+ if crud[0]:
+ cruds.append(crud)
+
return [url(regex, view.as_view(), name=view.url_name(suffix))
- for regex, view, suffix in [
- (CrudListView.get_url_regex(), CrudListView, LIST),
- (CrudCreateView.get_url_regex(), CrudCreateView, CREATE),
- (CrudDetailView.get_url_regex(), CrudDetailView, DETAIL),
- (CrudUpdateView.get_url_regex(), CrudUpdateView, UPDATE),
- (CrudDeleteView.get_url_regex(), CrudDeleteView, DELETE),
- ]]
+ for regex, view, suffix in cruds]
@classonlymethod
- def build(cls, _model, _help_path):
+ def build(cls, _model, _help_path, _model_set=None, list_field_names=[]):
- class ModelCrud(cls):
- model = _model
- help_path = _help_path
+ def create_class(_list_field_names):
+ class ModelCrud(cls):
+ model = _model
+ model_set = _model_set
+ help_path = _help_path
+ list_field_names = _list_field_names
+ return ModelCrud
+ ModelCrud = create_class(list_field_names)
ModelCrud.__name__ = '%sCrud' % _model.__name__
return ModelCrud
+
+
+class CrudAux(Crud):
+
+ class BaseMixin(Crud.BaseMixin):
+ permission_required = ('base.view_tabelas_auxiliares',)
+ subnav_template_name = None
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['subnav_template_name'] = self.subnav_template_name
+ return context
+
+ @classonlymethod
+ def build(cls, _model, _help_path, _model_set=None, list_field_names=[]):
+
+ ModelCrud = Crud.build(
+ _model, _help_path, _model_set, list_field_names)
+
+ class ModelCrudAux(ModelCrud):
+ BaseMixin = CrudAux.BaseMixin
+
+ return ModelCrudAux
+
+
+class MasterDetailCrud(Crud):
+ is_m2m = False
+
+ class BaseMixin(Crud.BaseMixin):
+
+ @property
+ def list_url(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.ListView:
+ return ''
+ return self.resolve_url(ACTION_LIST, args=(self.kwargs['pk'],))\
+ if self.request.user.has_perm(self.permission(RP_LIST)) else ''
+
+ @property
+ def create_url(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.CreateView:
+ return ''
+ return self.resolve_url(ACTION_CREATE, args=(self.kwargs['pk'],))\
+ if self.request.user.has_perm(self.permission(RP_ADD)) else ''
+
+ @property
+ def detail_url(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.DetailView:
+ return ''
+ pkk = self.request.GET['pkk'] if 'pkk' in self.request.GET else ''
+ return (super().detail_url + (('?pkk=' + pkk) if pkk else ''))\
+ if self.request.user.has_perm(
+ self.permission(RP_DETAIL)) else ''
+
+ @property
+ def update_url(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.UpdateView:
+ return ''
+ pkk = self.request.GET['pkk'] if 'pkk' in self.request.GET else ''
+ return (super().update_url + (('?pkk=' + pkk) if pkk else ''))\
+ if self.request.user.has_perm(
+ self.permission(RP_CHANGE)) else ''
+
+ @property
+ def delete_url(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.DeleteView:
+ return ''
+ return super().delete_url\
+ if self.request.user.has_perm(
+ self.permission(RP_DELETE)) else ''
+
+ def get_context_data(self, **kwargs):
+ obj = self.crud if hasattr(self, 'crud') else self
+ self.object = getattr(self, 'object', None)
+ parent_object = None
+ if self.object:
+ if '__' in obj.parent_field:
+ fields = obj.parent_field.split('__')
+ parent_object = self.object
+ for field in fields:
+ parent_object = getattr(parent_object, field)
+ else:
+ parent_object = getattr(self.object, obj.parent_field)
+ if not isinstance(parent_object, models.Model):
+ if parent_object.count() > 1:
+ if 'pkk' not in self.request.GET:
+ raise Http404
+ root_pk = self.request.GET['pkk']
+ parent_object = parent_object.filter(id=root_pk)
+
+ parent_object = parent_object.first()
+
+ if not parent_object:
+ raise Http404
+ root_pk = parent_object.pk
+ else:
+ root_pk = self.kwargs['pk'] # in list and create
+ kwargs.setdefault('root_pk', root_pk)
+ context = super(CrudBaseMixin, self).get_context_data(**kwargs)
+
+ if parent_object:
+ context['title'] = '%s (%s)' % (
+ self.object, parent_object)
+
+ return context
+
+ class ListView(Crud.ListView):
+ permission_required = RP_LIST,
+
+ @classmethod
+ def get_url_regex(cls):
+ return r'^(?P\d+)/%s$' % cls.model._meta.model_name
+
+ def get_context_data(self, **kwargs):
+ obj = self.crud if hasattr(self, 'crud') else self
+ context = CrudListView.get_context_data(self, **kwargs)
+
+ parent_model = None
+ if '__' in obj.parent_field:
+ fields = obj.parent_field.split('__')
+ parent_model = self.model
+ for field in fields:
+ parent_model = getattr(
+ parent_model, field).field.related_model
+ else:
+ parent_model = getattr(
+ self.model, obj.parent_field).field.related_model
+
+ params = {'pk': kwargs['root_pk']}
+
+ if self.container_field:
+ container = self.container_field.split('__')
+ if len(container) > 1:
+ params['__'.join(container[1:])] = self.request.user.pk
+
+ try:
+ parent_object = parent_model.objects.get(**params)
+ except:
+ raise Http404()
+
+ context[
+ 'title'] = '%s (%s)' % (
+ context['title'], parent_object)
+ return context
+
+ def get_queryset(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ qs = super().get_queryset()
+
+ kwargs = {obj.parent_field: self.kwargs['pk']}
+
+ """if self.container_field:
+ kwargs[self.container_field] = self.request.user.pk"""
+
+ return qs.filter(**kwargs)
+
+ class CreateView(Crud.CreateView):
+ permission_required = RP_ADD,
+
+ def dispatch(self, request, *args, **kwargs):
+ return PermissionRequiredMixin.dispatch(
+ self, request, *args, **kwargs)
+
+ @classmethod
+ def get_url_regex(cls):
+ return r'^(?P\d+)/%s/create$' % cls.model._meta.model_name
+
+ def get_form(self, form_class=None):
+ obj = self.crud if hasattr(self, 'crud') else self
+ form = super(MasterDetailCrud.CreateView, self).get_form(
+ self.form_class)
+ if not obj.is_m2m:
+ parent_field = obj.parent_field.split('__')[0]
+ field = self.model._meta.get_field(parent_field)
+ parent = field.related_model.objects.get(pk=self.kwargs['pk'])
+ setattr(form.instance, parent_field, parent)
+ return form
+
+ def get_context_data(self, **kwargs):
+ obj = self.crud if hasattr(self, 'crud') else self
+ context = Crud.CreateView.get_context_data(
+ self, **kwargs)
+
+ params = {'pk': self.kwargs['pk']}
+ if self.container_field:
+ parent_model = getattr(
+ self.model, obj.parent_field).field.related_model
+
+ container = self.container_field.split('__')
+ if len(container) > 1:
+ params['__'.join(container[1:])] = self.request.user.pk
+
+ try:
+ parent = parent_model.objects.get(**params)
+ except:
+ raise Http404()
+ else:
+ parent_field = obj.parent_field.split('__')[0]
+
+ field = self.model._meta.get_field(parent_field)
+ parent = field.related_model.objects.get(**params)
+ if parent:
+ context['title'] = '%s (%s)' % (
+ context['title'], parent)
+
+ return context
+
+ class UpdateView(Crud.UpdateView):
+ permission_required = RP_CHANGE,
+
+ @classmethod
+ def get_url_regex(cls):
+ return r'^%s/(?P\d+)/edit$' % cls.model._meta.model_name
+
+ def get(self, request, *args, **kwargs):
+ return Crud.UpdateView.get(self, request, *args, **kwargs)
+
+ class DeleteView(Crud.DeleteView):
+ permission_required = RP_DELETE,
+
+ @classmethod
+ def get_url_regex(cls):
+ return r'^%s/(?P\d+)/delete$' % cls.model._meta.model_name
+
+ def get_success_url(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ parent_object = getattr(
+ self.get_object(), obj.parent_field)
+ if not isinstance(parent_object, models.Model):
+ if parent_object.count() > 1:
+ if 'pkk' not in self.request.GET:
+ raise Http404
+ root_pk = self.request.GET['pkk']
+ parent_object = parent_object.filter(id=root_pk)
+
+ parent_object = parent_object.first()
+
+ if not parent_object:
+ raise Http404
+ root_pk = parent_object.pk
+
+ pk = root_pk
+ return self.resolve_url(ACTION_LIST, args=(pk,))
+
+ class DetailView(Crud.DetailView):
+ permission_required = RP_DETAIL,
+ template_name = 'crud/detail_detail.html'
+
+ @classmethod
+ def get_url_regex(cls):
+ return r'^%s/(?P\d+)$' % cls.model._meta.model_name
+
+ @property
+ def detail_list_url(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.ListView.permission_required or\
+ self.request.user.has_perm(self.permission(RP_LIST)):
+ if '__' in obj.parent_field:
+ fields = obj.parent_field.split('__')
+ parent_object = self.object
+ for field in fields:
+ parent_object = getattr(parent_object, field)
+ else:
+ parent_object = getattr(self.object, obj.parent_field)
+
+ if not isinstance(parent_object, models.Model):
+ if parent_object.count() > 1:
+ if 'pkk' not in self.request.GET:
+ raise Http404
+ root_pk = self.request.GET['pkk']
+ parent_object = parent_object.filter(id=root_pk)
+
+ parent_object = parent_object.first()
+
+ if not parent_object:
+ raise Http404
+ root_pk = parent_object.pk
+
+ pk = root_pk
+ return self.resolve_url(ACTION_LIST, args=(pk,))
+ else:
+ return ''
+
+ @property
+ def detail_create_url(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ if not obj.CreateView:
+ return ''
+
+ if self.request.user.has_perm(self.permission(RP_ADD)):
+ parent_field = obj.parent_field.split('__')[0]
+ parent_object = getattr(self.object, parent_field)
+
+ if not isinstance(parent_object, models.Model):
+ if parent_object.count() > 1:
+ if 'pkk' not in self.request.GET:
+ raise Http404
+ root_pk = self.request.GET['pkk']
+ parent_object = parent_object.filter(id=root_pk)
+
+ parent_object = parent_object.first()
+
+ if not parent_object:
+ raise Http404
+ root_pk = parent_object.pk
+ pk = root_pk
+ return self.resolve_url(ACTION_CREATE, args=(pk,))
+ else:
+ return ''
+
+ @property
+ def detail_set_create_url(self):
+ obj = self.crud if hasattr(self, 'crud') else self
+ if hasattr(obj, 'model_set') and obj.model_set\
+ and self.request.user.has_perm(
+ self.permission_set(RP_ADD)):
+ root_pk = self.object .pk
+ pk = root_pk
+ return self.resolve_url_set(ACTION_CREATE, args=(pk,))
+ else:
+ return ''
+
+ @property
+ def detail_root_detail_url(self):
+ """
+ Implementar retorno para o parent_field imediato no caso de
+ edição em cascata de MasterDetailDetail...
+ """
+ return ''
+
+ obj = self.crud if hasattr(self, 'crud') else self
+ if hasattr(obj, 'parent_field'):
+ # parent_field = obj.parent_field.split('__')[0]
+
+ root_pk = self.object .pk
+ pk = root_pk
+ return self.resolve_url(ACTION_DELETE, args=(pk,))
+ else:
+ return ''
+
+ @classonlymethod
+ def build(cls, model, parent_field, help_path,
+ _model_set=None, list_field_names=[]):
+ crud = super(MasterDetailCrud, cls).build(
+ model, help_path, _model_set=_model_set,
+ list_field_names=list_field_names)
+ crud.parent_field = parent_field
+ return crud
+
+
+class CrudBaseForListAndDetailExternalAppView(MasterDetailCrud):
+ CreateView, UpdateView, DeleteView = None, None, None
+
+ class BaseMixin(Crud.PublicMixin, MasterDetailCrud.BaseMixin):
+
+ @classmethod
+ def url_name(cls, suffix):
+ return '%s_parlamentar_%s' % (cls.model._meta.model_name, suffix)
+
+ def resolve_url(self, suffix, args=None):
+ obj = self.crud if hasattr(self, 'crud') else self
+
+ """ namespace deve ser redirecionado para app local pois
+ o models colocados nos cruds que herdam este Crud são de outras app
+ """
+ return reverse('%s:%s' % (obj.namespace, self.url_name(suffix)),
+ args=args)
diff --git a/sapl/crud/masterdetail.py b/sapl/crud/masterdetail.py
deleted file mode 100644
index 2d0bf32d1..000000000
--- a/sapl/crud/masterdetail.py
+++ /dev/null
@@ -1,81 +0,0 @@
-from django.utils.decorators import classonlymethod
-
-from .base import (CREATE, LIST, Crud, CrudBaseMixin, CrudCreateView,
- CrudDeleteView, CrudDetailView, CrudListView,
- CrudUpdateView)
-
-
-class MasterDetailCrud(Crud):
-
- class BaseMixin(CrudBaseMixin):
-
- @property
- def list_url(self):
- return self.resolve_url(LIST, args=(self.kwargs['pk'],))
-
- @property
- def create_url(self):
- return self.resolve_url(CREATE, args=(self.kwargs['pk'],))
-
- def get_context_data(self, **kwargs):
- obj = getattr(self, 'object', None)
- if obj:
- root_pk = getattr(obj, self.crud.parent_field).pk
- else:
- root_pk = self.kwargs['pk'] # in list and create
- kwargs.setdefault('root_pk', root_pk)
- return super(MasterDetailCrud.BaseMixin,
- self).get_context_data(**kwargs)
-
- class ListView(CrudListView):
-
- @classmethod
- def get_url_regex(cls):
- return r'^(?P\d+)/%s$' % cls.model._meta.model_name
-
- def get_queryset(self):
- qs = super(MasterDetailCrud.ListView, self).get_queryset()
- kwargs = {self.crud.parent_field: self.kwargs['pk']}
- return qs.filter(**kwargs)
-
- class CreateView(CrudCreateView):
-
- @classmethod
- def get_url_regex(cls):
- return r'^(?P\d+)/%s/create$' % cls.model._meta.model_name
-
- def get_form(self, form_class=None):
- form = super(MasterDetailCrud.CreateView,
- self).get_form(self.form_class)
- field = self.model._meta.get_field(self.crud.parent_field)
- parent = field.related_model.objects.get(pk=self.kwargs['pk'])
- setattr(form.instance, self.crud.parent_field, parent)
- return form
-
- class DetailView(CrudDetailView):
-
- @classmethod
- def get_url_regex(cls):
- return r'^%s/(?P\d+)$' % cls.model._meta.model_name
-
- class UpdateView(CrudUpdateView):
-
- @classmethod
- def get_url_regex(cls):
- return r'^%s/(?P\d+)/edit$' % cls.model._meta.model_name
-
- class DeleteView(CrudDeleteView):
-
- @classmethod
- def get_url_regex(cls):
- return r'^%s/(?P\d+)/delete$' % cls.model._meta.model_name
-
- def get_success_url(self):
- pk = getattr(self.get_object(), self.crud.parent_field).pk
- return self.resolve_url(LIST, args=(pk,))
-
- @classonlymethod
- def build(cls, model, parent_field, help_path):
- crud = super(MasterDetailCrud, cls).build(model, help_path)
- crud.parent_field = parent_field
- return crud
diff --git a/sapl/legacy/management/commands/migracao_25_31.py b/sapl/legacy/management/commands/migracao_25_31.py
index 199075d44..f01b8117a 100644
--- a/sapl/legacy/management/commands/migracao_25_31.py
+++ b/sapl/legacy/management/commands/migracao_25_31.py
@@ -1,4 +1,5 @@
from django.core.management.base import BaseCommand
+
from sapl.legacy import migration
diff --git a/sapl/lexml/views.py b/sapl/lexml/views.py
index 5c988e43f..3627d5829 100644
--- a/sapl/lexml/views.py
+++ b/sapl/lexml/views.py
@@ -1,6 +1,6 @@
-from sapl.crud.base import Crud
+from sapl.crud.base import CrudAux
from .models import LexmlProvedor, LexmlPublicador
-LexmlProvedorCrud = Crud.build(LexmlProvedor, 'lexml_provedor')
-LexmlPublicadorCrud = Crud.build(LexmlPublicador, 'lexml_publicador')
+LexmlProvedorCrud = CrudAux.build(LexmlProvedor, 'lexml_provedor')
+LexmlPublicadorCrud = CrudAux.build(LexmlPublicador, 'lexml_publicador')
diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py
index 16c5641e2..f4575658a 100644
--- a/sapl/materia/forms.py
+++ b/sapl/materia/forms.py
@@ -1,6 +1,5 @@
from datetime import datetime
-import django_filters
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout
from django import forms
@@ -12,6 +11,7 @@ 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 _
+import django_filters
from sapl.comissoes.models import Comissao
from sapl.crispy_layout_mixin import form_actions, to_row
@@ -27,6 +27,7 @@ from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria,
Numeracao, Proposicao, Relatoria, TipoMateriaLegislativa,
Tramitacao, UnidadeTramitacao)
+
ANO_CHOICES = [('', '---------')] + RANGE_ANOS
@@ -192,9 +193,9 @@ class RelatoriaForm(ModelForm):
widgets = {'comissao': forms.Select(attrs={'disabled': 'disabled'})}
def __init__(self, *args, **kwargs):
- super(RelatoriaForm, self).__init__(*args, **kwargs)
- self.fields['parlamentar'].queryset = Parlamentar.objects.filter(
- ativo=True).order_by('nome_completo')
+ super(RelatoriaForm, self).__init__(*args, **kwargs)
+ self.fields['parlamentar'].queryset = Parlamentar.objects.filter(
+ ativo=True).order_by('nome_completo')
def clean(self):
cleaned_data = self.cleaned_data
@@ -427,6 +428,10 @@ class AnexadaForm(ModelForm):
ano = forms.CharField(label='Ano', required=True)
+ def __init__(self, *args, **kwargs):
+
+ return super(AnexadaForm, self).__init__(*args, **kwargs)
+
def clean(self):
if self.errors:
return self.errors
diff --git a/sapl/materia/migrations/0050_auto_20161003_0417.py b/sapl/materia/migrations/0050_auto_20161003_0417.py
new file mode 100644
index 000000000..2506b31a9
--- /dev/null
+++ b/sapl/materia/migrations/0050_auto_20161003_0417.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.7 on 2016-10-03 07:17
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('materia', '0049_remove_autoria_partido'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='tramitacao',
+ options={'ordering': ('data_tramitacao',), 'verbose_name': 'Tramitação', 'verbose_name_plural': 'Tramitações'},
+ ),
+ ]
diff --git a/sapl/materia/models.py b/sapl/materia/models.py
index 2e40cde6f..8927057d3 100644
--- a/sapl/materia/models.py
+++ b/sapl/materia/models.py
@@ -6,8 +6,8 @@ from model_utils import Choices
from sapl.comissoes.models import Comissao
from sapl.parlamentares.models import Parlamentar, Partido
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
- restringe_tipos_de_arquivo_txt, xstr,
- get_settings_auth_user_model)
+ get_settings_auth_user_model,
+ restringe_tipos_de_arquivo_txt, xstr)
def grupo_autor():
@@ -589,6 +589,7 @@ class Tramitacao(models.Model):
class Meta:
verbose_name = _('Tramitação')
verbose_name_plural = _('Tramitações')
+ ordering = 'data_tramitacao',
def __str__(self):
return _('%(materia)s | %(status)s | %(data)s') % {
diff --git a/sapl/materia/tests/test_materia.py b/sapl/materia/tests/test_materia.py
index 953546c27..c7ca7d721 100644
--- a/sapl/materia/tests/test_materia.py
+++ b/sapl/materia/tests/test_materia.py
@@ -1,8 +1,8 @@
+import pytest
from django.contrib.auth import get_user_model
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.urlresolvers import reverse
from model_mommy import mommy
-import pytest
from sapl.comissoes.models import Comissao, TipoComissao
from sapl.materia.models import (Anexada, Autor, Autoria, DespachoInicial,
diff --git a/sapl/materia/views.py b/sapl/materia/views.py
index 75cd34b94..b7ddbc233 100644
--- a/sapl/materia/views.py
+++ b/sapl/materia/views.py
@@ -26,25 +26,20 @@ 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,
- CrudDeleteView, CrudDetailView, CrudListView,
- CrudUpdateView, make_pagination)
-from sapl.crud.masterdetail import MasterDetailCrud
+from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, CrudDetailView,
+ MasterDetailCrud, make_pagination)
+from sapl.materia.forms import AnexadaForm
from sapl.norma.models import LegislacaoCitada
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
autor_modal, gerar_hash_arquivo, get_base_url,
- permissao_tb_aux, permissoes_autor, permissoes_materia,
+ permissoes_autor, permissoes_materia,
permissoes_protocoloadm)
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
- AnexadaForm, AutorForm, AutoriaForm,
- ConfirmarProposicaoForm, DespachoInicialForm,
- DocumentoAcessorioForm, LegislacaoCitadaForm,
- MateriaLegislativaFilterSet, NumeracaoForm,
+ AutorForm, ConfirmarProposicaoForm, DocumentoAcessorioForm,
+ MateriaLegislativaFilterSet,
PrimeiraTramitacaoEmLoteFilterSet, ProposicaoForm,
- ReceberProposicaoForm, RelatoriaForm,
- TramitacaoEmLoteFilterSet, TramitacaoForm,
- TramitacaoUpdateForm, UnidadeTramitacaoForm,
+ ReceberProposicaoForm, TramitacaoEmLoteFilterSet,
filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status,
filtra_tramitacao_status)
@@ -55,8 +50,26 @@ from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria,
TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao,
Tramitacao, UnidadeTramitacao)
+
AnexadaCrud = Crud.build(Anexada, '')
+OrigemCrud = Crud.build(Origem, '')
+
+TipoMateriaCrud = CrudAux.build(
+ TipoMateriaLegislativa, 'tipo_materia_legislativa')
+
+RegimeTramitacaoCrud = CrudAux.build(
+ RegimeTramitacao, 'regime_tramitacao')
+
+TipoDocumentoCrud = CrudAux.build(
+ TipoDocumento, 'tipo_documento')
+
+TipoFimRelatoriaCrud = CrudAux.build(
+ TipoFimRelatoria, 'fim_relatoria')
+
+TipoAutorCrud = CrudAux.build(
+ TipoAutor, 'regime_tramitacao')
+
def recuperar_materia(request):
tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo'])
@@ -70,66 +83,6 @@ def recuperar_materia(request):
return response
-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)
-
-
def montar_helper_autor(self):
autor_row = montar_row_autor('nome')
self.helper = FormHelper()
@@ -152,18 +105,14 @@ def montar_helper_autor(self):
' class="btn btn-inverse">Cancelar')]))
-class AutorCrud(Crud):
+class AutorCrud(CrudAux):
model = Autor
help_path = 'autor'
- class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
+ class BaseMixin(CrudAux.BaseMixin):
list_field_names = ['tipo', 'nome']
- def has_permission(self):
- return permissao_tb_aux(self)
-
- class UpdateView(CrudUpdateView):
- form_class = AutorForm
+ class UpdateView(CrudAux.UpdateView):
layout_key = 'AutorCreate'
def __init__(self, *args, **kwargs):
@@ -175,7 +124,7 @@ class AutorCrud(Crud):
context['helper'] = self.helper
return context
- class CreateView(CrudCreateView):
+ class CreateView(CrudAux.CreateView):
form_class = AutorForm
layout_key = 'AutorCreate'
@@ -229,34 +178,10 @@ class ConfirmarEmailView(TemplateView):
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)
+OrgaoCrud = CrudAux.build(Orgao, 'orgao')
+TipoProposicaoCrud = CrudAux.build(TipoProposicao, 'tipo_proposicao')
+StatusTramitacaoCrud = CrudAux.build(StatusTramitacao, 'status_tramitacao')
+UnidadeTramitacaoCrud = CrudAux.build(UnidadeTramitacao, 'unidade_tramitacao')
def criar_materia_proposicao(proposicao):
@@ -296,22 +221,6 @@ def criar_doc_proposicao(proposicao):
)
-class UnidadeTramitacaoCrud(Crud):
- model = UnidadeTramitacao
- help_path = 'unidade_tramitacao'
-
- class CreateView(PermissionRequiredMixin, CrudCreateView):
- permission_required = permissoes_materia()
- form_class = UnidadeTramitacaoForm
-
- class UpdateView(PermissionRequiredMixin, CrudUpdateView):
- permission_required = permissoes_materia()
- form_class = UnidadeTramitacaoForm
-
- class DeleteView(PermissionRequiredMixin, CrudDeleteView):
- permission_required = permissoes_materia()
-
-
class ProposicaoDevolvida(PermissionRequiredMixin, ListView):
template_name = 'materia/prop_devolvidas_list.html'
model = Proposicao
@@ -457,13 +366,12 @@ class ProposicaoCrud(Crud):
model = Proposicao
help_path = ''
- class BaseMixin(CrudBaseMixin):
+ class BaseMixin(Crud.BaseMixin):
list_field_names = ['data_envio', 'descricao',
'tipo', 'data_recebimento']
- class CreateView(PermissionRequiredMixin, CrudCreateView):
+ class CreateView(Crud.CreateView):
form_class = ProposicaoForm
- permission_required = {'materia.add_proposicao'}
@property
def layout_key(self):
@@ -489,9 +397,8 @@ class ProposicaoCrud(Crud):
else:
return {'autor': autor_id}
- class UpdateView(PermissionRequiredMixin, CrudUpdateView):
+ class UpdateView(Crud.UpdateView):
form_class = ProposicaoForm
- permission_required = permissoes_autor()
def get_initial(self):
initial = self.initial.copy()
@@ -525,8 +432,7 @@ class ProposicaoCrud(Crud):
messages.add_message(self.request, messages.ERROR, msg)
return False
- class DetailView(PermissionRequiredMixin, CrudDetailView):
- permission_required = permissoes_autor()
+ class DetailView(Crud.DetailView):
def has_permission(self):
perms = self.get_permission_required()
@@ -542,9 +448,8 @@ class ProposicaoCrud(Crud):
context['subnav_template_name'] = ''
return context
- class ListView(PermissionRequiredMixin, CrudListView):
+ class ListView(Crud.ListView):
ordering = ['-data_envio', 'descricao']
- permission_required = permissoes_autor()
def get_rows(self, object_list):
@@ -572,8 +477,7 @@ class ProposicaoCrud(Crud):
return lista
- class DeleteView(PermissionRequiredMixin, CrudDeleteView):
- permission_required = {'materia.delete_proposicao'}
+ class DeleteView(Crud.DeleteView):
def has_permission(self):
perms = self.get_permission_required()
@@ -636,10 +540,9 @@ class RelatoriaCrud(MasterDetailCrud):
model = Relatoria
parent_field = 'materia'
help_path = ''
+ public = [RP_LIST, RP_DETAIL]
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- permission_required = permissoes_materia()
- form_class = RelatoriaForm
+ class CreateView(MasterDetailCrud.CreateView):
def get_initial(self):
materia = MateriaLegislativa.objects.get(id=self.kwargs['pk'])
@@ -658,26 +561,20 @@ class RelatoriaCrud(MasterDetailCrud):
return {'comissao': localizacao}
- 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
parent_field = 'materia'
help_path = ''
+ public = [RP_LIST, RP_DETAIL]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['data_tramitacao', 'unidade_tramitacao_local',
'unidade_tramitacao_destino', 'status']
+ ordered_list = False
+ ordering = '-data_tramitacao',
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- form_class = TramitacaoForm
- permission_required = permissoes_materia()
+ class CreateView(MasterDetailCrud.CreateView):
def get_initial(self):
local = MateriaLegislativa.objects.get(
@@ -692,9 +589,7 @@ class TramitacaoCrud(MasterDetailCrud):
do_envia_email_tramitacao(request, materia)
return super(CreateView, self).post(request, *args, **kwargs)
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
- form_class = TramitacaoUpdateForm
- permission_required = permissoes_materia()
+ class UpdateView(MasterDetailCrud.UpdateView):
def post(self, request, *args, **kwargs):
materia = MateriaLegislativa.objects.get(
@@ -713,8 +608,7 @@ class TramitacaoCrud(MasterDetailCrud):
kwargs = {self.crud.parent_field: self.kwargs['pk']}
return qs.filter(**kwargs).order_by('-data_tramitacao', '-id')
- class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
- permission_required = permissoes_materia()
+ class DeleteView(MasterDetailCrud.DeleteView):
def delete(self, request, *args, **kwargs):
tramitacao = Tramitacao.objects.get(id=self.kwargs['pk'])
@@ -767,78 +661,56 @@ class DocumentoAcessorioCrud(MasterDetailCrud):
model = DocumentoAcessorio
parent_field = 'materia'
help_path = ''
+ public = [RP_LIST, RP_DETAIL]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['nome', 'tipo', 'data', 'autor', 'arquivo']
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
+ class CreateView(MasterDetailCrud.CreateView):
form_class = DocumentoAcessorioForm
- permission_required = permissoes_materia()
- def __init__(self, *args, **kwargs):
+ def __init__(self, **kwargs):
montar_helper_documento_acessorio(self)
- super(CreateView, self).__init__(*args, **kwargs)
+ super(MasterDetailCrud.CreateView, self).__init__(**kwargs)
def get_context_data(self, **kwargs):
- context = super(CreateView, self).get_context_data(**kwargs)
+ context = super(
+ MasterDetailCrud.CreateView, self).get_context_data(**kwargs)
context['helper'] = self.helper
return context
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
+ class UpdateView(MasterDetailCrud.UpdateView):
form_class = DocumentoAcessorioForm
- permission_required = permissoes_materia()
- def __init__(self, *args, **kwargs):
+ def __init__(self, **kwargs):
montar_helper_documento_acessorio(self)
- super(UpdateView, self).__init__(*args, **kwargs)
+ super(MasterDetailCrud.UpdateView, self).__init__(**kwargs)
def get_context_data(self, **kwargs):
context = super(UpdateView, self).get_context_data(**kwargs)
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(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- form_class = AutoriaForm
- permission_required = permissoes_materia()
-
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
- form_class = AutoriaForm
- permission_required = permissoes_materia()
-
- class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
- permission_required = permissoes_materia()
+ public = [RP_LIST, RP_DETAIL]
class DespachoInicialCrud(MasterDetailCrud):
model = DespachoInicial
parent_field = 'materia'
help_path = ''
-
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- form_class = DespachoInicialForm
- permission_required = permissoes_materia()
-
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
- form_class = DespachoInicialForm
- permission_required = permissoes_materia()
-
- class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
- permission_required = permissoes_materia()
+ public = [RP_LIST, RP_DETAIL]
class LegislacaoCitadaCrud(MasterDetailCrud):
model = LegislacaoCitada
parent_field = 'materia'
help_path = ''
+ public = [RP_LIST, RP_DETAIL]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['norma', 'disposicoes']
@@ -848,13 +720,7 @@ class LegislacaoCitadaCrud(MasterDetailCrud):
return reverse('%s:%s' % (namespace, self.url_name(suffix)),
args=args)
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- form_class = LegislacaoCitadaForm
- permission_required = permissoes_materia()
-
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
- form_class = LegislacaoCitadaForm
- permission_required = permissoes_materia()
+ class UpdateView(MasterDetailCrud.UpdateView):
def get_initial(self):
self.initial['tipo'] = self.object.norma.tipo.id
@@ -862,9 +728,6 @@ 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
@@ -876,69 +739,35 @@ class NumeracaoCrud(MasterDetailCrud):
model = Numeracao
parent_field = 'materia'
help_path = ''
-
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- form_class = NumeracaoForm
- permission_required = permissoes_materia()
-
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
- form_class = NumeracaoForm
- permission_required = permissoes_materia()
-
- class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
- permission_required = permissoes_materia()
+ public = [RP_LIST, RP_DETAIL]
class AnexadaCrud(MasterDetailCrud):
model = Anexada
parent_field = 'materia_principal'
help_path = ''
+ public = [RP_LIST, RP_DETAIL]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['materia_anexada', 'data_anexacao']
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- form_class = AnexadaForm
- permission_required = permissoes_materia()
-
- 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
- self.initial['numero'] = self.object.materia_anexada.numero
- self.initial['ano'] = self.object.materia_anexada.ano
-
- return self.initial
-
class DetailView(MasterDetailCrud.DetailView):
@property
def layout_key(self):
return 'AnexadaDetail'
- class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
- permission_required = permissoes_materia()
-
class MateriaLegislativaCrud(Crud):
model = MateriaLegislativa
help_path = 'materia_legislativa'
+ public = [RP_LIST, RP_DETAIL]
- class BaseMixin(CrudBaseMixin):
+ class BaseMixin(Crud.BaseMixin):
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()
-
+# FIXME - qual a finalidade dessa classe??
class DocumentoAcessorioView(PermissionRequiredMixin, CreateView):
template_name = "materia/documento_acessorio.html"
form_class = DocumentoAcessorioForm
diff --git a/sapl/norma/views.py b/sapl/norma/views.py
index 396695f13..27f8b94dd 100644
--- a/sapl/norma/views.py
+++ b/sapl/norma/views.py
@@ -1,46 +1,33 @@
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,
- CrudDeleteView, CrudUpdateView, make_pagination)
-from sapl.utils import permissoes_norma
+from sapl.crud.base import RP_DETAIL, RP_LIST, Crud, CrudAux, make_pagination
-from .forms import NormaJuridicaForm, NormaJuridicaPesquisaForm
+from .forms import NormaJuridicaPesquisaForm
from .models import (AssuntoNorma, LegislacaoCitada, NormaJuridica,
TipoNormaJuridica)
LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '')
-class AssuntoNormaCrud(Crud):
- model = AssuntoNorma
- help_path = 'assunto_norma_juridica'
+AssuntoNormaCrud = CrudAux.build(AssuntoNorma, 'assunto_norma_juridica',
+ list_field_names=['assunto', 'descricao'])
- 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']
+TipoNormaCrud = CrudAux.build(
+ TipoNormaJuridica, 'tipo_norma_juridica',
+ list_field_names=['equivalente_lexml', 'sigla', 'descricao'])
class NormaCrud(Crud):
model = NormaJuridica
help_path = 'norma_juridica'
+ public = [RP_LIST, RP_DETAIL]
- class UpdateView(PermissionRequiredMixin, CrudUpdateView):
- form_class = NormaJuridicaForm
- permission_required = permissoes_norma()
+ class UpdateView(Crud.UpdateView):
@property
def layout_key(self):
@@ -54,18 +41,13 @@ class NormaCrud(Crud):
self.initial['numero_materia'] = norma.materia.numero
return self.initial.copy()
- class CreateView(PermissionRequiredMixin, CrudCreateView):
- form_class = NormaJuridicaForm
- permission_required = permissoes_norma()
+ class CreateView(Crud.CreateView):
@property
def layout_key(self):
return 'NormaJuridicaCreate'
- class DeleteView(PermissionRequiredMixin, CrudDeleteView):
- permission_required = permissoes_norma()
-
- class BaseMixin(CrudBaseMixin):
+ class BaseMixin(Crud.BaseMixin):
list_field_names = ['tipo', 'numero', 'ano', 'ementa']
diff --git a/sapl/parlamentares/migrations/0032_frenteproxymasterdetail.py b/sapl/parlamentares/migrations/0032_frenteproxymasterdetail.py
new file mode 100644
index 000000000..8974be563
--- /dev/null
+++ b/sapl/parlamentares/migrations/0032_frenteproxymasterdetail.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.7 on 2016-09-30 20:09
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('parlamentares', '0031_auto_20160929_1842'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='FrenteProxyMasterDetail',
+ fields=[
+ ],
+ options={
+ 'proxy': True,
+ },
+ bases=('parlamentares.frente',),
+ ),
+ ]
diff --git a/sapl/parlamentares/migrations/0033_auto_20160930_1715.py b/sapl/parlamentares/migrations/0033_auto_20160930_1715.py
new file mode 100644
index 000000000..14591d16c
--- /dev/null
+++ b/sapl/parlamentares/migrations/0033_auto_20160930_1715.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.7 on 2016-09-30 20:15
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('parlamentares', '0032_frenteproxymasterdetail'),
+ ]
+
+ operations = [
+ migrations.DeleteModel(
+ name='FrenteProxyMasterDetail',
+ ),
+ migrations.CreateModel(
+ name='FrenteParlamentar',
+ fields=[
+ ],
+ options={
+ 'proxy': True,
+ 'verbose_name': 'Frente',
+ 'verbose_name_plural': 'Frentes',
+ },
+ bases=('parlamentares.frente',),
+ ),
+ ]
diff --git a/sapl/parlamentares/migrations/0034_delete_frenteparlamentar.py b/sapl/parlamentares/migrations/0034_delete_frenteparlamentar.py
new file mode 100644
index 000000000..4c5e8d710
--- /dev/null
+++ b/sapl/parlamentares/migrations/0034_delete_frenteparlamentar.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.7 on 2016-09-30 21:43
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('parlamentares', '0033_auto_20160930_1715'),
+ ]
+
+ operations = [
+ migrations.DeleteModel(
+ name='FrenteParlamentar',
+ ),
+ ]
diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py
index 0c06c8746..c1948ceb3 100644
--- a/sapl/parlamentares/models.py
+++ b/sapl/parlamentares/models.py
@@ -267,6 +267,19 @@ class Parlamentar(models.Model):
def __str__(self):
return self.nome_completo
+ @property
+ def filiacao_atual(self):
+ ultima_filiacao = self.filiacao_set.order_by('-data').first()
+ if ultima_filiacao and not ultima_filiacao.data_desfiliacao:
+ return ultima_filiacao.partido.sigla
+ else:
+ return _('Sem Partido')
+
+ @property
+ def avatar_html(self):
+ return ''if self.fotografia else ''
+
class TipoDependente(models.Model):
descricao = models.CharField(max_length=50, verbose_name=_('Descrição'))
diff --git a/sapl/parlamentares/urls.py b/sapl/parlamentares/urls.py
index 70af2200a..a977992f8 100644
--- a/sapl/parlamentares/urls.py
+++ b/sapl/parlamentares/urls.py
@@ -23,12 +23,9 @@ urlpatterns = [
FiliacaoCrud.get_urls() + MandatoCrud.get_urls() +
ParticipacaoParlamentarCrud.get_urls() +
ProposicaoParlamentarCrud.get_urls() +
- RelatoriaParlamentarCrud.get_urls()
+ RelatoriaParlamentarCrud.get_urls() + FrenteList.get_urls()
)),
- url(r'^parlamentar/(?P\d+)/frente$',
- FrenteList.as_view(), name="frent_list"),
-
url(r'^sistema/coligacao/',
include(ColigacaoCrud.get_urls() +
ComposicaoColigacaoCrud.get_urls())),
diff --git a/sapl/parlamentares/views.py b/sapl/parlamentares/views.py
index 9d3dde7c5..105bd0679 100644
--- a/sapl/parlamentares/views.py
+++ b/sapl/parlamentares/views.py
@@ -1,126 +1,88 @@
+
from django.contrib import messages
-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 ObjectDoesNotExist
from django.core.urlresolvers import reverse, 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, ListView
+from django.views.generic import FormView
from sapl.comissoes.models import Participacao
-from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView,
- CrudDeleteView, CrudDetailView, CrudListView,
- CrudUpdateView)
-from sapl.crud.masterdetail import MasterDetailCrud
+from sapl.crud.base import (RP_CHANGE, RP_DETAIL, RP_LIST, Crud, CrudAux,
+ CrudBaseForListAndDetailExternalAppView,
+ MasterDetailCrud)
from sapl.materia.models import Proposicao, Relatoria
-from sapl.utils import permissao_tb_aux, permissoes_parlamentares
+from sapl.parlamentares.apps import AppConfig
-from .forms import (ComposicaoColigacaoForm, FiliacaoForm, FrenteForm,
- LegislaturaForm, ParlamentarCreateForm, ParlamentarForm)
+from .forms import LegislaturaForm, ParlamentarCreateForm, ParlamentarForm
from .models import (CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa,
Dependente, Filiacao, Frente, Legislatura, Mandato,
NivelInstrucao, Parlamentar, Partido, SessaoLegislativa,
SituacaoMilitar, TipoAfastamento, TipoDependente)
+CargoMesaCrud = CrudAux.build(CargoMesa, 'cargo_mesa')
+PartidoCrud = CrudAux.build(Partido, 'partidos')
+SessaoLegislativaCrud = CrudAux.build(SessaoLegislativa, 'sessao_legislativa')
+TipoDependenteCrud = CrudAux.build(TipoDependente, 'tipo_dependente')
+NivelInstrucaoCrud = CrudAux.build(NivelInstrucao, 'nivel_instrucao')
+TipoAfastamentoCrud = CrudAux.build(TipoAfastamento, 'tipo_afastamento')
+TipoMilitarCrud = CrudAux.build(SituacaoMilitar, 'tipo_situa_militar')
-class FrenteList(ListView):
- model = Frente
- paginate_by = 10
- template_name = 'parlamentares/frentes.html'
-
- def get_queryset(self):
- return Frente.objects.filter(parlamentares__in=[self.kwargs['pk']])
+FrenteCrud = CrudAux.build(Frente, 'tipo_situa_militar', list_field_names=[
+ 'nome', 'data_criacao', 'parlamentares'])
- def get_context_data(self, **kwargs):
- context = super(FrenteList, self).get_context_data(**kwargs)
- context['root_pk'] = self.kwargs['pk']
- context['object_list'] = self.get_queryset()
- return context
+DependenteCrud = MasterDetailCrud.build(
+ Dependente, 'parlamentar', 'dependente')
-class FrenteCrud(Crud):
+class FrenteList(MasterDetailCrud):
model = Frente
- help_path = ''
-
- class BaseMixin(CrudBaseMixin):
- list_field_names = ['nome', 'data_criacao', 'parlamentares']
+ is_m2m = True
+ parent_field = 'parlamentares'
+ CreateView, UpdateView, DeleteView = None, None, None
- def has_permission(self):
- return permissao_tb_aux(self)
+ class BaseMixin(Crud.PublicMixin, MasterDetailCrud.BaseMixin):
+ list_field_names = ['nome', 'data_criacao']
- class CreateView(PermissionRequiredMixin, CrudCreateView):
- form_class = FrenteForm
+ @classmethod
+ def url_name(cls, suffix):
+ return '%s_parlamentar_%s' % (cls.model._meta.model_name, suffix)
- class UpdateView(PermissionRequiredMixin, CrudUpdateView):
- form_class = FrenteForm
-
-class RelatoriaParlamentarCrud(MasterDetailCrud):
+class RelatoriaParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
model = Relatoria
parent_field = 'parlamentar'
- help_path = ''
-
- class ListView(MasterDetailCrud.ListView):
- permission_required = permissoes_parlamentares()
+ help_path = 'relatoria_parlamentar'
+ namespace = AppConfig.name
- 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 ProposicaoParlamentarCrud(MasterDetailCrud):
+class ProposicaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
model = Proposicao
+ list_field_names = ['tipo', 'descricao']
parent_field = 'autor__parlamentar'
- help_path = ''
+ namespace = AppConfig.name
- class BaseMixin(CrudBaseMixin):
- list_field_names = ['tipo', 'descricao']
-
- class ListView(MasterDetailCrud.ListView):
- permission_required = permissoes_parlamentares()
-
- def get_context_data(self, **kwargs):
- context = super(ProposicaoParlamentarCrud.ListView, self
- ).get_context_data(**kwargs)
- context['root_pk'] = self.kwargs['pk']
- return context
+ class ListView(CrudBaseForListAndDetailExternalAppView.ListView):
def get_queryset(self):
- try:
- proposicoes = Proposicao.objects.filter(
- autor__parlamentar_id=self.kwargs['pk'],
- data_envio__isnull=False)
- except ObjectDoesNotExist:
- return []
- else:
- return proposicoes
-
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- permission_required = permissoes_parlamentares()
-
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
- permission_required = permissoes_parlamentares()
+ return super().get_queryset().filter(
+ autor__parlamentar_id=self.kwargs['pk'],
+ data_envio__isnull=False)
- class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
- permission_required = permissoes_parlamentares()
-
-class ParticipacaoParlamentarCrud(MasterDetailCrud):
+class ParticipacaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
model = Participacao
parent_field = 'parlamentar'
- help_path = ''
+ namespace = AppConfig.name
+ list_field_names = ['composicao__comissao__nome', 'cargo__nome', (
+ 'composicao__periodo__data_inicio', 'composicao__periodo__data_fim')]
- class ListView(MasterDetailCrud.ListView):
+ class ListView(CrudBaseForListAndDetailExternalAppView.ListView):
ordering = ('-composicao__periodo')
def get_rows(self, object_list):
+ """
+ FIXME:
+ Este metodo não será necessário quando get_rows for refatorada
+ """
+
comissoes = []
for p in object_list:
if p.cargo.nome != 'Relator':
@@ -138,324 +100,141 @@ class ParticipacaoParlamentarCrud(MasterDetailCrud):
return comissoes
def get_headers(self):
- return ['Comissão', 'Cargo', 'Período']
-
- 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 CargoMesaCrud(Crud):
- model = CargoMesa
- help_path = 'cargo_mesa'
-
- class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
-
- def has_permission(self):
- return permissao_tb_aux(self)
-
+ return [_('Comissão'), _('Cargo'), _('Período de participação'), ]
-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 ColigacaoCrud(CrudAux):
+ model = Coligacao
+ help_path = 'tabelas_auxiliares#coligacao'
- class ListView(PermissionRequiredMixin, MasterDetailCrud.ListView):
- permission_required = permissoes_parlamentares()
+ class ListView(CrudAux.ListView):
+ ordering = ('-numero_votos', 'nome')
- class DetailView(PermissionRequiredMixin, MasterDetailCrud.DetailView):
- permission_required = permissoes_parlamentares()
+ class BaseMixin(CrudAux.BaseMixin):
+ subnav_template_name = 'parlamentares/subnav_coligacao.yaml'
class MandatoCrud(MasterDetailCrud):
model = Mandato
parent_field = 'parlamentar'
- help_path = ''
+ public = [RP_DETAIL, RP_LIST]
class ListView(MasterDetailCrud.ListView):
ordering = ('-legislatura__numero')
- 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
- help_path = 'tabelas_auxiliares#coligacao'
-
- class ListView(CrudListView):
- ordering = ('-numero_votos', 'nome')
-
- class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
-
- def has_permission(self):
- return permissao_tb_aux(self)
-
class ComposicaoColigacaoCrud(MasterDetailCrud):
model = ComposicaoColigacao
parent_field = 'coligacao'
help_path = ''
- class CreateView(MasterDetailCrud.CreateView):
- form_class = ComposicaoColigacaoForm
-
- def get_initial(self):
- id = self.kwargs['pk']
- return {'coligacao_id': id}
+ class BaseMixin(MasterDetailCrud.BaseMixin):
- class UpdateView(MasterDetailCrud.UpdateView):
- form_class = ComposicaoColigacaoForm
-
- def get_initial(self):
- id = self.kwargs['pk']
- return {'coligacao_id': id}
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data()
+ context['subnav_template_name'] = \
+ 'parlamentares/subnav_coligacao.yaml'
+ return context
class ListView(MasterDetailCrud.ListView):
ordering = '-partido__sigla'
- class BaseMixin(PermissionRequiredMixin, MasterDetailCrud.BaseMixin):
-
- def has_permission(self):
- return permissao_tb_aux(self)
-
-class LegislaturaCrud(Crud):
+class LegislaturaCrud(CrudAux):
model = Legislatura
help_path = 'tabelas_auxiliares#legislatura'
- class CreateView(CrudCreateView):
- form_class = LegislaturaForm
-
- class UpdateView(CrudUpdateView):
+ class BaseMixin(CrudAux.BaseMixin):
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 = ''
+ public = [RP_LIST, RP_DETAIL]
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- form_class = FiliacaoForm
- permission_required = permissoes_parlamentares()
-
- 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):
+ class BaseMixin(MasterDetailCrud.BaseMixin):
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 DetailView(CrudDetailView):
+ public = [RP_LIST, RP_DETAIL]
- def get_template_names(self):
- usuario = self.request.user
- lista_permissoes = get_parlamentar_permissions()
+ class BaseMixin(Crud.BaseMixin):
+ form_class = ParlamentarCreateForm
+ ordered_list = False
+ list_field_names = [
+ 'avatar_html', 'nome_parlamentar', 'filiacao_atual', 'ativo']
- if usuario.has_perms(lista_permissoes):
- return ['crud/detail.html']
+ class DetailView(Crud.DetailView):
- else:
- return ['parlamentares/parlamentar_perfil_publico.html']
+ def get_template_names(self):
+ return ['crud/detail.html']\
+ if self.request.user.has_perm(self.permission(RP_CHANGE))\
+ else ['parlamentares/parlamentar_perfil_publico.html']
- class UpdateView(PermissionRequiredMixin, CrudUpdateView):
+ class UpdateView(Crud.UpdateView):
form_class = ParlamentarForm
- permission_required = permissoes_parlamentares()
- class CreateView(PermissionRequiredMixin, CrudCreateView):
- form_class = ParlamentarCreateForm
- permission_required = permissoes_parlamentares()
+ class CreateView(Crud.CreateView):
@property
def layout_key(self):
return 'ParlamentarCreate'
- class DeleteView(PermissionRequiredMixin, CrudDeleteView):
- form_class = ParlamentarCreateForm
- permission_required = permissoes_parlamentares()
+ def form_valid(self, form):
+ '''
+ Reimplementa form_valid devido ao save de ParlamentarCreateForm
+ ser específico, sendo necessário isolar padrão do crud que aciona
+ form.save(commit=False) para registrar dados de auditoria se
+ o model implementá-los, bem como de container se também implement.
+ '''
+ return super(Crud.CreateView, self).form_valid(form)
- class ListView(CrudListView):
+ class ListView(Crud.ListView):
template_name = "parlamentares/parlamentares_list.html"
paginate_by = None
- ordering = '-nome_parlamentar'
def take_legislatura_id(self):
- legislaturas = Legislatura.objects.all().order_by(
- '-numero')
-
- if legislaturas:
- try:
- legislatura_id = int(self.request.GET['periodo'])
- except MultiValueDictKeyError:
- for l in Legislatura.objects.all():
- if l.atual():
- return l.id
- return legislatura_id
- else:
+ try:
+ return int(self.request.GET['periodo'])
+ except:
+ for l in Legislatura.objects.all():
+ if l.atual():
+ return l.id
return 0
def get_queryset(self):
- if self.take_legislatura_id() != 0:
- mandatos = Mandato.objects.filter(
- legislatura_id=self.take_legislatura_id()).order_by(
- 'parlamentar__nome_parlamentar')
- return mandatos
- return []
+ queryset = super().get_queryset()
- def get_rows(self, object_list):
- parlamentares = []
- for m in object_list:
- ultima_filiacao = m.parlamentar.filiacao_set.order_by(
- '-data').first()
- if ultima_filiacao and not ultima_filiacao.data_desfiliacao:
- partido = ultima_filiacao.partido.sigla
- else:
- partido = _('Sem Partido')
-
- parlamentar = [
- ("" if m.parlamentar.fotografia
- else '', ''),
- (m.parlamentar.nome_parlamentar, m.parlamentar.id),
- (partido, None),
- ('Sim' if m.parlamentar.ativo else 'Não', None)
- ]
- parlamentares.append(parlamentar)
- return parlamentares
+ legislatura_id = self.take_legislatura_id()
+ if legislatura_id != 0:
+ queryset = queryset.filter(
+ mandato__legislatura_id=legislatura_id)
+ return queryset
def get_headers(self):
- return ['', 'Parlamentar', 'Partido', 'Ativo?']
+ return ['', _('Parlamentar'), _('Partido'), _('Ativo?')]
def get_context_data(self, **kwargs):
- context = super(ParlamentarCrud.ListView, self
- ).get_context_data(**kwargs)
- context.setdefault('title', self.verbose_name_plural)
+ context = super().get_context_data(**kwargs)
# Adiciona legislatura para filtrar parlamentares
- legislaturas = Legislatura.objects.all().order_by(
- '-numero')
+ legislaturas = Legislatura.objects.all().order_by('-numero')
context['legislaturas'] = legislaturas
context['legislatura_id'] = self.take_legislatura_id()
- 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))
+ # Tira Link do avatar_html e coloca no nome
+ for row in context['rows']:
+ row[1] = (row[1][0], row[0][1])
+ row[0] = (row[0][0], None)
+ return context
class MesaDiretoraView(FormView):
- template_name = "mesa_diretora/mesa_diretora.html"
+ template_name = 'parlamentares/composicaomesa_form.html'
success_url = reverse_lazy('sapl.parlamentares:mesa_diretora')
# Essa função avisa quando se pode compor uma Mesa Legislativa
@@ -474,18 +253,18 @@ class MesaDiretoraView(FormView):
def get(self, request, *args, **kwargs):
if (not Legislatura.objects.exists() or
- not SessaoLegislativa.objects.all()):
+ not SessaoLegislativa.objects.exists()):
return self.validation(request)
mesa = SessaoLegislativa.objects.filter(
- legislatura=Legislatura.objects.last()).first(
+ legislatura=Legislatura.objects.first()).first(
).composicaomesa_set.all()
cargos_ocupados = [m.cargo for m in mesa]
cargos = CargoMesa.objects.all()
cargos_vagos = list(set(cargos) - set(cargos_ocupados))
- parlamentares = Legislatura.objects.last().mandato_set.all()
+ parlamentares = Legislatura.objects.first().mandato_set.all()
parlamentares_ocupados = [m.parlamentar for m in mesa]
parlamentares_vagos = list(
set(
@@ -495,22 +274,25 @@ class MesaDiretoraView(FormView):
return self.render_to_response(
{'legislaturas': Legislatura.objects.all(
).order_by('-numero'),
- 'legislatura_selecionada': Legislatura.objects.last(),
+ 'legislatura_selecionada': Legislatura.objects.first(),
'sessoes': SessaoLegislativa.objects.filter(
- legislatura=Legislatura.objects.last()),
+ legislatura=Legislatura.objects.first()),
'sessao_selecionada': SessaoLegislativa.objects.filter(
- legislatura=Legislatura.objects.last()).first(),
+ legislatura=Legislatura.objects.first()).first(),
'composicao_mesa': mesa,
'parlamentares': parlamentares_vagos,
'cargos_vagos': cargos_vagos
})
def post(self, request, *args, **kwargs):
- if 'Incluir' in request.POST and check_permission_mesa(request):
- if (not Legislatura.objects.all() or
- not SessaoLegislativa.objects.all()):
- return self.validation(request)
+ if (not Legislatura.objects.exists() or
+ not SessaoLegislativa.objects.exists()):
+ return self.validation(request)
+
+ if 'Incluir' in request.POST and request.user.has_perm(
+ '%s.add_%s' % (
+ AppConfig.label, ComposicaoMesa._meta.model_name)):
composicao = ComposicaoMesa()
composicao.sessao_legislativa = SessaoLegislativa.objects.get(
@@ -521,13 +303,12 @@ class MesaDiretoraView(FormView):
id=int(request.POST['cargo']))
composicao.save()
- return redirect('sapl.parlamentares:mesa_diretora')
+ messages.success(request, _(
+ 'Parlamentar adicionado com sucesso!'))
- elif 'Excluir' in request.POST and check_permission_mesa(request):
-
- if (not Legislatura.objects.all() or
- not SessaoLegislativa.objects.all()):
- return self.validation(request)
+ elif 'Excluir' in request.POST and request.user.has_perm(
+ '%s.delete_%s' % (
+ AppConfig.label, ComposicaoMesa._meta.model_name)):
if 'composicao_mesa' in request.POST:
ids = request.POST['composicao_mesa'].split(':')
@@ -537,32 +318,42 @@ class MesaDiretoraView(FormView):
cargo_id=int(ids[1])
)
composicao.delete()
- return redirect('sapl.parlamentares:mesa_diretora')
- else:
- mesa = ComposicaoMesa.objects.filter(
- sessao_legislativa=request.POST['sessao'])
-
- cargos_ocupados = [m.cargo for m in mesa]
- cargos = CargoMesa.objects.all()
- cargos_vagos = list(set(cargos) - set(cargos_ocupados))
-
- parlamentares = Legislatura.objects.get(
- id=int(request.POST['legislatura'])).mandato_set.all()
- parlamentares_ocupados = [m.parlamentar for m in mesa]
- parlamentares_vagos = list(
- set(
- [p.parlamentar for p in parlamentares]) - set(
- parlamentares_ocupados))
- return self.render_to_response(
- {'legislaturas': Legislatura.objects.all(
- ).order_by('-numero'),
- 'legislatura_selecionada': Legislatura.objects.get(
- id=int(request.POST['legislatura'])),
- 'sessoes': SessaoLegislativa.objects.filter(
- legislatura_id=int(request.POST['legislatura'])),
- 'sessao_selecionada': SessaoLegislativa.objects.get(
- id=int(request.POST['sessao'])),
- 'composicao_mesa': mesa,
- 'parlamentares': parlamentares_vagos,
- 'cargos_vagos': cargos_vagos
- })
+ messages.success(request, _(
+ 'Parlamentar excluido com sucesso!'))
+ else:
+ messages.error(request, _(
+ 'Selecione um parlamentar para ser excluido!'))
+
+ mesa = ComposicaoMesa.objects.filter(
+ sessao_legislativa=request.POST['sessao'])
+
+ cargos_ocupados = [m.cargo for m in mesa]
+ cargos = CargoMesa.objects.all()
+ cargos_vagos = list(set(cargos) - set(cargos_ocupados))
+
+ parlamentares = Legislatura.objects.get(
+ id=int(request.POST['legislatura'])).mandato_set.all()
+ parlamentares_ocupados = [m.parlamentar for m in mesa]
+ parlamentares_vagos = list(
+ set(
+ [p.parlamentar for p in parlamentares]) - set(
+ parlamentares_ocupados))
+
+ sessao_selecionada = SessaoLegislativa.objects.get(
+ id=int(request.POST['sessao']))
+ if str(sessao_selecionada.legislatura_id) != int(
+ request.POST['legislatura']):
+ sessao_selecionada = SessaoLegislativa.objects.filter(
+ legislatura=Legislatura.objects.first()).first()
+ return self.render_to_response(
+ {'legislaturas': Legislatura.objects.all(
+ ).order_by('-numero'),
+ 'legislatura_selecionada': Legislatura.objects.get(
+ id=int(request.POST['legislatura'])),
+ 'sessoes': SessaoLegislativa.objects.filter(
+ legislatura_id=int(request.POST['legislatura'])),
+ 'sessao_selecionada': sessao_selecionada,
+ 'composicao_mesa': mesa,
+ 'parlamentares': parlamentares_vagos,
+ 'cargos_vagos': cargos_vagos
+ })
diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py
index 4ea8d86a7..48f354b17 100644
--- a/sapl/protocoloadm/views.py
+++ b/sapl/protocoloadm/views.py
@@ -14,12 +14,9 @@ from django.views.generic import CreateView, DetailView, FormView, ListView
from django.views.generic.base import TemplateView
from django_filters.views import FilterView
-import sapl.crud.base
+from sapl.base.apps import AppConfig as AppsAppConfig
from sapl.base.models import AppConfig
-from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView,
- CrudDeleteView, CrudDetailView, CrudListView,
- CrudUpdateView, make_pagination)
-from sapl.crud.masterdetail import MasterDetailCrud
+from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination
from sapl.materia.models import TipoMateriaLegislativa
from sapl.utils import (create_barcode, get_client_ip, permissoes_adm,
permissoes_protocoloadm)
@@ -35,79 +32,56 @@ from .models import (Autor, DocumentoAcessorioAdministrativo,
TipoDocumentoAdministrativo, TipoInstituicao,
TramitacaoAdministrativo)
-TipoDocumentoAdministrativoCrud = Crud.build(TipoDocumentoAdministrativo, '')
-DocumentoAcessorioAdministrativoCrud = Crud.build(
- DocumentoAcessorioAdministrativo, '')
+TipoDocumentoAdministrativoCrud = CrudAux.build(
+ TipoDocumentoAdministrativo, '')
+TipoInstituicaoCrud = CrudAux.build(TipoInstituicao, '')
+
+
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()
+DocumentoAcessorioAdministrativoCrud = Crud.build(
+ DocumentoAcessorioAdministrativo, '')
- class DeleteView(PermissionRequiredMixin, CrudDeleteView):
- permission_required = permissoes_adm()
- class ListView(PermissionRequiredMixin, CrudListView):
- permission_required = permissoes_adm()
+class DocumentoAdministrativoMixin:
- def has_permission(self):
- app_config = AppConfig.objects.last()
+ def has_permission(self):
+ app_config = AppConfig.objects.last()
+ if app_config and app_config.documentos_administrativos == 'O':
+ return True
- if app_config:
- if app_config.documentos_administrativos == 'O':
- return True
+ return self.request.user.has_module_perms(AppsAppConfig.label)
- perms = self.get_permission_required()
- return self.request.user.has_perms(perms)
- class DetailView(PermissionRequiredMixin, CrudDetailView):
- permission_required = permissoes_adm()
+class DocumentoAdministrativoCrud(Crud):
+ model = DocumentoAdministrativo
+ help_path = ''
- def has_permission(self):
- app_config = AppConfig.objects.last()
+ class BaseMixin(Crud.BaseMixin):
+ list_field_names = ['tipo', 'numero', 'ano', 'data',
+ 'numero_protocolo', 'assunto',
+ 'interessado', 'tramitacao', 'texto_integral']
- if app_config:
- if app_config.documentos_administrativos == 'O':
- return True
+ class ListView(Crud.ListView, DocumentoAdministrativoMixin):
+ pass
- perms = self.get_permission_required()
- return self.request.user.has_perms(perms)
+ class DetailView(Crud.DetailView, DocumentoAdministrativoMixin):
+ pass
-class StatusTramitacaoAdministrativoCrud(Crud):
+class StatusTramitacaoAdministrativoCrud(CrudAux):
model = StatusTramitacaoAdministrativo
help_path = ''
- class BaseMixin(CrudBaseMixin):
+ class BaseMixin(CrudAux.BaseMixin):
list_field_names = ['sigla', 'indicador', 'descricao']
- class ListView(CrudListView):
+ class ListView(CrudAux.ListView):
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(PermissionRequiredMixin, FilterView):
model = Protocolo
@@ -394,22 +368,13 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
class PesquisarDocumentoAdministrativoView(PermissionRequiredMixin,
- FilterView):
+ FilterView,
+ DocumentoAdministrativoMixin):
model = DocumentoAdministrativo
filterset_class = DocumentoAdministrativoFilterSet
paginate_by = 10
permission_required = permissoes_adm()
- def has_permission(self):
- app_config = AppConfig.objects.last()
-
- if app_config:
- if app_config.documentos_administrativos == 'O':
- return True
-
- perms = self.get_permission_required()
- return self.request.user.has_perms(perms)
-
def get_filterset_kwargs(self, filterset_class):
super(PesquisarDocumentoAdministrativoView,
self).get_filterset_kwargs(filterset_class)
@@ -603,47 +568,22 @@ class TramitacaoAdmCrud(MasterDetailCrud):
list_field_names = ['data_tramitacao', 'unidade_tramitacao_local',
'unidade_tramitacao_destino', 'status']
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
+ class CreateView(MasterDetailCrud.CreateView):
form_class = TramitacaoAdmForm
- permission_required = permissoes_adm()
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
+ class UpdateView(MasterDetailCrud.UpdateView):
form_class = TramitacaoAdmEditForm
- permission_required = permissoes_adm()
-
- class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
- permission_required = permissoes_adm()
- class ListView(PermissionRequiredMixin, MasterDetailCrud.ListView):
- permission_required = permissoes_adm()
+ class ListView(MasterDetailCrud.ListView, DocumentoAdministrativoMixin):
def get_queryset(self):
qs = super(MasterDetailCrud.ListView, self).get_queryset()
kwargs = {self.crud.parent_field: self.kwargs['pk']}
return qs.filter(**kwargs).order_by('-data_tramitacao', '-id')
- def has_permission(self):
- app_config = AppConfig.objects.last()
-
- if app_config:
- if app_config.documentos_administrativos == 'O':
- return True
-
- perms = self.get_permission_required()
- return self.request.user.has_perms(perms)
-
- class DetailView(PermissionRequiredMixin, MasterDetailCrud.DetailView):
- permission_required = permissoes_adm()
-
- def has_permission(self):
- app_config = AppConfig.objects.last()
-
- if app_config:
- if app_config.documentos_administrativos == 'O':
- return True
-
- perms = self.get_permission_required()
- return self.request.user.has_perms(perms)
+ class DetailView(MasterDetailCrud.DetailView,
+ DocumentoAdministrativoMixin):
+ pass
def get_nome_autor(request):
diff --git a/sapl/sessao/migrations/0027_auto_20161003_0417.py b/sapl/sessao/migrations/0027_auto_20161003_0417.py
new file mode 100644
index 000000000..324cd919c
--- /dev/null
+++ b/sapl/sessao/migrations/0027_auto_20161003_0417.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.7 on 2016-10-03 07:17
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('sessao', '0026_auto_20160926_1445'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='bancada',
+ options={'ordering': ('-legislatura__numero',), 'verbose_name': 'Bancada', 'verbose_name_plural': 'Bancadas'},
+ ),
+ ]
diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py
index 78ff6a410..86ce4c2e2 100644
--- a/sapl/sessao/models.py
+++ b/sapl/sessao/models.py
@@ -41,6 +41,7 @@ class Bancada(models.Model):
class Meta:
verbose_name = _('Bancada')
verbose_name_plural = _('Bancadas')
+ ordering = ('-legislatura__numero', )
def __str__(self):
return self.nome
diff --git a/sapl/sessao/urls.py b/sapl/sessao/urls.py
index e23bb4113..efbfbaf9a 100644
--- a/sapl/sessao/urls.py
+++ b/sapl/sessao/urls.py
@@ -39,6 +39,7 @@ urlpatterns = [
ExpedienteMateriaCrud.get_urls() +
MateriaOrdemDiaCrud.get_urls())),
+ url(r'^sessao/(?P\d+)/mesa$', MesaView.as_view(), name='mesa'),
url(r'^recuperar-materia/', recuperar_materia),
url(r'^recuperar-numero-sessao/', recuperar_numero_sessao),
@@ -86,17 +87,16 @@ urlpatterns = [
PautaOrdemDetail.as_view(), name='pauta_ordem_detail'),
# Subnav sessão
- url(r'^(?P\d+)/expediente$',
+ url(r'^sessao/(?P\d+)/expediente$',
ExpedienteView.as_view(), name='expediente'),
- url(r'^(?P\d+)/presenca$',
+ url(r'^sessao/(?P\d+)/presenca$',
PresencaView.as_view(), name='presenca'),
- url(r'^(?P\d+)/painel$',
+ url(r'^sessao/(?P\d+)/painel$',
PainelView.as_view(), name='painel'),
- url(r'^(?P\d+)/presencaordemdia$',
+ url(r'^sessao/(?P\d+)/presencaordemdia$',
PresencaOrdemDiaView.as_view(),
name='presencaordemdia'),
- url(r'^(?P\d+)/mesa$', MesaView.as_view(), name='mesa'),
- url(r'^(?P\d+)/resumo$',
+ url(r'^sessao/(?P\d+)/resumo$',
ResumoView.as_view(), name='resumo'),
url(r'^sessao/pesquisar-sessao$',
PesquisarSessaoPlenariaView.as_view(), name='pesquisar_sessao'),
diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py
index 8a500b2cb..daff34b99 100644
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -1,41 +1,41 @@
from datetime import datetime
from re import sub
+from braces.views import PermissionRequiredMixin
from django.contrib import messages
-from django.contrib.auth.mixins import PermissionRequiredMixin
+from django.contrib.auth.decorators import permission_required
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.urlresolvers import reverse
from django.forms.utils import ErrorList
from django.http import JsonResponse
from django.http.response import HttpResponseRedirect
from django.utils.datastructures import MultiValueDictKeyError
+from django.utils.decorators import method_decorator
from django.utils.html import strip_tags
from django.utils.translation import ugettext_lazy as _
from django.views.generic import ListView, TemplateView
+from django.views.generic.detail import DetailView
from django.views.generic.edit import FormMixin
from django_filters.views import FilterView
from rest_framework import generics
-from sapl.crud.base import (Crud, CrudBaseMixin, CrudCreateView,
- CrudDeleteView, CrudDetailView, CrudListView,
- CrudUpdateView, make_pagination)
-from sapl.crud.masterdetail import MasterDetailCrud
+from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
+ MasterDetailCrud, make_pagination)
from sapl.materia.forms import pega_ultima_tramitacao
from sapl.materia.models import (Autoria, DocumentoAcessorio,
TipoMateriaLegislativa, Tramitacao)
from sapl.materia.views import MateriaLegislativaPesquisaView
from sapl.norma.models import NormaJuridica
-from sapl.parlamentares.models import (Parlamentar, SessaoLegislativa,
- Legislatura)
+from sapl.parlamentares.models import (Legislatura, Parlamentar,
+ SessaoLegislativa)
+from sapl.sessao.apps import AppConfig
from sapl.sessao.serializers import SessaoPlenariaSerializer
-from sapl.utils import permissao_tb_aux, permissoes_painel, permissoes_sessao
-
-from .forms import (AdicionarVariasMateriasFilterSet, BancadaForm,
- ExpedienteForm, ExpedienteMateriaForm, ListMateriaForm,
- MesaForm, OradorExpedienteForm, OradorForm, OrdemDiaForm,
- PautaSessaoFilterSet, PresencaForm,
- SessaoPlenariaFilterSet, VotacaoEditForm, VotacaoForm,
- VotacaoNominalForm)
+from sapl.utils import permissoes_painel, permissoes_sessao
+
+from .forms import (AdicionarVariasMateriasFilterSet, ExpedienteForm,
+ ListMateriaForm, MesaForm, PautaSessaoFilterSet,
+ PresencaForm, SessaoPlenariaFilterSet, VotacaoEditForm,
+ VotacaoForm, VotacaoNominalForm)
from .models import (Bancada, Bloco, CargoBancada, CargoMesa,
ExpedienteMateria, ExpedienteSessao, IntegranteMesa,
MateriaLegislativa, Orador, OradorExpediente, OrdemDia,
@@ -46,6 +46,19 @@ from .models import (Bancada, Bloco, CargoBancada, CargoMesa,
OrdemDiaCrud = Crud.build(OrdemDia, '')
RegistroVotacaoCrud = Crud.build(RegistroVotacao, '')
+TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria')
+TipoExpedienteCrud = CrudAux.build(TipoExpediente, 'tipo_expediente')
+CargoBancadaCrud = CrudAux.build(CargoBancada, '')
+TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria')
+TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria')
+
+BlocoCrud = CrudAux.build(
+ Bloco, '', list_field_names=['nome', 'data_criacao', 'partidos'])
+BancadaCrud = CrudAux.build(
+ Bancada, '', list_field_names=['nome', 'legislatura'])
+TipoResultadoVotacaoCrud = CrudAux.build(
+ TipoResultadoVotacao, 'tipo_resultado_votacao')
+
def reordernar_materias_expediente(request, pk):
expedientes = ExpedienteMateria.objects.filter(
@@ -73,73 +86,6 @@ def reordernar_materias_ordem(request, pk):
reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk}))
-class BlocoCrud(Crud):
- model = Bloco
- help_path = ''
-
- class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
- list_field_names = ['nome', 'data_criacao', 'partidos']
-
- def has_permission(self):
- return permissao_tb_aux(self)
-
-
-class BancadaCrud(Crud):
- model = Bancada
- help_path = ''
-
- class BaseMixin(PermissionRequiredMixin, CrudBaseMixin):
- list_field_names = ['nome', 'legislatura']
-
- def has_permission(self):
- return permissao_tb_aux(self)
-
- class ListView(CrudListView):
- ordering = 'legislatura'
-
- class CreateView(CrudCreateView):
- form_class = BancadaForm
-
- class UpdateView(CrudUpdateView):
- 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
@@ -182,14 +128,12 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
'resultado']
class CreateView(MasterDetailCrud.CreateView):
- form_class = OrdemDiaForm
def get_success_url(self):
return reverse('sapl.sessao:ordemdia_list',
kwargs={'pk': self.kwargs['pk']})
class UpdateView(MasterDetailCrud.UpdateView):
- form_class = OrdemDiaForm
def get_initial(self):
self.initial['tipo_materia'] = self.object.materia.tipo.id
@@ -198,6 +142,7 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
return self.initial
class DetailView(MasterDetailCrud.DetailView):
+
@property
def layout_key(self):
return 'OrdemDiaDetail'
@@ -241,7 +186,7 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
url = reverse('sapl.sessao:abrir_votacao', kwargs={
'pk': obj.pk, 'spk': obj.sessao_plenaria_id})
- if self.request.user.has_perms(permissoes_sessao()):
+ if self.request.user.has_module_perms(AppConfig.label):
btn_abrir = '''
Matéria não votada
Abrir Votação''' % (url)
+
obj.resultado = btn_abrir
else:
url = ''
@@ -370,17 +316,13 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
obj.resultado)
return [self._as_row(obj) for obj in object_list]
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- form_class = ExpedienteMateriaForm
- permission_required = permissoes_sessao()
+ class CreateView(MasterDetailCrud.CreateView):
def get_success_url(self):
return reverse('sapl.sessao:expedientemateria_list',
kwargs={'pk': self.kwargs['pk']})
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
- form_class = ExpedienteMateriaForm
- permission_required = permissoes_sessao()
+ class UpdateView(MasterDetailCrud.UpdateView):
def get_initial(self):
self.initial['tipo_materia'] = self.object.materia.tipo.id
@@ -388,9 +330,6 @@ 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
@@ -402,57 +341,31 @@ class OradorCrud(MasterDetailCrud):
model = ''
parent_field = 'sessao_plenaria'
help_path = ''
+ public = [RP_LIST, RP_DETAIL]
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()
- form_class = OradorExpedienteForm
+ class CreateView(MasterDetailCrud.CreateView):
def get_success_url(self):
return reverse('sapl.sessao:oradorexpediente_list',
kwargs={'pk': self.kwargs['pk']})
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
- permission_required = permissoes_sessao()
- form_class = OradorExpedienteForm
-
- class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
- permission_required = permissoes_sessao()
-
class OradorCrud(OradorCrud):
model = Orador
- class CreateView(PermissionRequiredMixin, MasterDetailCrud.CreateView):
- permission_required = permissoes_sessao()
- form_class = OradorForm
+ class CreateView(MasterDetailCrud.CreateView):
def get_success_url(self):
return reverse('sapl.sessao:orador_list',
kwargs={'pk': self.kwargs['pk']})
- class UpdateView(PermissionRequiredMixin, MasterDetailCrud.UpdateView):
- permission_required = permissoes_sessao()
- form_class = OradorForm
-
- class DeleteView(PermissionRequiredMixin, MasterDetailCrud.DeleteView):
- permission_required = permissoes_sessao()
-
def recuperar_numero_sessao(request):
try:
@@ -469,22 +382,19 @@ def recuperar_numero_sessao(request):
class SessaoCrud(Crud):
model = SessaoPlenaria
help_path = 'sessao_plenaria'
+ public = [RP_DETAIL]
- class BaseMixin(CrudBaseMixin):
+ class BaseMixin(Crud.BaseMixin):
list_field_names = ['data_inicio', 'legislatura', 'sessao_legislativa',
'tipo']
- # FIXME!!!! corrigir referencias no codigo e remover isso!!!!!
- # fazer com #230
- class CrudDetailView(CrudDetailView):
+ class CrudDetailView(DetailView):
model = SessaoPlenaria
- help_path = 'sessao_plenaria'
- class ListView(CrudListView):
+ class ListView(Crud.ListView):
ordering = ['-data_inicio']
- class CreateView(PermissionRequiredMixin, CrudCreateView):
- permission_required = permissoes_sessao()
+ class CreateView(Crud.CreateView):
def get_initial(self):
legislatura = Legislatura.objects.order_by('-numero')[0]
@@ -493,12 +403,6 @@ class SessaoCrud(Crud):
return {'legislatura': legislatura,
'sessao_legislativa': sessao_legislativa}
- class UpdateView(PermissionRequiredMixin, CrudUpdateView):
- permission_required = permissoes_sessao()
-
- class DeleteView(PermissionRequiredMixin, CrudDeleteView):
- permission_required = permissoes_sessao()
-
class PresencaMixin:
@@ -531,18 +435,24 @@ class PresencaMixin:
yield (parlamentar, False)
-class PresencaView(FormMixin,
- PresencaMixin,
- SessaoCrud.CrudDetailView):
+class PresencaView(FormMixin, PresencaMixin, DetailView):
template_name = 'sessao/presenca.html'
form_class = PresencaForm
model = SessaoPlenaria
+ @method_decorator(permission_required((
+ '%s.add_%s' % (
+ AppConfig.label, SessaoPlenariaPresenca._meta.model_name),
+ '%s.change_%s' % (
+ AppConfig.label, SessaoPlenariaPresenca._meta.model_name),
+ '%s.delete_%s' % (
+ AppConfig.label, SessaoPlenariaPresenca._meta.model_name),
+ )))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
- if not self.request.user.has_perms(permissoes_sessao()):
+ if not self.request.user.has_module_perms(AppConfig.label):
return self.form_invalid(form)
if form.is_valid():
@@ -582,12 +492,16 @@ class PainelView(PermissionRequiredMixin, TemplateView):
permission_required = permissoes_painel()
-class PresencaOrdemDiaView(FormMixin,
- PresencaMixin,
- SessaoCrud.CrudDetailView):
+class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView):
template_name = 'sessao/presenca_ordemdia.html'
form_class = PresencaForm
+ model = SessaoPlenaria
+ @method_decorator(permission_required((
+ '%s.add_%s' % (AppConfig.label, PresencaOrdemDia._meta.model_name),
+ '%s.change_%s' % (AppConfig.label, PresencaOrdemDia._meta.model_name),
+ '%s.delete_%s' % (AppConfig.label, PresencaOrdemDia._meta.model_name),
+ )))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
@@ -630,9 +544,10 @@ class PresencaOrdemDiaView(FormMixin,
return reverse('sapl.sessao:presencaordemdia', kwargs={'pk': pk})
-class ListMateriaOrdemDiaView(FormMixin, SessaoCrud.CrudDetailView):
+class ListMateriaOrdemDiaView(FormMixin, DetailView):
template_name = 'sessao/materia_ordemdia_list.html'
form_class = ListMateriaForm
+ model = SessaoPlenaria
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@@ -669,6 +584,11 @@ class ListMateriaOrdemDiaView(FormMixin, SessaoCrud.CrudDetailView):
return self.render_to_response(context)
+ @method_decorator(permission_required((
+ '%s.add_%s' % (AppConfig.label, OrdemDia._meta.model_name),
+ '%s.change_%s' % (AppConfig.label, OrdemDia._meta.model_name),
+ '%s.delete_%s' % (AppConfig.label, OrdemDia._meta.model_name),
+ )))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
@@ -733,12 +653,13 @@ class ListMateriaOrdemDiaView(FormMixin, SessaoCrud.CrudDetailView):
return self.get(self, request, args, kwargs)
-class MesaView(PermissionRequiredMixin, FormMixin, SessaoCrud.CrudDetailView):
+class MesaView(FormMixin, DetailView):
template_name = 'sessao/mesa.html'
form_class = MesaForm
- permission_required = permissoes_sessao()
+ model = SessaoPlenaria
def get(self, request, *args, **kwargs):
+
self.object = self.get_object()
context = self.get_context_data(object=self.object)
@@ -758,6 +679,11 @@ class MesaView(PermissionRequiredMixin, FormMixin, SessaoCrud.CrudDetailView):
return self.render_to_response(context)
+ @method_decorator(permission_required((
+ '%s.add_integrantemesa' % AppConfig.label,
+ '%s.change_integrantemesa' % AppConfig.label,
+ '%s.delete_integrantemesa' % AppConfig.label,
+ )))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = MesaForm(request.POST)
@@ -2118,11 +2044,11 @@ class PesquisarPautaSessaoView(PesquisarSessaoPlenariaView):
def filtra_tramitacao_ordem_dia():
- lista = pega_ultima_tramitacao()
- return Tramitacao.objects.filter(
- id__in=lista,
- status__descricao='Ordem do Dia').distinct().values_list(
- 'materia_id', flat=True)
+ lista = pega_ultima_tramitacao()
+ return Tramitacao.objects.filter(
+ id__in=lista,
+ status__descricao='Ordem do Dia').distinct().values_list(
+ 'materia_id', flat=True)
def retira_materias_ja_adicionadas(id_sessao, model):
diff --git a/sapl/static/styles/app.scss b/sapl/static/styles/app.scss
index 114d4052d..beb9f8bf5 100644
--- a/sapl/static/styles/app.scss
+++ b/sapl/static/styles/app.scss
@@ -70,6 +70,13 @@ h6, .h6 {
color: inherit;
}
+.caret {
+ /* Por padrão caret aponta para baixo*/
+ &.top {
+ transform: rotate(180deg);
+ }
+}
+
// #### CRUD DETAIL ########################################
p.control-label {
font-weight: bold;
@@ -147,6 +154,11 @@ fieldset {
}
}
+.avatar-parlamentar {
+ height: 42px;
+ width: 42px;
+}
+
/* INDEX */
#conteudo {
position: relative;
diff --git a/sapl/templates/base.html b/sapl/templates/base.html
index 24c3af670..1367ab816 100644
--- a/sapl/templates/base.html
+++ b/sapl/templates/base.html
@@ -103,11 +103,11 @@
- {% if user|ver_menu_sistema_perm %}
-
+ {% if perms.base.menu_sistemas %}
+
Sistema