Browse Source

Merge pull request #788 from interlegis/774-container-usuario-em-compilacao

774 container usuario em compilacao
pull/789/head
Leandro Roberto da Silva 8 years ago
committed by GitHub
parent
commit
adda444f18
  1. 46
      sapl/compilacao/migrations/0064_auto_20161104_1420.py
  2. 20
      sapl/compilacao/migrations/0065_auto_20161107_1024.py
  3. 20
      sapl/compilacao/migrations/0066_auto_20161107_1028.py
  4. 19
      sapl/compilacao/migrations/0067_auto_20161107_1351.py
  5. 19
      sapl/compilacao/migrations/0068_auto_20161107_1546.py
  6. 20
      sapl/compilacao/migrations/0069_auto_20161107_1932.py
  7. 147
      sapl/compilacao/models.py
  8. 4
      sapl/compilacao/templatetags/compilacao_filters.py
  9. 98
      sapl/compilacao/views.py
  10. 5
      sapl/crispy_layout_mixin.py
  11. 7
      sapl/crud/base.py
  12. 35
      sapl/materia/forms.py
  13. 86
      sapl/materia/views.py
  14. 35
      sapl/parlamentares/views.py
  15. 15
      sapl/rules/map_rules.py
  16. 2
      sapl/templates/compilacao/publicacao_detail.html
  17. 6
      sapl/templates/compilacao/text_edit.html
  18. 8
      sapl/templates/compilacao/text_list.html
  19. 27
      sapl/templates/compilacao/textoarticulado_detail.html
  20. 29
      sapl/templates/compilacao/tipotextoarticulado_detail.html
  21. 9
      sapl/templates/crud/detail.html
  22. 11
      sapl/templates/crud/detail_detail.html
  23. 1
      sapl/templates/materia/proposicao_detail.html

46
sapl/compilacao/migrations/0064_auto_20161104_1420.py

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-11-04 14:20
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('compilacao', '0063_tipotextoarticulado_publicacao_func'),
]
operations = [
migrations.AlterModelOptions(
name='textoarticulado',
options={'ordering': ['-data', '-numero'], 'permissions': (('view_restricted_textoarticulado', 'Pode ver qualquer Texto Articulado'),), 'verbose_name': 'Texto Articulado', 'verbose_name_plural': 'Textos Articulados'},
),
migrations.AddField(
model_name='textoarticulado',
name='editable_only_by_owners',
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=True, verbose_name='Editável apenas pelos donos do Texto Articulado'),
),
migrations.AddField(
model_name='textoarticulado',
name='editing_locked',
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=True, verbose_name='Texto Articulado em Edição'),
),
migrations.AddField(
model_name='textoarticulado',
name='owners',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Donos do Texto Articulado'),
),
migrations.AddField(
model_name='textoarticulado',
name='visibilidade',
field=models.IntegerField(choices=[(99, 'Privado'), (79, 'Restrito'), (89, 'Em Edição'), (0, 'Público')], default=99, verbose_name='Visibilidade'),
),
migrations.AlterField(
model_name='tipotextoarticulado',
name='publicacao_func',
field=models.NullBooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Histórico de Publicação'),
),
]

20
sapl/compilacao/migrations/0065_auto_20161107_1024.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-11-07 10:24
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0064_auto_20161104_1420'),
]
operations = [
migrations.RenameField(
model_name='textoarticulado',
old_name='visibilidade',
new_name='privacidade'
),
]

20
sapl/compilacao/migrations/0066_auto_20161107_1028.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-11-07 10:28
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0065_auto_20161107_1024'),
]
operations = [
migrations.AlterField(
model_name='textoarticulado',
name='privacidade',
field=models.IntegerField(choices=[(99, 'Privado'), (79, 'Restrito'), (89, 'Em Edição'), (0, 'Público')], default=99, verbose_name='Privacidade'),
),
]

19
sapl/compilacao/migrations/0067_auto_20161107_1351.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-11-07 13:51
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0066_auto_20161107_1028'),
]
operations = [
migrations.AlterModelOptions(
name='textoarticulado',
options={'ordering': ['-data', '-numero'], 'permissions': (('view_restricted_textoarticulado', 'Pode ver qualquer Texto Articulado'), ('lock_unlock_textoarticulado', 'Pode bloquear/desbloquear edição de Texto Articulado')), 'verbose_name': 'Texto Articulado', 'verbose_name_plural': 'Textos Articulados'},
),
]

19
sapl/compilacao/migrations/0068_auto_20161107_1546.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-11-07 15:46
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0067_auto_20161107_1351'),
]
operations = [
migrations.AlterModelOptions(
name='dispositivo',
options={'ordering': ['ta', 'ordem'], 'permissions': (('change_dispositivo_edicao_dinamica', 'Permissão de edição de dispositivos originais via editor dinâmico.'), ('change_your_dispositivo_edicao_dinamica', 'Permissão de edição de dispositivos originais via editor dinâmico desde que seja dono.'), ('change_dispositivo_edicao_avancada', 'Permissão de edição de dispositivos originais via formulários de edição avançada.'), ('change_dispositivo_registros_compilacao', 'Permissão de registro de compilação via editor dinâmico.'), ('view_dispositivo_notificacoes', 'Permissão de acesso às notificações de pendências.'), ('change_dispositivo_de_vigencia_global', 'Permissão alteração global do dispositivo de vigência')), 'verbose_name': 'Dispositivo', 'verbose_name_plural': 'Dispositivos'},
),
]

20
sapl/compilacao/migrations/0069_auto_20161107_1932.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-11-07 19:32
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0068_auto_20161107_1546'),
]
operations = [
migrations.AlterField(
model_name='textoarticulado',
name='privacidade',
field=models.IntegerField(choices=[(99, 'Privado'), (79, 'Imotável Restrito'), (69, 'Imutável Público'), (89, 'Em Edição'), (0, 'Público')], default=99, verbose_name='Privacidade'),
),
]

147
sapl/compilacao/models.py

