diff --git a/sapl/compilacao/models.py b/sapl/compilacao/models.py index 6752a82c1..9e589f65b 100644 --- a/sapl/compilacao/models.py +++ b/sapl/compilacao/models.py @@ -1,3 +1,5 @@ +from datetime import datetime + from django.contrib import messages from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType @@ -6,9 +8,11 @@ from django.db.models import F, Q from django.db.models.aggregates import Max from django.http.response import Http404 from django.template import defaultfilters +from django.utils.decorators import classonlymethod from django.utils.translation import ugettext_lazy as _ -from sapl.compilacao.utils import int_to_letter, int_to_roman +from sapl.compilacao.utils import int_to_letter, int_to_roman,\ + get_integrations_view_names from sapl.utils import YES_NO_CHOICES, get_settings_auth_user_model @@ -280,6 +284,129 @@ class TextoArticulado(TimestampedMixin): return True + @classonlymethod + def update_or_create(cls, view_integracao, obj): + + map_fields = view_integracao.map_fields + ta_values = getattr(view_integracao, 'ta_values', {}) + + related_object_type = ContentType.objects.get_for_model(obj) + ta = TextoArticulado.objects.filter( + object_id=obj.pk, + content_type=related_object_type) + + ta_exists = bool(ta.exists()) + + if not ta_exists: + tipo_ta = TipoTextoArticulado.objects.filter( + content_type=related_object_type).first() + + ta = TextoArticulado() + ta.tipo_ta = tipo_ta + ta.content_object = obj + + 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: + ta = ta[0] + + if not ta.data: + ta.data = getattr(obj, map_fields['data'] + if map_fields['data'] else 'xxx', + datetime.now()) + if not ta.data: + ta.data = datetime.now() + + ta.ementa = getattr( + obj, map_fields['ementa'] + if map_fields['ementa'] else 'xxx', _( + 'Integração com %s sem ementa.') % obj) + + ta.observacao = getattr( + obj, map_fields['observacao'] + if map_fields['observacao'] else 'xxx', '') + + ta.numero = getattr( + obj, map_fields['numero'] + if map_fields['numero'] else 'xxx', int('%s%s%s' % ( + int(datetime.now().year), + int(datetime.now().month), + int(datetime.now().day)))) + + ta.ano = getattr(obj, map_fields['ano'] + if map_fields['ano'] else 'xxx', datetime.now().year) + + ta.save() + return ta + + def clone_for(self, obj): + # O clone gera um texto válido original dada a base self, + # mesmo sendo esta base um texto compilado. + # Os dispositivos a clonar será com base no texto compilado + + assert self.tipo_ta and self.tipo_ta.content_type, _( + 'Não é permitido chamar o método clone_for ' + 'para Textos Articulados independentes.') + + view_integracao = list(filter(lambda x: + x.model == obj._meta.model, + get_integrations_view_names())) + + assert len(view_integracao) > 0, _( + 'Não é permitido chamar o método clone_for ' + 'se não existe integração.') + + assert len(view_integracao) == 1, _( + 'Não é permitido haver mais de uma integração para um Model.') + + view_integracao = view_integracao[0] + + ta = TextoArticulado.update_or_create(view_integracao, obj) + + dispositivos = Dispositivo.objects.filter(ta=self).order_by('ordem') + + map_ids = {} + for d in dispositivos: + id_old = d.id + + # TODO + # validar isso: é o suficiente para pegar apenas o texto válido? + # exemplo: + # quando uma matéria for alterada por uma emenda + # ao usar esta função para gerar uma norma deve vir apenas + # o texto válido, compilado... + if d.dispositivo_subsequente: + continue + + d.id = None + d.inicio_vigencia = ta.data + d.fim_vigencia = None + d.inicio_eficacia = ta.data + d.fim_eficacia = None + d.publicacao = None + d.ta = ta + d.ta_publicado = None + d.dispositivo_subsequente = None + d.dispositivo_substituido = None + d.dispositivo_vigencia = None + d.dispositivo_atualizador = None + d.save() + map_ids[id_old] = d.id + + dispositivos = Dispositivo.objects.filter(ta=ta).order_by('ordem') + + for d in dispositivos: + if not d.dispositivo_pai: + continue + + d.dispositivo_pai_id = map_ids[d.dispositivo_pai_id] + d.save() + + return ta + def reagrupar_ordem_de_dispositivos(self): dpts = Dispositivo.objects.filter(ta=self) diff --git a/sapl/compilacao/utils.py b/sapl/compilacao/utils.py index 83f44e8f3..aa1793484 100644 --- a/sapl/compilacao/utils.py +++ b/sapl/compilacao/utils.py @@ -1,3 +1,4 @@ +import sys DISPOSITIVO_SELECT_RELATED = ( 'tipo_dispositivo', @@ -52,3 +53,16 @@ def int_to_letter(int_value): result = chr(rest + 65) + result result = chr(int_value + 65) + result return result + + +def get_integrations_view_names(): + result = [] + modules = sys.modules + for key, value in modules.items(): + if key.endswith('.views'): + for v in value.__dict__.values(): + if hasattr(v, '__bases__'): + for base in v.__bases__: + if 'IntegracaoTaView' in str(base): + result.append(v) + return result diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index 3b25eb045..1d5e6d459 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -45,7 +45,8 @@ from sapl.compilacao.models import (Dispositivo, Nota, VeiculoPublicacao, Vide, STATUS_TA_EDITION, STATUS_TA_PRIVATE, STATUS_TA_PUBLIC) from sapl.compilacao.utils import (DISPOSITIVO_SELECT_RELATED, - DISPOSITIVO_SELECT_RELATED_EDIT) + DISPOSITIVO_SELECT_RELATED_EDIT, + get_integrations_view_names) from sapl.crud.base import Crud, CrudListView, make_pagination from sapl.settings import BASE_DIR @@ -60,19 +61,6 @@ TipoDispositivoCrud = Crud.build( logger = logging.getLogger(BASE_DIR.name) -def get_integrations_view_names(): - result = [] - modules = sys.modules - for key, value in modules.items(): - if key.endswith('.views'): - for v in value.__dict__.values(): - if hasattr(v, '__bases__'): - for base in v.__bases__: - if base == IntegracaoTaView: - result.append(v) - return result - - def choice_models_in_extenal_views(): integrations_view_names = get_integrations_view_names() result = [(None, '-------------'), ] @@ -165,54 +153,35 @@ class IntegracaoTaView(TemplateView): object_id=item.pk, content_type=related_object_type) - tipo_ta = TipoTextoArticulado.objects.filter( - content_type=related_object_type) - ta_exists = bool(ta.exists()) - if not ta_exists: - ta = TextoArticulado() - tipo_ta = TipoTextoArticulado.objects.filter( - content_type=related_object_type)[:1] - if tipo_ta.exists(): - ta.tipo_ta = tipo_ta[0] - ta.content_object = item - - ta.privacidade = ta_values.get('privacidade', STATUS_TA_EDITION) + if (ta_exists or + (request.user.has_perm( + 'compilacao.change_dispositivo_edicao_dinamica') and + ta_values.get('privacidade', STATUS_TA_EDITION + ) != STATUS_TA_PRIVATE) or + (request.user.has_perm( + 'compilacao.change_your_dispositivo_edicao_dinamica') and + ta_values.get('privacidade', STATUS_TA_EDITION + ) == STATUS_TA_PUBLIC)): + """ + o texto articulado será criado/atualizado se: + - texto articulado já foi criado. - ta.editing_locked = ta_values.get('editing_locked', False) - ta.editable_only_by_owners = ta_values.get( - 'editable_only_by_owners', False) + - não foi criado e o usuário possui permissão para criar + desde que o texto não seja um texto privado pois a permissão + para criar textos privados é diferente. + - não foi criado e o usuário possui permissão para criar desde + que o texto seja privado e a permissão seja específica para + textos privados. + """ + pass else: - ta = ta[0] - - if not ta.data: - 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( - item, map_fields['ementa'] - if map_fields['ementa'] else 'xxx', _( - 'Integração com %s sem ementa.') % item) - - ta.observacao = getattr( - item, map_fields['observacao'] - if map_fields['observacao'] else 'xxx', '') - - ta.numero = getattr( - item, map_fields['numero'] - if map_fields['numero'] else 'xxx', int('%s%s%s' % ( - int(datetime.now().year), - int(datetime.now().month), - int(datetime.now().day)))) - - ta.ano = getattr(item, map_fields['ano'] - if map_fields['ano'] else 'xxx', datetime.now().year) - - ta.save() + messages.info(request, _('%s não possui %s.') % ( + item, TextoArticulado._meta.verbose_name)) + return redirect('/message') + + ta = TextoArticulado.update_or_create(self, item) if not ta_exists: if ta.editable_only_by_owners and\ diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index aedb90532..9f107a87d 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -22,7 +22,7 @@ import django_filters from sapl.base.models import Autor from sapl.comissoes.models import Comissao from sapl.compilacao.models import STATUS_TA_PRIVATE,\ - STATUS_TA_IMMUTABLE_PUBLIC, TextoArticulado + STATUS_TA_IMMUTABLE_PUBLIC, TextoArticulado, STATUS_TA_PUBLIC from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, to_row) from sapl.materia.models import TipoProposicao, MateriaLegislativa,\ @@ -1212,14 +1212,10 @@ class ConfirmarProposicaoForm(ProposicaoForm): if proposicao.texto_articulado.exists(): ta = proposicao.texto_articulado.first() - - ta.id = None - ta.content_object = materia - ta.save() - - pass - # FIXME - gerar texto_articulado da materia com base na prop. - # materia.texto_articulo = proposicao.texto_articulado + ta_materia = ta.clone_for(materia) + ta_materia.editing_locked = True + ta_materia.privacidade = STATUS_TA_IMMUTABLE_PUBLIC + ta_materia.save() self.instance.results['messages']['success'].append(_( 'Matéria Legislativa registrada com sucesso (%s)' diff --git a/sapl/urls.py b/sapl/urls.py index ee512b31f..1869e760c 100644 --- a/sapl/urls.py +++ b/sapl/urls.py @@ -36,6 +36,7 @@ import sapl.sessao.urls urlpatterns = [ url(r'^$', TemplateView.as_view(template_name='index.html')), + url(r'^message$', TemplateView.as_view(template_name='base.html')), url(r'^admin/', include(admin.site.urls)), url(r'', include(sapl.comissoes.urls)),