@ -1,8 +1,10 @@
from django.contrib import messages
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.db.models import F, Q from django.db.models import F, Q
from django.db.models.aggregates import Max from django.db.models.aggregates import Max
from django.http.response import Http404
from django.template import defaultfilters from django.template import defaultfilters
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -82,7 +84,7 @@ class TipoTextoArticulado(models.Model):
verbose_name=_('Participação Social')) verbose_name=_('Participação Social'))
publicacao_func = models.NullBooleanField( publicacao_func = models.NullBooleanField(
default=True, default=False,
blank=True, null=True, blank=True, null=True,
choices=YES_NO_CHOICES, choices=YES_NO_CHOICES,
verbose_name=_('Histórico de Publicação')) verbose_name=_('Histórico de Publicação'))
@ -101,6 +103,25 @@ PARTICIPACAO_SOCIAL_CHOICES = [
(False, _('Não'))] (False, _('Não'))]
STATUS_TA_PRIVATE = 99 # Só os donos podem ver
STATUS_TA_EDITION = 89
STATUS_TA_IMMUTABLE_RESTRICT = 79
STATUS_TA_IMMUTABLE_PUBLIC = 69
STATUS_TA_PUBLIC = 0
PRIVACIDADE_STATUS = (
(STATUS_TA_PRIVATE, _('Privado')), # só dono ve e edita
# só quem tem permissão para ver
(STATUS_TA_IMMUTABLE_RESTRICT, _('Imotável Restrito')),
# só quem tem permissão para ver
(STATUS_TA_IMMUTABLE_PUBLIC, _('Imutável Público')),
(STATUS_TA_EDITION, _('Em Edição')), # só quem tem permissão para editar
(STATUS_TA_PUBLIC, _('Público')), # visualização pública
)
class TextoArticulado(TimestampedMixin): class TextoArticulado(TimestampedMixin):
data = models.DateField(blank=True, null=True, verbose_name=_('Data')) data = models.DateField(blank=True, null=True, verbose_name=_('Data'))
ementa = models.TextField(verbose_name=_('Ementa')) ementa = models.TextField(verbose_name=_('Ementa'))
@ -124,10 +145,35 @@ class TextoArticulado(TimestampedMixin):
blank=True, null=True, default=None) blank=True, null=True, default=None)
content_object = GenericForeignKey('content_type', 'object_id') content_object = GenericForeignKey('content_type', 'object_id')
owners = models.ManyToManyField(
get_settings_auth_user_model(),
blank=True, verbose_name=_('Donos do Texto Articulado'))
editable_only_by_owners = models.BooleanField(
choices=YES_NO_CHOICES,
default=True,
verbose_name=_('Editável apenas pelos donos do Texto Articulado'))
editing_locked = models.BooleanField(
choices=YES_NO_CHOICES,
default=True,
verbose_name=_('Texto Articulado em Edição'))
privacidade = models.IntegerField(
_('Privacidade'),
choices=PRIVACIDADE_STATUS,
default=STATUS_TA_PRIVATE)
class Meta: class Meta:
verbose_name = _('Texto Articulado') verbose_name = _('Texto Articulado')
verbose_name_plural = _('Textos Articulados') verbose_name_plural = _('Textos Articulados')
ordering = ['-data', '-numero'] ordering = ['-data', '-numero']
permissions = (
('view_restricted_textoarticulado',
_('Pode ver qualquer Texto Articulado')),
('lock_unlock_textoarticulado',
_('Pode bloquear/desbloquear edição de Texto Articulado')),
)
def __str__(self): def __str__(self):
if self.content_object: if self.content_object:
@ -138,6 +184,102 @@ class TextoArticulado(TimestampedMixin):
'numero': self.numero, 'numero': self.numero,
'data': defaultfilters.date(self.data, "d \d\e F \d\e Y")} 'data': defaultfilters.date(self.data, "d \d\e F \d\e Y")}
def hash(self):
from django.core import serializers
import hashlib
data = serializers.serialize(
"xml", Dispositivo.objects.filter(
Q(ta_id=self.id) | Q(ta_publicado_id=self.id)))
md5 = hashlib.md5()
md5.update(data.encode('utf-8'))
return md5.hexdigest()
def can_use_dynamic_editing(self, user):
return not self.editing_locked and\
(not self.editable_only_by_owners and
user.has_perm(
'compilacao.change_dispositivo_edicao_dinamica') or
self.editable_only_by_owners and user in self.owners.all() and
user.has_perm(
'compilacao.change_your_dispositivo_edicao_dinamica'))
def has_view_permission(self, request):
if self.privacidade in (STATUS_TA_IMMUTABLE_PUBLIC, STATUS_TA_PUBLIC):
return True
if request.user in self.owners.all():
return True
if self.privacidade == STATUS_TA_IMMUTABLE_RESTRICT and\
request.user.has_perm(
'compilacao.view_restricted_textoarticulado'):
return True
elif self.privacidade == STATUS_TA_EDITION:
if request.user.has_perm(
'compilacao.change_dispositivo_edicao_dinamica'):
return True
else:
messages.error(request, _(
'Este Texto Articulado está em edição.'))
elif self.privacidade == STATUS_TA_PRIVATE:
if request.user in self.owners.all():
return True
else:
raise Http404()
return False
def has_edit_permission(self, request):
if self.privacidade == STATUS_TA_PRIVATE:
if request.user not in self.owners.all():
raise Http404()
if not self.can_use_dynamic_editing(request.user):
messages.error(request, _(
'Usuário sem permissão para edição.'))
return False
else:
return True
if self.privacidade == STATUS_TA_IMMUTABLE_RESTRICT:
messages.error(request, _(
'A edição deste Texto Articulado está bloqueada. '
'Este documento é imutável e de acesso é restrito.'))
return False
if self.privacidade == STATUS_TA_IMMUTABLE_PUBLIC:
messages.error(request, _(
'A edição deste Texto Articulado está bloqueada. '
'Este documento é imutável.'))
return False
if self.editing_locked and\
self.privacidade in (STATUS_TA_PUBLIC, STATUS_TA_EDITION) and\
not request.user.has_perm(
'compilacao.lock_unlock_textoarticulado'):
messages.error(request, _(
'A edição deste Texto Articulado está bloqueada. '
'É necessário acessar com usuário que possui '
'permissão de desbloqueio.'))
return False
if not request.user.has_perm(
'compilacao.change_dispositivo_edicao_dinamica'):
messages.error(request, _(
'Usuário sem permissão para edição.'))
return False
if self.editable_only_by_owners and\
request.user not in self.owners.all():
messages.error(request, _(
'Apenas usuários donos do Texto Articulado podem editá-lo.'))
return False
return True
def reagrupar_ordem_de_dispositivos(self): def reagrupar_ordem_de_dispositivos(self):
dpts = Dispositivo.objects.filter(ta=self) dpts = Dispositivo.objects.filter(ta=self)
@ -703,6 +845,9 @@ class Dispositivo(BaseModel, TimestampedMixin):
('change_dispositivo_edicao_dinamica', _( ('change_dispositivo_edicao_dinamica', _(
'Permissão de edição de dispositivos originais ' 'Permissão de edição de dispositivos originais '
'via editor dinâmico.')), 'via editor dinâmico.')),
('change_your_dispositivo_edicao_dinamica', _(
'Permissão de edição de dispositivos originais '
'via editor dinâmico desde que seja dono.')),
('change_dispositivo_edicao_avancada', _( ('change_dispositivo_edicao_avancada', _(
'Permissão de edição de dispositivos originais ' 'Permissão de edição de dispositivos originais '
'via formulários de edição avançada.')), 'via formulários de edição avançada.')),

4
sapl/compilacao/templatetags/compilacao_filters.py

@ -295,3 +295,7 @@ def urldetail_content_type(obj):
@register.filter @register.filter
def list(obj): def list(obj):
return [obj, ] return [obj, ]
@register.filter
def can_use_dynamic_editing(texto_articulado, user):
return texto_articulado.can_use_dynamic_editing(user)

98
sapl/compilacao/views.py

@ -7,7 +7,6 @@ from braces.views import FormMessagesMixin
from django import forms from django import forms
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.signing import Signer from django.core.signing import Signer
@ -19,7 +18,6 @@ from django.http.response import (HttpResponse, HttpResponseRedirect,
JsonResponse) JsonResponse)
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.utils.dateparse import parse_date from django.utils.dateparse import parse_date
from django.utils.decorators import method_decorator
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.translation import string_concat from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -44,7 +42,8 @@ from sapl.compilacao.models import (Dispositivo, Nota,
Publicacao, TextoArticulado, Publicacao, TextoArticulado,
TipoDispositivo, TipoNota, TipoPublicacao, TipoDispositivo, TipoNota, TipoPublicacao,
TipoTextoArticulado, TipoVide, TipoTextoArticulado, TipoVide,
VeiculoPublicacao, Vide) VeiculoPublicacao, Vide, STATUS_TA_EDITION,
STATUS_TA_PRIVATE, STATUS_TA_PUBLIC)
from sapl.compilacao.utils import (DISPOSITIVO_SELECT_RELATED, from sapl.compilacao.utils import (DISPOSITIVO_SELECT_RELATED,
DISPOSITIVO_SELECT_RELATED_EDIT) DISPOSITIVO_SELECT_RELATED_EDIT)
from sapl.crud.base import Crud, CrudListView, make_pagination from sapl.crud.base import Crud, CrudListView, make_pagination
@ -157,6 +156,7 @@ class IntegracaoTaView(TemplateView):
""") """)
map_fields = self.map_fields map_fields = self.map_fields
ta_values = getattr(self, 'ta_values', {})
item = get_object_or_404(self.model, pk=kwargs['pk']) item = get_object_or_404(self.model, pk=kwargs['pk'])
related_object_type = ContentType.objects.get_for_model(item) related_object_type = ContentType.objects.get_for_model(item)
@ -168,18 +168,30 @@ class IntegracaoTaView(TemplateView):
tipo_ta = TipoTextoArticulado.objects.filter( tipo_ta = TipoTextoArticulado.objects.filter(
content_type=related_object_type) content_type=related_object_type)
if not ta.exists(): ta_exists = bool(ta.exists())
if not ta_exists:
ta = TextoArticulado() ta = TextoArticulado()
tipo_ta = TipoTextoArticulado.objects.filter( tipo_ta = TipoTextoArticulado.objects.filter(
content_type=related_object_type)[:1] content_type=related_object_type)[:1]
if tipo_ta.exists(): if tipo_ta.exists():
ta.tipo_ta = tipo_ta[0] ta.tipo_ta = tipo_ta[0]
ta.content_object = item ta.content_object = item
ta.privacidade = ta_values.get('privacidade', STATUS_TA_EDITION)
ta.editing_locked = ta_values.get('editing_locked', False)
ta.editable_only_by_owners = ta_values.get(
'editable_only_by_owners', False)
else: else:
ta = ta[0] ta = ta[0]
ta.data = getattr(item, map_fields['data'] if not ta.data:
if map_fields['data'] else 'xxx', datetime.now()) ta.data = getattr(item, map_fields['data']
if map_fields['data'] else 'xxx',
datetime.now())
if not ta.data:
ta.data = datetime.now()
ta.ementa = getattr( ta.ementa = getattr(
item, map_fields['ementa'] item, map_fields['ementa']
@ -202,11 +214,17 @@ class IntegracaoTaView(TemplateView):
ta.save() ta.save()
if Dispositivo.objects.filter(ta_id=ta.pk).exists(): if not ta_exists:
return redirect(to=reverse_lazy('sapl.compilacao:ta_text', if ta.editable_only_by_owners and\
not self.request.user.is_anonymous():
ta.owners.add(self.request.user)
if not Dispositivo.objects.filter(ta_id=ta.pk).exists() and\
ta.can_use_dynamic_editing(self.request.user):
return redirect(to=reverse_lazy('sapl.compilacao:ta_text_edit',
kwargs={'ta_id': ta.pk})) kwargs={'ta_id': ta.pk}))
else: else:
return redirect(to=reverse_lazy('sapl.compilacao:ta_text_edit', return redirect(to=reverse_lazy('sapl.compilacao:ta_text',
kwargs={'ta_id': ta.pk})) kwargs={'ta_id': ta.pk}))
def import_pattern(self): def import_pattern(self):
@ -284,7 +302,8 @@ class CompMixin(PermissionRequiredMixin):
@property @property
def ta(self): def ta(self):
ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id']) ta = TextoArticulado.objects.get(
pk=self.kwargs.get('ta_id', self.kwargs.get('pk', 0)))
return ta return ta
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -407,10 +426,26 @@ class TaListView(CompMixin, ListView):
page_obj.number, paginator.num_pages) page_obj.number, paginator.num_pages)
return context return context
def get_queryset(self):
qs = ListView.get_queryset(self)
qs = qs.exclude(
~Q(owners=self.request.user.id),
privacidade=STATUS_TA_PRIVATE)
return qs
class TaDetailView(CompMixin, DetailView): class TaDetailView(CompMixin, DetailView):
model = TextoArticulado model = TextoArticulado
def has_permission(self):
self.object = self.ta
if self.object.has_view_permission(self.request):
return CompMixin.has_permission(self)
else:
return False
@property @property
def title(self): def title(self):
if self.get_object().content_object: if self.get_object().content_object:
@ -736,9 +771,9 @@ class TextView(CompMixin, ListView):
fim_vigencia = None fim_vigencia = None
ta_vigencia = None ta_vigencia = None
def get(self, request, *args, **kwargs): def has_permission(self):
self.object = self.ta self.object = self.ta
return super(TextView, self).get(request, *args, **kwargs) return self.object.has_view_permission(self.request)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(TextView, self).get_context_data(**kwargs) context = super(TextView, self).get_context_data(**kwargs)
@ -931,7 +966,42 @@ class DispositivoView(TextView):
class TextEditView(CompMixin, TemplateView): class TextEditView(CompMixin, TemplateView):
template_name = 'compilacao/text_edit.html' template_name = 'compilacao/text_edit.html'
permission_required = 'compilacao.change_dispositivo_edicao_dinamica'
def has_permission(self):
self.object = self.ta
return self.object.has_edit_permission(self.request)
def get(self, request, *args, **kwargs):
if self.object.editing_locked:
if 'unlock' not in request.GET:
messages.error(
request, _(
'A edição deste Texto Articulado está bloqueada.'))
return redirect(to=reverse_lazy(
'sapl.compilacao:ta_text', kwargs={
'ta_id': self.object.id}))
else:
# TODO - implementar logging de ação de usuário
self.object.editing_locked = False
self.object.privacidade = STATUS_TA_EDITION
self.object.save()
messages.success(request, _(
'Texto Articulado desbloqueado com sucesso.'))
else:
if 'lock' in request.GET:
# TODO - implementar logging de ação de usuário
self.object.editing_locked = True
self.object.privacidade = STATUS_TA_PUBLIC
self.object.save()
messages.success(request, _(
'Texto Articulado bloqueado com sucesso.'))
return redirect(to=reverse_lazy(
'sapl.compilacao:ta_text', kwargs={
'ta_id': self.object.id}))
return TemplateView.get(self, request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
dispositivo_id = int(self.kwargs['dispositivo_id']) \ dispositivo_id = int(self.kwargs['dispositivo_id']) \
@ -2421,8 +2491,6 @@ class DispositivoDinamicEditView(
template_name = 'compilacao/text_edit_bloco.html' template_name = 'compilacao/text_edit_bloco.html'
model = Dispositivo model = Dispositivo
form_class = DispositivoEdicaoBasicaForm form_class = DispositivoEdicaoBasicaForm
contador = -1
permission_required = 'compilacao.change_dispositivo_edicao_dinamica',
def get_initial(self): def get_initial(self):
initial = UpdateView.get_initial(self) initial = UpdateView.get_initial(self)

5
sapl/crispy_layout_mixin.py

@ -1,12 +1,12 @@
from math import ceil from math import ceil
import rtyaml
from crispy_forms.bootstrap import FormActions from crispy_forms.bootstrap import FormActions
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit
from django import template from django import template
from django.utils import formats from django.utils import formats
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
import rtyaml
def heads_and_tails(list_of_lists): def heads_and_tails(list_of_lists):
@ -91,7 +91,8 @@ def get_field_display(obj, fieldname):
else: else:
display = '' display = ''
elif 'ManyRelatedManager' in str(type(value))\ elif 'ManyRelatedManager' in str(type(value))\
or 'RelatedManager' in str(type(value)): or 'RelatedManager' in str(type(value))\
or 'GenericRelatedObjectManager' in str(type(value)):
display = '<ul>' display = '<ul>'
for v in value.all(): for v in value.all():
display += '<li>%s</li>' % str(v) display += '<li>%s</li>' % str(v)

7
sapl/crud/base.py

@ -16,8 +16,8 @@ from django.http.response import Http404
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.decorators import classonlymethod from django.utils.decorators import classonlymethod
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _
from django.views.generic import (CreateView, DeleteView, DetailView, ListView, from django.views.generic import (CreateView, DeleteView, DetailView, ListView,
UpdateView) UpdateView)
from django.views.generic.base import ContextMixin from django.views.generic.base import ContextMixin
@ -29,6 +29,7 @@ from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL,
from sapl.settings import BASE_DIR from sapl.settings import BASE_DIR
from sapl.utils import normalize from sapl.utils import normalize
logger = logging.getLogger(BASE_DIR.name) logger = logging.getLogger(BASE_DIR.name)
ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \ ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \
@ -1401,10 +1402,6 @@ class CrudBaseForListAndDetailExternalAppView(MasterDetailCrud):
class BaseMixin(Crud.PublicMixin, MasterDetailCrud.BaseMixin): 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): def resolve_url(self, suffix, args=None):
obj = self.crud if hasattr(self, 'crud') else self obj = self.crud if hasattr(self, 'crud') else self

35
sapl/materia/forms.py

@ -1,8 +1,7 @@
import os
from datetime import date, datetime from datetime import date, datetime
import os
import django_filters
from crispy_forms.bootstrap import (Alert, FormActions, InlineCheckboxes, from crispy_forms.bootstrap import (Alert, FormActions, InlineCheckboxes,
InlineRadios) InlineRadios)
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
@ -18,10 +17,12 @@ from django.db.models import Max
from django.forms import ModelForm, widgets from django.forms import ModelForm, widgets
from django.forms.forms import Form from django.forms.forms import Form
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import django_filters
import sapl
from sapl.base.models import Autor from sapl.base.models import Autor
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
from sapl.compilacao.models import STATUS_TA_PRIVATE,\
STATUS_TA_IMMUTABLE_PUBLIC
from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
to_row) to_row)
from sapl.materia.models import (MateriaLegislativa, RegimeTramitacao, from sapl.materia.models import (MateriaLegislativa, RegimeTramitacao,
@ -35,6 +36,7 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
ChoiceWithoutValidationField, ChoiceWithoutValidationField,
MateriaPesquisaOrderingFilter, RangeWidgetOverride, MateriaPesquisaOrderingFilter, RangeWidgetOverride,
autor_label, autor_modal, models_with_gr_for_model) autor_label, autor_modal, models_with_gr_for_model)
import sapl
from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial, from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial,
DocumentoAcessorio, MateriaLegislativa, Numeracao, DocumentoAcessorio, MateriaLegislativa, Numeracao,
@ -1134,6 +1136,12 @@ class ConfirmarProposicaoForm(ProposicaoForm):
self.instance.data_envio = None self.instance.data_envio = None
self.instance.save() self.instance.save()
if self.instance.texto_articulado.exists():
ta = self.instance.texto_articulado.first()
ta.privacidade = STATUS_TA_PRIVATE
ta.editing_locked = False
ta.save()
self.instance.results = { self.instance.results = {
'messages': { 'messages': {
'success': [_('Devolução efetuada com sucesso.'), ] 'success': [_('Devolução efetuada com sucesso.'), ]
@ -1147,6 +1155,12 @@ class ConfirmarProposicaoForm(ProposicaoForm):
self.instance.data_devolucao = None self.instance.data_devolucao = None
self.instance.data_recebimento = datetime.now() self.instance.data_recebimento = datetime.now()
if self.instance.texto_articulado.exists():
ta = self.instance.texto_articulado.first()
ta.privacidade = STATUS_TA_IMMUTABLE_PUBLIC
ta.editing_locked = True
ta.save()
self.instance.save() self.instance.save()
""" """
@ -1187,10 +1201,17 @@ class ConfirmarProposicaoForm(ProposicaoForm):
materia.data_apresentacao = datetime.now() materia.data_apresentacao = datetime.now()
materia.em_tramitacao = True materia.em_tramitacao = True
materia.regime_tramitacao = cd['regime_tramitacao'] materia.regime_tramitacao = cd['regime_tramitacao']
materia.texto_original = File(
proposicao.texto_original, if proposicao.texto_original:
os.path.basename(proposicao.texto_original.path)) materia.texto_original = File(
materia.texto_articulo = proposicao.texto_articulado proposicao.texto_original,
os.path.basename(proposicao.texto_original.path))
if proposicao.texto_articulado.exists():
pass
# FIXME - gerar texto_articulado da materia com base na prop.
# materia.texto_articulo = proposicao.texto_articulado
materia.save() materia.save()
conteudo_gerado = materia conteudo_gerado = materia

86
sapl/materia/views.py

@ -1,6 +1,7 @@
from datetime import datetime from datetime import datetime
from random import choice from random import choice
from string import ascii_letters, digits from string import ascii_letters, digits
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML from crispy_forms.layout import HTML
from django.contrib import messages from django.contrib import messages
@ -11,7 +12,7 @@ from django.core.mail import send_mail
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http import JsonResponse from django.http import JsonResponse
from django.http.response import Http404, HttpResponseRedirect from django.http.response import Http404, HttpResponseRedirect
from django.shortcuts import redirect from django.shortcuts import redirect, get_object_or_404
from django.template import Context, loader from django.template import Context, loader
from django.utils import formats from django.utils import formats
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -21,6 +22,9 @@ from django.views.generic.edit import FormView
from django_filters.views import FilterView from django_filters.views import FilterView
from sapl.base.models import Autor, CasaLegislativa from sapl.base.models import Autor, CasaLegislativa
from sapl.compilacao.models import STATUS_TA_PRIVATE, STATUS_TA_EDITION,\
STATUS_TA_IMMUTABLE_RESTRICT
from sapl.compilacao.views import IntegracaoTaView from sapl.compilacao.views import IntegracaoTaView
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions from sapl.crispy_layout_mixin import SaplFormLayout, form_actions
from sapl.crud.base import (ACTION_CREATE, ACTION_DELETE, ACTION_DETAIL, from sapl.crud.base import (ACTION_CREATE, ACTION_DELETE, ACTION_DETAIL,
@ -107,7 +111,11 @@ class MateriaTaView(IntegracaoTaView):
'ano': 'ano', 'ano': 'ano',
} }
map_funcs = { map_funcs = {
'publicacao_func': False 'publicacao_func': False,
}
ta_values = {
'editable_only_by_owners': False,
'editing_locked': False,
} }
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
@ -126,7 +134,7 @@ class ProposicaoTaView(IntegracaoTaView):
model = Proposicao model = Proposicao
model_type_foreignkey = TipoProposicao model_type_foreignkey = TipoProposicao
map_fields = { map_fields = {
'data': 'data_recebimento', 'data': 'data_envio',
'ementa': 'descricao', 'ementa': 'descricao',
'observacao': None, 'observacao': None,
'numero': 'numero_proposicao', 'numero': 'numero_proposicao',
@ -135,6 +143,11 @@ class ProposicaoTaView(IntegracaoTaView):
map_funcs = { map_funcs = {
'publicacao_func': False 'publicacao_func': False
} }
ta_values = {
'editable_only_by_owners': True,
'editing_locked': False,
'privacidade': STATUS_TA_PRIVATE
}
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
""" """
@ -143,6 +156,13 @@ class ProposicaoTaView(IntegracaoTaView):
de usuário. de usuário.
""" """
if sapl.base.models.AppConfig.attr('texto_articulado_proposicao'): if sapl.base.models.AppConfig.attr('texto_articulado_proposicao'):
proposicao = get_object_or_404(self.model, pk=kwargs['pk'])
if not proposicao.data_envio and\
request.user != proposicao.autor.user:
raise Http404()
return IntegracaoTaView.get(self, request, *args, **kwargs) return IntegracaoTaView.get(self, request, *args, **kwargs)
else: else:
return self.get_redirect_deactivated() return self.get_redirect_deactivated()
@ -313,10 +333,14 @@ class ReceberProposicao(PermissionRequiredForAppCrudMixin, FormView):
data_envio__isnull=False, data_recebimento__isnull=True) data_envio__isnull=False, data_recebimento__isnull=True)
for proposicao in proposicoes: for proposicao in proposicoes:
# FIXME implementar hash para texto eletrônico if proposicao.texto_articulado.exists():
hasher = gerar_hash_arquivo( ta = proposicao.texto_articulado.first()
proposicao.texto_original.path, # FIXME hash para textos articulados
str(proposicao.pk)) if proposicao.texto_original else None hasher = 'P' + ta.hash() + '/' + str(proposicao.id)
else:
hasher = gerar_hash_arquivo(
proposicao.texto_original.path,
str(proposicao.pk)) if proposicao.texto_original else None
if hasher == form.cleaned_data['cod_hash']: if hasher == form.cleaned_data['cod_hash']:
return HttpResponseRedirect( return HttpResponseRedirect(
reverse('sapl.materia:proposicao-confirmar', reverse('sapl.materia:proposicao-confirmar',
@ -343,9 +367,6 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView):
form_class = ConfirmarProposicaoForm form_class = ConfirmarProposicaoForm
def get_success_url(self): def get_success_url(self):
# FIXME redirecionamento trival,
# ainda por implementar se será para protocolo ou para doc resultante
msgs = self.object.results['messages'] msgs = self.object.results['messages']
for key, value in msgs.items(): for key, value in msgs.items():
@ -365,9 +386,15 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView):
data_recebimento__isnull=True) data_recebimento__isnull=True)
self.object = None self.object = None
# FIXME implementar hash para texto eletrônico # FIXME implementar hash para texto eletrônico
hasher = gerar_hash_arquivo(
proposicao.texto_original.path, if proposicao.texto_articulado.exists():
str(proposicao.pk)) if proposicao.texto_original else None ta = proposicao.texto_articulado.first()
# FIXME hash para textos articulados
hasher = 'P' + ta.hash() + '/' + str(proposicao.id)
else:
hasher = gerar_hash_arquivo(
proposicao.texto_original.path,
str(proposicao.pk)) if proposicao.texto_original else None
if hasher == 'P%s/%s' % (self.kwargs['hash'], proposicao.pk): if hasher == 'P%s/%s' % (self.kwargs['hash'], proposicao.pk):
self.object = proposicao self.object = proposicao
@ -474,6 +501,13 @@ class ProposicaoCrud(Crud):
p.data_devolucao = None p.data_devolucao = None
p.data_envio = datetime.now() p.data_envio = datetime.now()
p.save() p.save()
if p.texto_articulado.exists():
ta = p.texto_articulado.first()
ta.privacidade = STATUS_TA_IMMUTABLE_RESTRICT
ta.editing_locked = True
ta.save()
messages.success(request, _( messages.success(request, _(
'Proposição enviada com sucesso.')) 'Proposição enviada com sucesso.'))
@ -486,6 +520,11 @@ class ProposicaoCrud(Crud):
else: else:
p.data_envio = None p.data_envio = None
p.save() p.save()
if p.texto_articulado.exists():
ta = p.texto_articulado.first()
ta.privacidade = STATUS_TA_PRIVATE
ta.editing_locked = False
ta.save()
messages.success(request, _( messages.success(request, _(
'Proposição Retornada com sucesso.')) 'Proposição Retornada com sucesso.'))
@ -547,9 +586,8 @@ class ProposicaoCrud(Crud):
messages.info(self.request, messages.info(self.request,
_('Sempre que uma Proposição é inclusa ou ' _('Sempre que uma Proposição é inclusa ou '
'alterada e a opção "Texto Articulado " for ' 'alterada e a opção "Texto Articulado " for '
'marcada, você será redirecionado para o ' 'marcada, você será redirecionado para a '
'Texto Eletrônico. Use a opção "Editar Texto" ' 'edição do Texto Eletrônico.'))
'para construir seu texto.'))
return reverse('sapl.materia:proposicao_ta', return reverse('sapl.materia:proposicao_ta',
kwargs={'pk': self.object.pk}) kwargs={'pk': self.object.pk})
else: else:
@ -618,10 +656,18 @@ class ReciboProposicaoView(TemplateView):
context = super(ReciboProposicaoView, self).get_context_data( context = super(ReciboProposicaoView, self).get_context_data(
**kwargs) **kwargs)
proposicao = Proposicao.objects.get(pk=self.kwargs['pk']) proposicao = Proposicao.objects.get(pk=self.kwargs['pk'])
if proposicao.texto_original:
_hash = gerar_hash_arquivo(
proposicao.texto_original.path,
self.kwargs['pk'])
elif proposicao.texto_articulado.exists():
ta = proposicao.texto_articulado.first()
# FIXME hash para textos articulados
_hash = 'P' + ta.hash() + '/' + str(proposicao.id)
context.update({'proposicao': proposicao, context.update({'proposicao': proposicao,
'hash': gerar_hash_arquivo( 'hash': _hash})
proposicao.texto_original.path,
self.kwargs['pk'])})
return context return context
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
@ -631,7 +677,7 @@ class ReciboProposicaoView(TemplateView):
return TemplateView.get(self, request, *args, **kwargs) return TemplateView.get(self, request, *args, **kwargs)
if not proposicao.data_envio and not proposicao.data_devolucao: if not proposicao.data_envio and not proposicao.data_devolucao:
messages.error(request, _('Não é possível gerar recebo para uma ' messages.error(request, _('Não é possível gerar recibo para uma '
'Proposição ainda não enviada.')) 'Proposição ainda não enviada.'))
elif proposicao.data_devolucao: elif proposicao.data_devolucao:
messages.error(request, _('Não é possível gerar recibo.')) messages.error(request, _('Não é possível gerar recibo.'))

35
sapl/parlamentares/views.py

@ -54,6 +54,12 @@ class RelatoriaParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
help_path = 'relatoria_parlamentar' help_path = 'relatoria_parlamentar'
namespace = AppConfig.name namespace = AppConfig.name
class BaseMixin(CrudBaseForListAndDetailExternalAppView.BaseMixin):
@classmethod
def url_name(cls, suffix):
return '%s_parlamentar_%s' % (cls.model._meta.model_name, suffix)
class ProposicaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView): class ProposicaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
model = Proposicao model = Proposicao
@ -61,10 +67,31 @@ class ProposicaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
parent_field = 'autor__parlamentar_set' parent_field = 'autor__parlamentar_set'
namespace = AppConfig.name namespace = AppConfig.name
class BaseMixin(CrudBaseForListAndDetailExternalAppView.BaseMixin):
@classmethod
def url_name(cls, suffix):
return '%s_parlamentar_%s' % (cls.model._meta.model_name, suffix)
class ListView(CrudBaseForListAndDetailExternalAppView.ListView): class ListView(CrudBaseForListAndDetailExternalAppView.ListView):
def get_queryset(self): def get_queryset(self):
return super().get_queryset().filter(data_envio__isnull=False) return super().get_queryset().filter(
data_envio__isnull=False,
data_recebimento__isnull=False)
class DetailView(CrudBaseForListAndDetailExternalAppView.DetailView):
@property
def extras_url(self):
if self.object.texto_articulado.exists():
ta = self.object.texto_articulado.first()
yield (str(reverse_lazy(
'sapl.compilacao:ta_text',
kwargs={'ta_id': ta.pk})) + '?back_type=history',
'btn-success',
_('Texto Eletrônico'))
class ParticipacaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView): class ParticipacaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
@ -74,6 +101,12 @@ class ParticipacaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
list_field_names = ['composicao__comissao__nome', 'cargo__nome', ( list_field_names = ['composicao__comissao__nome', 'cargo__nome', (
'composicao__periodo__data_inicio', 'composicao__periodo__data_fim')] 'composicao__periodo__data_inicio', 'composicao__periodo__data_fim')]
class BaseMixin(CrudBaseForListAndDetailExternalAppView.BaseMixin):
@classmethod
def url_name(cls, suffix):
return '%s_parlamentar_%s' % (cls.model._meta.model_name, suffix)
class ListView(CrudBaseForListAndDetailExternalAppView.ListView): class ListView(CrudBaseForListAndDetailExternalAppView.ListView):
ordering = ('-composicao__periodo') ordering = ('-composicao__periodo')

15
sapl/rules/map_rules.py

@ -84,6 +84,7 @@ rules_group_protocolo = {
(materia.Autoria, __base__), (materia.Autoria, __base__),
(materia.Proposicao, __listdetailchange__), (materia.Proposicao, __listdetailchange__),
(compilacao.TextoArticulado, ['view_restricted_textoarticulado'])
] ]
} }
@ -117,8 +118,8 @@ rules_group_materia = {
# quando testes forem feitos para permtir que matérias possam # quando testes forem feitos para permtir que matérias possam
# ser vinculadas a outras matérias via registro de compilação. # ser vinculadas a outras matérias via registro de compilação.
# Normalmente emendas e/ou projetos substitutivos podem alterar # Normalmente emendas e/ou projetos substitutivos podem alterar
# uma matéria original. Fazer esse registro de compilação # uma matéria original. Fazer esse registro de compilação ofereceria
# oferecia um autografo eletrônico pronto ser convertido em Norma. # um autografo eletrônico pronto para ser convertido em Norma.
]) ])
] ]
} }
@ -175,7 +176,7 @@ rules_group_autor = {
'rules': [ 'rules': [
(materia.Proposicao, __base__), (materia.Proposicao, __base__),
(compilacao.Dispositivo, __base__ + [ (compilacao.Dispositivo, __base__ + [
'change_dispositivo_edicao_dinamica', 'change_your_dispositivo_edicao_dinamica',
]) ])
] ]
} }
@ -258,12 +259,18 @@ rules_group_geral = {
# este model é um espelho do model integrado e sua edição pode # este model é um espelho do model integrado e sua edição pode
# confundir Autores, operadores de matéria e/ou norma. # confundir Autores, operadores de matéria e/ou norma.
# Por isso está adicionado apenas para o operador geral # Por isso está adicionado apenas para o operador geral
(compilacao.TextoArticulado, __base__), (compilacao.TextoArticulado, __base__ + ['lock_unlock_textoarticulado']),
# estes tres models são complexos e a principio apenas o admin tem perm # estes tres models são complexos e a principio apenas o admin tem perm
(compilacao.TipoDispositivo, []), (compilacao.TipoDispositivo, []),
(compilacao.TipoDispositivoRelationship, []), (compilacao.TipoDispositivoRelationship, []),
(compilacao.PerfilEstruturalTextoArticulado, []), (compilacao.PerfilEstruturalTextoArticulado, []),
] ]
} }

2
sapl/templates/compilacao/publicacao_detail.html

@ -8,7 +8,7 @@
{% block actions %} {% block actions %}
<div class="actions btn-group pull-right" role="group"> <div class="actions btn-group pull-right" role="group">
<a href="{% url 'sapl.compilacao:ta_pub_edit' object.ta.pk object.pk %}" class="btn btn-default">{% trans 'Editar' %}</a> <a href="{% url 'sapl.compilacao:ta_pub_edit' object.ta.pk object.pk %}" class="btn btn-default">{% trans 'Editar' %}</a>
<a href="{% url 'sapl.compilacao:ta_pub_delete' object.ta.pk object.pk %}" class="btn btn-default">{% trans 'Excluir' %}</a> <a href="{% url 'sapl.compilacao:ta_pub_delete' object.ta.pk object.pk %}" class="btn btn-default btn-excluir">{% trans 'Excluir' %}</a>
</div> </div>
{% endblock actions %} {% endblock actions %}
</div> </div>

6
sapl/templates/compilacao/text_edit.html

@ -11,7 +11,7 @@
{% endblock %} {% endblock %}
{% block title%} {% block title%}
<h1>{{object }}. <small><i>{% trans 'Texto Multivigente em Edição' %}</i></small></h1> <h1 class="page-header">{{object }}. <small><i>{% trans 'Texto Multivigente em Edição' %}</i></small></h1>
{% endblock %} {% endblock %}
{% block actions %} {% block actions %}
@ -19,6 +19,10 @@
<div class="clearfix"> <div class="clearfix">
<div class="actions btn-toolbar pull-right" role="toolbar"> <div class="actions btn-toolbar pull-right" role="toolbar">
<div class="actions btn-group" role="group"> <div class="actions btn-group" role="group">
{% if perms.compilacao.lock_unlock_textoarticulado and not object.editable_only_by_owners%}
<a href="{% url 'sapl.compilacao:ta_text_edit' object.pk %}?{% if object.editing_locked %}unlock{%else%}lock{% endif %}" class="btn btn-default btn-excluir">{% if object.editing_locked %}{% trans 'Desbloquear Edição' %}{%else%}{% trans 'Bloquear Edição' %}{% endif %}</a>
{% endif %}
<a href="{% url 'sapl.compilacao:ta_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Metadados do Texto Articulado' %}</a> <a href="{% url 'sapl.compilacao:ta_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Metadados do Texto Articulado' %}</a>
{% include 'compilacao/textoarticulado_menu_config.html' %} {% include 'compilacao/textoarticulado_menu_config.html' %}
</div> </div>

8
sapl/templates/compilacao/text_list.html

@ -11,6 +11,13 @@
{% endblock %} {% endblock %}
{% block extra_sections_nav %}{% endblock %} {% block extra_sections_nav %}{% endblock %}
{% block base_content %} {% block base_content %}
{% block actions %}
{{block.super}}
{% endblock %}
{% comment %}
{% if perms.compilacao.change_dispositivo_edicao_dinamica %} {% if perms.compilacao.change_dispositivo_edicao_dinamica %}
{% block actions %} {% block actions %}
<div class="clearfix"> <div class="clearfix">
@ -20,6 +27,7 @@
</div> </div>
{% endblock actions %} {% endblock actions %}
{% endif %} {% endif %}
{% endcomment %}
{% block detail_content %} {% block detail_content %}
{{block.super}} {{block.super}}

27
sapl/templates/compilacao/textoarticulado_detail.html

@ -7,7 +7,9 @@
<ul class="nav nav-pills navbar-right"> <ul class="nav nav-pills navbar-right">
{%if object %} {%if object %}
<li> <li>
{% if object.content_object%} {% if request.GET.back_type == 'history' and object.content_object %}
<a href="javascript:window.history.back()" title="{% trans 'Voltar para '%}{{object.content_object}}">{% trans 'Voltar para '%}{{object.content_object}}</a>
{% elif object.content_object%}
<a href="{% url object|urldetail_content_type object.content_object.pk %}" title="{% trans 'Voltar para '%}{{object.content_object}}">{% trans 'Voltar para '%}{{object.content_object}}</a> <a href="{% url object|urldetail_content_type object.content_object.pk %}" title="{% trans 'Voltar para '%}{{object.content_object}}">{% trans 'Voltar para '%}{{object.content_object}}</a>
{%else%} {%else%}
<a href="{% url 'sapl.compilacao:ta_detail' object.pk %}">{% trans 'Início' %}</a> <a href="{% url 'sapl.compilacao:ta_detail' object.pk %}">{% trans 'Início' %}</a>
@ -30,13 +32,18 @@
{% block actions %} {% block actions %}
<div class="clearfix"> <div class="clearfix">
<div class="actions btn-group pull-right" role="group"> <div class="actions btn-group pull-right" role="group">
{% if perms.compilacao.change_textoarticulado %} {% if perms.compilacao.lock_unlock_textoarticulado and not object.editable_only_by_owners%}
<a href="{% url 'sapl.compilacao:ta_text_edit' object.pk %}?{% if object.editing_locked %}unlock{%else%}lock{% endif %}" class="btn btn-default btn-excluir">{% if object.editing_locked %}{% trans 'Desbloquear Edição' %}{%else%}{% trans 'Bloquear Edição' %}{% endif %}</a>
{% endif %}
{% if perms.compilacao.change_textoarticulado and object|can_use_dynamic_editing:user %}
<a href="{% url 'sapl.compilacao:ta_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Metadados do Texto Articulado' %}</a> <a href="{% url 'sapl.compilacao:ta_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Metadados do Texto Articulado' %}</a>
{% endif %} {% endif %}
{% if perms.compilacao.change_dispositivo_edicao_dinamica %} {% if object|can_use_dynamic_editing:user %}
<a href="{% url 'sapl.compilacao:ta_text_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Texto' %}</a> <a href="{% url 'sapl.compilacao:ta_text_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Texto' %}</a>
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% endblock actions %} {% endblock actions %}
@ -82,14 +89,14 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<div id="div_id_ementa" class="holder"> <div id="div_id_ementa" class="holder">
<label>{% field_verbose_name object 'ementa' %}</label> <label>{% field_verbose_name object 'ementa' %}</label>
<p>{{ object.ementa|safe}}</p> <p>{{ object.ementa|safe}}</p>
</div>
</div> </div>
</div> </div>
</div>
</fieldset> </fieldset>
{% endblock detail_content %} {% endblock detail_content %}
{% endblock base_content %} {% endblock base_content %}

29
sapl/templates/compilacao/tipotextoarticulado_detail.html

@ -10,8 +10,7 @@
{% block actions %} {% block actions %}
<div class="actions btn-group pull-right" role="group"> <div class="actions btn-group pull-right" role="group">
{% if perms.compilacao.change_tipotextoarticulado %}<a class="btn btn-default" href="{% url 'sapl.compilacao:tipo_ta_edit' object.pk %}">{% trans 'Editar' %}</a>{% endif %} {% if perms.compilacao.change_tipotextoarticulado %}<a class="btn btn-default" href="{% url 'sapl.compilacao:tipo_ta_edit' object.pk %}">{% trans 'Editar' %}</a>{% endif %}
{% if perms.compilacao.delete_tipotextoarticulado %}<a class="btn btn-default" href="{% url 'sapl.compilacao:tipo_ta_delete' object.pk %}">{% trans 'Excluir' %}</a>{% endif %} {% if perms.compilacao.delete_tipotextoarticulado %}<a class="btn btn-default btn-excluir" href="{% url 'sapl.compilacao:tipo_ta_delete' object.pk %}">{% trans 'Excluir' %}</a>{% endif %}
</div> </div>
{% endblock actions %} {% endblock actions %}
</div> </div>
@ -20,33 +19,43 @@
<fieldset> <fieldset>
<legend>{%trans 'Identificação Básica'%}</legend> <legend>{%trans 'Identificação Básica'%}</legend>
<div class="row"> <div class="row">
<div class="col-md-2"> <div class="col-md-3">
<div id="div_id_tipo" class="holder"> <div id="div_id_tipo" class="holder">
<label>{% field_verbose_name object 'sigla' %}</label> <label>{% field_verbose_name object 'sigla' %}</label>
<p>{{ object.sigla}}</p> <p>{{ object.sigla}}</p>
</div> </div>
</div> </div>
<div class="col-md-4"> <div class="col-md-5">
<div id="div_id_numero" class="holder"> <div id="div_id_numero" class="holder">
<label>{% field_verbose_name object 'descricao' %}</label> <label>{% field_verbose_name object 'descricao' %}</label>
<p>{{ object.descricao}}</p> <p>{{ object.descricao}}</p>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-4">
<div id="div_id_ano" class="holder"> <div id="div_id_ano" class="holder">
<label>{% field_verbose_name object 'content_type' %}</label> <label>{% field_verbose_name object 'content_type' %}</label>
<p>{{ object.content_type|default:""}}</p> <p>{{ object.content_type|default:""}}</p>
</div> </div>
</div> </div>
<div class="col-md-3"> </fieldset>
<div id="div_id_ano" class="holder"> <fieldset>
<label>{% field_verbose_name object 'participacao_social' %}</label> <legend>{%trans 'Funcionalidades'%}</legend>
<p>{{ object.get_participacao_social_display}}</p> <div class="row">
</div> <div class="col-md-3">
<div id="div_id_ano" class="holder">
<label>{% field_verbose_name object 'participacao_social' %}</label>
<p>{{ object.get_participacao_social_display}}</p>
</div>
</div>
<div class="col-md-3">
<div id="div_id_ano" class="holder">
<label>{% field_verbose_name object 'publicacao_func' %}</label>
<p>{{ object.get_publicacao_func_display}}</p>
</div> </div>
</div> </div>
</div>
</fieldset> </fieldset>
{% endblock detail_content %} {% endblock detail_content %}
{% endblock base_content %} {% endblock base_content %}

9
sapl/templates/crud/detail.html

@ -21,6 +21,15 @@
</a> </a>
{% endif %} {% endif %}
</div> </div>
{% if view.extras_url %}
<div class="actions btn-group btn-group-sm" role="group">
{% for url, css_class, text in view.extras_url %}
<a href="{{url}}" class="btn btn-default {{css_class}}">
{{text}}
</a>
{% endfor %}
</div>
{% endif %}
{% endblock sub_actions %} {% endblock sub_actions %}
<div class="editons pull-right"> <div class="editons pull-right">

11
sapl/templates/crud/detail_detail.html

@ -18,6 +18,17 @@
</a> </a>
{% endif %} {% endif %}
</div> </div>
{% if view.extras_url %}
<div class="actions btn-group btn-group-sm" role="group">
{% for url, css_class, text in view.extras_url %}
<a href="{{url}}" class="btn btn-default {{css_class}}">
{{text}}
</a>
{% endfor %}
</div>
{% endif %}
{% if view.update_url or view.delete_url %} {% if view.update_url or view.delete_url %}
<div class="actions btn-group pull-right " role="group"> <div class="actions btn-group pull-right " role="group">
{% if view.update_url %} {% if view.update_url %}

1
sapl/templates/materia/proposicao_detail.html

@ -123,5 +123,4 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% endblock detail_content %} {% endblock detail_content %}

Loading…
Cancel
Save