Browse Source

Merge pull request #1356 from interlegis/1328-ref-autor-autoria-pesquisa

Resolve parte da refatoração da issue #1328
pull/1361/head
Leandro Roberto da Silva 7 years ago
committed by GitHub
parent
commit
e86dc47bf1
  1. 110
      sapl/api/forms.py
  2. 8
      sapl/api/urls.py
  3. 60
      sapl/api/views.py
  4. 4
      sapl/base/models.py
  5. 19
      sapl/materia/forms.py
  6. 84
      sapl/materia/views.py
  7. 5
      sapl/settings.py
  8. 17
      sapl/static/js/app.js
  9. 5
      sapl/templates/base/autor_form.html
  10. 8
      sapl/templates/materia/autoria_form.html

110
sapl/api/forms.py

@ -1,11 +1,15 @@
from django.db.models import Q
from django.db.models import Q, F
from django.forms.fields import CharField, MultiValueField
from django.forms.widgets import MultiWidget, TextInput
from django_filters.filters import MethodFilter, ModelChoiceFilter
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django_filters.filters import MethodFilter, ModelChoiceFilter, DateFilter
from rest_framework import serializers
from rest_framework.compat import django_filters
from rest_framework.filters import FilterSet
from sapl.base.models import Autor, TipoAutor
from sapl.parlamentares.models import Legislatura
from sapl.utils import generic_relations_for_model
@ -38,11 +42,13 @@ class SaplGenericRelationSearchFilterSet(FilterSet):
item.related_query_name(),
field[0])
)
if len(field) == 3 and field[2](qtext) is not None:
q_fs = q_fs | Q(**{'%s__%s%s' % (
item.related_query_name(),
field[0],
field[1]): qtext if len(field) == 2 else field[2](qtext)})
# if len(field) == 3 and field[2](qtext) is not
# None:
q_fs = q_fs | Q(**{'%s__%s%s' % (
item.related_query_name(),
field[0],
field[1]): qtext if len(field) == 2
else field[2](qtext)})
q = q & q_fs
@ -115,3 +121,93 @@ class AutorSearchForFieldFilterSet(AutorChoiceFilterSet):
v = '1' if v == 'True' else '0'
params[key] = v
return queryset.filter(**params).distinct('nome').order_by('nome')
class AutoresPossiveisFilterSet(FilterSet):
data_relativa = DateFilter(method='filter_data_relativa')
tipo = MethodFilter()
class Meta:
model = Autor
fields = ['data_relativa', 'tipo', ]
def filter_data_relativa(self, queryset, name, value):
return queryset
def filter_tipo(self, queryset, value):
try:
tipo = TipoAutor.objects.get(pk=value)
except:
raise serializers.ValidationError(_('Tipo de Autor inexistente.'))
qs = queryset.filter(tipo=tipo)
return qs
@property
def qs(self):
qs = super().qs
data_relativa = self.form.cleaned_data['data_relativa'] \
if 'data_relativa' in self.form.cleaned_data else None
tipo = self.form.cleaned_data['tipo'] \
if 'tipo' in self.form.cleaned_data else None
if not tipo and not data_relativa:
return qs
if tipo:
# não precisa de try except, já foi validado em filter_tipo
tipo = TipoAutor.objects.get(pk=tipo)
if not tipo.content_type:
return qs
filter_for_model = 'filter_%s' % tipo.content_type.model
if not hasattr(self, filter_for_model):
return qs
return getattr(self, filter_for_model)(qs, data_relativa)
def filter_parlamentar(self, queryset, data_relativa):
# não leva em conta afastamentos
if not data_relativa:
data_relativa = timezone.now()
legislatura_relativa = Legislatura.objects.filter(
data_inicio__lte=data_relativa,
data_fim__gte=data_relativa).first()
params = {
'parlamentar_set__mandato__data_inicio_mandato__lte':
data_relativa,
'parlamentar_set__mandato__data_fim_mandato__gte': data_relativa
}
if legislatura_relativa.atual():
params['parlamentar_set__ativo'] = True
qs = queryset.filter(**params).distinct()
return qs
def filter_frente(self, queryset, data_relativa):
# implementar regras específicas para frente
return queryset
def filter_comissao(self, queryset, data_relativa):
# implementar regras específicas para comissao
return queryset
def filter_orgao(self, queryset, data_relativa):
# implementar regras específicas para orgao
return queryset
def filter_bancada(self, queryset, data_relativa):
# implementar regras específicas para bancada
return queryset
def filter_bloco(self, queryset, data_relativa):
# implementar regras específicas para bloco
return queryset

8
sapl/api/urls.py

@ -3,7 +3,8 @@ from django.conf.urls import include, url
from rest_framework.routers import DefaultRouter
from sapl.api.views import (AutorListView, MateriaLegislativaViewSet,
ModelChoiceView, SessaoPlenariaViewSet)
ModelChoiceView, SessaoPlenariaViewSet,
AutoresPossiveisListView, AutoresProvaveisListView)
from .apps import AppConfig
@ -17,6 +18,11 @@ urlpatterns_router = router.urls
urlpatterns_api = [
url(r'^autor/provaveis',
AutoresProvaveisListView.as_view(), name='autores_provaveis_list'),
url(r'^autor/possiveis',
AutoresPossiveisListView.as_view(), name='autores_possiveis_list'),
url(r'^autor', AutorListView.as_view(), name='autor_list'),
url(r'^model/(?P<content_type>\d+)/(?P<pk>\d*)$',

60
sapl/api/views.py

@ -9,7 +9,8 @@ from rest_framework.permissions import (AllowAny, IsAuthenticated,
IsAuthenticatedOrReadOnly)
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from sapl.api.forms import AutorChoiceFilterSet, AutorSearchForFieldFilterSet
from sapl.api.forms import AutorChoiceFilterSet, AutorSearchForFieldFilterSet,\
AutoresPossiveisFilterSet
from sapl.api.serializers import (AutorChoiceSerializer, AutorSerializer,
ChoiceSerializer,
MateriaLegislativaSerializer,
@ -57,14 +58,6 @@ class AutorListView(ListAPIView):
de Autores feita pelo django-filter
-> processo usado nas pesquisas, o mais usado.
= 2 -> para (value, text) usados geralmente
em combobox, radiobox, checkbox, etc com pesquisa básica
de Autores mas feito para Possíveis Autores armazenados
segundo o ContentType associado ao Tipo de Autor via
relacionamento genérico.
Busca feita sem django-filter processada no get_queryset
-> processo no cadastro de autores para seleção e busca
dos possíveis autores
= 3 -> Devolve instancias da classe Autor filtradas pelo
django-filter
@ -78,14 +71,14 @@ class AutorListView(ListAPIView):
o django-filter é desativado e a busca é feita
no model do ContentType associado ao tipo.
- q_0 / q_1 - q_0 faz o código ignorar "q"...
- q_0 / q_1 - q_0 é opcional e quando usado, faz o código ignorar "q"...
q_0 -> campos lookup a serem filtrados em qualquer Model
que implemente SaplGenericRelation
q_1 -> o valor que será pesquisado no lookup de q_0
q_0 e q_1 podem ser separados por ","... isso dará a
possibilidade de filtrar mais de um campo.
possibilidade de filtrar mais de um campo.
http://localhost:8000
@ -114,7 +107,7 @@ class AutorListView(ListAPIView):
não importa o campo que vc passe de qualquer dos Models
ligados... é possível ver que models são esses,
ligados... é possível ver que models são esses,
na ocasião do commit deste texto, executando:
In [6]: from sapl.utils import models_with_gr_for_model
@ -127,15 +120,13 @@ class AutorListView(ListAPIView):
sapl.sessao.models.Bancada,
sapl.sessao.models.Bloco]
qualquer atributo destes models podem ser passados
qualquer atributo destes models podem ser passados
para busca
"""
TR_AUTOR_CHOICE_SERIALIZER = 1
TR_CHOICE_SERIALIZER = 2
TR_AUTOR_SERIALIZER = 3
# FIXME aplicar permissão correta de usuário
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
model = Autor
@ -152,7 +143,6 @@ class AutorListView(ListAPIView):
assert tr in (
AutorListView.TR_AUTOR_CHOICE_SERIALIZER,
AutorListView.TR_CHOICE_SERIALIZER,
AutorListView.TR_AUTOR_SERIALIZER), sapl_logger.info(
_("Tipo do Resultado a ser fornecido não existe!"))
except:
@ -161,16 +151,8 @@ class AutorListView(ListAPIView):
return tr
def get(self, request, *args, **kwargs):
"""
desativa o django-filter se a busca for por possiveis autores
parametro tr = TR_CHOICE_SERIALIZER
"""
if self.tr == AutorListView.TR_CHOICE_SERIALIZER:
self.filter_class = None
self.filter_backends = []
self.serializer_class = ChoiceSerializer
elif self.tr == AutorListView.TR_AUTOR_SERIALIZER:
if self.tr == AutorListView.TR_AUTOR_SERIALIZER:
self.serializer_class = AutorSerializer
self.permission_classes = (IsAuthenticated,)
@ -179,12 +161,20 @@ class AutorListView(ListAPIView):
return ListAPIView.get(self, request, *args, **kwargs)
class AutoresProvaveisListView(ListAPIView):
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
model = Autor
filter_class = None
filter_backends = []
serializer_class = ChoiceSerializer
def get_queryset(self):
queryset = ListAPIView.get_queryset(self)
if self.filter_backends:
return queryset
params = {'content_type__isnull': False}
tipo = ''
@ -252,6 +242,18 @@ class AutorListView(ListAPIView):
return r
class AutoresPossiveisListView(ListAPIView):
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
model = Autor
pagination_class = None
filter_class = AutoresPossiveisFilterSet
serializer_class = AutorChoiceSerializer
class MateriaLegislativaViewSet(ListModelMixin,
RetrieveModelMixin,
GenericViewSet):

4
sapl/base/models.py

@ -1,11 +1,12 @@
import reversion
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.translation import ugettext_lazy as _
import reversion
from sapl.utils import UF, YES_NO_CHOICES, get_settings_auth_user_model
TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensivo')),
('R', _('Restritivo')))
@ -221,6 +222,7 @@ class Autor(models.Model):
verbose_name = _('Autor')
verbose_name_plural = _('Autores')
unique_together = (('content_type', 'object_id'), )
ordering = ('nome',)
def __str__(self):

19
sapl/materia/forms.py

@ -14,16 +14,15 @@ from django.core.urlresolvers import reverse
from django.db import models, transaction
from django.db.models import Max
from django.forms import ModelForm, ModelChoiceField, widgets
from django.forms.fields import BooleanField
from django.forms.forms import Form
from django.forms.widgets import Select
from django.forms.widgets import Select, HiddenInput
from django.utils import six
from django.utils.encoding import force_text
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django_filters.filterset import STRICTNESS
import django_filters
from sapl.base.models import Autor, TipoAutor
@ -693,10 +692,13 @@ class AutoriaForm(ModelForm):
tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
required=False,
queryset=
TipoAutor.objects.all().order_by('descricao'),
queryset=TipoAutor.objects.all().order_by(
'descricao'),
empty_label='Selecione',)
data_relativa = forms.DateField(
widget=forms.HiddenInput())
def __init__(self, *args, **kwargs):
super(AutoriaForm, self).__init__(*args, **kwargs)
@ -707,11 +709,14 @@ class AutoriaForm(ModelForm):
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(_('Autoria'),
row1, form_actions(save_label='Salvar')))
row1, 'data_relativa', form_actions(save_label='Salvar')))
if not kwargs['instance']:
self.fields['autor'].choices = []
class Meta:
model = Autoria
fields = ['tipo_autor', 'autor', 'primeiro_autor']
fields = ['tipo_autor', 'autor', 'primeiro_autor', 'data_relativa']
def clean(self):
super(AutoriaForm, self).clean()

84
sapl/materia/views.py

@ -2,23 +2,6 @@ from datetime import datetime, date
from random import choice
from string import ascii_letters, digits
from .email_utils import do_envia_email_confirmacao
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AdicionarVariasAutoriasFilterSet, DespachoInicialForm,
DocumentoAcessorioForm, MateriaAssuntoForm,
MateriaLegislativaFilterSet, MateriaSimplificadaForm,
PrimeiraTramitacaoEmLoteFilterSet, ReceberProposicaoForm,
RelatoriaForm, TramitacaoEmLoteFilterSet,
filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status,
filtra_tramitacao_status)
from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria,
DespachoInicial, DocumentoAcessorio, MateriaAssunto,
MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao,
RegimeTramitacao, Relatoria, StatusTramitacao,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa,
TipoProposicao, Tramitacao, UnidadeTramitacao)
from .signals import tramitacao_signal
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML
from django import forms
@ -39,7 +22,7 @@ from django.views.generic import CreateView, ListView, TemplateView, UpdateView
from django.views.generic.base import RedirectView
from django.views.generic.edit import FormView
from django_filters.views import FilterView
import sapl
from sapl.base.models import Autor, CasaLegislativa
from sapl.comissoes.models import Comissao
from sapl.comissoes.models import Comissao, Participacao
@ -62,7 +45,25 @@ from sapl.protocoloadm.models import Protocolo
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
autor_modal, gerar_hash_arquivo, get_base_url,
montar_row_autor)
import sapl
from .email_utils import do_envia_email_confirmacao
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AdicionarVariasAutoriasFilterSet, DespachoInicialForm,
DocumentoAcessorioForm, MateriaAssuntoForm,
MateriaLegislativaFilterSet, MateriaSimplificadaForm,
PrimeiraTramitacaoEmLoteFilterSet, ReceberProposicaoForm,
RelatoriaForm, TramitacaoEmLoteFilterSet,
filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status,
filtra_tramitacao_status)
from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria,
DespachoInicial, DocumentoAcessorio, MateriaAssunto,
MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao,
RegimeTramitacao, Relatoria, StatusTramitacao,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa,
TipoProposicao, Tramitacao, UnidadeTramitacao)
from .signals import tramitacao_signal
AssuntoMateriaCrud = Crud.build(AssuntoMateria, 'assunto_materia')
@ -93,8 +94,8 @@ def proposicao_texto(request, pk):
if proposicao.texto_original:
if (not proposicao.data_recebimento and
proposicao.autor.user_id != request.user.id):
raise Http404
proposicao.autor.user_id != request.user.id):
raise Http404
arquivo = proposicao.texto_original
@ -1093,24 +1094,27 @@ class AutoriaCrud(MasterDetailCrud):
def layout_key(self):
return 'AutoriaCreate'
def get_context_data(self, **kwargs):
context = super(CreateView, self).get_context_data(**kwargs)
autores_ativos = self.autores_ativos()
autores = []
context['form'].fields['autor'].choices = autores
return context
def get_initial(self):
initial = super().get_initial()
materia = MateriaLegislativa.objects.get(id=self.kwargs['pk'])
initial['data_relativa'] = materia.data_apresentacao
initial['autor'] = []
return initial
def autores_ativos(self):
lista_parlamentares = Parlamentar.objects.filter(ativo=True).values_list('id', flat=True)
lista_parlamentares = Parlamentar.objects.filter(
ativo=True).values_list('id', flat=True)
model_parlamentar = ContentType.objects.get_for_model(Parlamentar)
autor_parlamentar = Autor.objects.filter(content_type=model_parlamentar, object_id__in=lista_parlamentares)
autor_parlamentar = Autor.objects.filter(
content_type=model_parlamentar, object_id__in=lista_parlamentares)
lista_comissoes = Comissao.objects.filter(Q(data_extincao__isnull=True)|Q(data_extincao__gt=date.today())).values_list('id', flat=True)
lista_comissoes = Comissao.objects.filter(Q(data_extincao__isnull=True) | Q(
data_extincao__gt=date.today())).values_list('id', flat=True)
model_comissao = ContentType.objects.get_for_model(Comissao)
autor_comissoes = Autor.objects.filter(content_type=model_comissao, object_id__in=lista_comissoes)
autores_outros = Autor.objects.exclude(content_type__in=[model_parlamentar, model_comissao])
autor_comissoes = Autor.objects.filter(
content_type=model_comissao, object_id__in=lista_comissoes)
autores_outros = Autor.objects.exclude(
content_type__in=[model_parlamentar, model_comissao])
q = autor_parlamentar | autor_comissoes | autores_outros
return q
@ -1516,9 +1520,9 @@ class AcompanhamentoMateriaView(CreateView):
base_url = get_base_url(request)
destinatario = AcompanhamentoMateria.objects.get(
materia=materia,
email=email,
confirmado=False)
materia=materia,
email=email,
confirmado=False)
casa = CasaLegislativa.objects.first()
do_envia_email_confirmacao(base_url,
@ -1699,10 +1703,10 @@ class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView):
context['primeira_tramitacao'] = False
if ('tramitacao__status' in qr and
'tramitacao__unidade_tramitacao_destino' in qr and
qr['tramitacao__status'] and
qr['tramitacao__unidade_tramitacao_destino']
):
'tramitacao__unidade_tramitacao_destino' in qr and
qr['tramitacao__status'] and
qr['tramitacao__unidade_tramitacao_destino']
):
lista = filtra_tramitacao_destino_and_status(
qr['tramitacao__status'],
qr['tramitacao__unidade_tramitacao_destino'])

5
sapl/settings.py

@ -22,6 +22,7 @@ from unipath import Path
from .temp_suppress_crispy_form_warnings import \
SUPRESS_CRISPY_FORM_WARNINGS_LOGGING
BASE_DIR = Path(__file__).ancestor(1)
PROJECT_DIR = Path(__file__).ancestor(2)
@ -101,7 +102,7 @@ if SOLR_URL:
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': SEARCH_BACKEND,
SEARCH_URL[0] : SEARCH_URL[1]
SEARCH_URL[0]: SEARCH_URL[1]
},
}
@ -200,7 +201,7 @@ MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB
# https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = 'pt-br'
LANGUAGES = (
('pt-br','Português'),
('pt-br', 'Português'),
)
TIME_ZONE = 'America/Sao_Paulo'

17
sapl/static/js/app.js

@ -58,7 +58,7 @@ function autorModal() {
autoOpen: false,
modal: true,
width: 500,
height: 300,
height: 340,
show: {
effect: "blind",
duration: 500},
@ -90,11 +90,11 @@ function autorModal() {
$("#pesquisar").click(function() {
var name_in_query = $("#q").val()
var q_0 = "q_0=nome__icontains"
var q_1 = "q_1=" + name_in_query
query = q_0 + "&" + q_1
//var q_0 = "q_0=nome__icontains"
//var q_1 = name_in_query
//query = q_1
$.get("/api/autor?" + query, function(data, status) {
$.get("/api/autor?q=" + name_in_query, function(data, status) {
$("#div-resultado").children().remove();
if (data.pagination.total_entries == 0) {
$("#selecionar").attr("hidden", "hidden");
@ -111,11 +111,12 @@ function autorModal() {
select.append($("<option>").attr('value', item.value).text(item.text));
});
$("#div-resultado").append("<br/>").append(select);
$("#selecionar").removeAttr("hidden", "hidden");
if (data.pagination.total_pages > 1)
$("#div-resultado").prepend('<span><br/>Mostrando 10 primeiros autores relativos a sua busca.<br/></span>');
$("#selecionar").click(function() {
res = $("#resultados option:selected");
id = res.val();
@ -235,4 +236,4 @@ function getCookie(name) {
}
}
return cookieValue;
}
}

5
sapl/templates/base/autor_form.html

@ -28,12 +28,11 @@ $(document).ready(function(){
var update_search = function(pk, atualizar=true) {
var q = $('#id_q').val();
var url = '{% url 'sapl.api:autor_list'%}'
var url = '{% url 'sapl.api:autores_provaveis_list'%}'
var formData = {
'q' : q,
'tipo' : pk,
'tr' : '2' // tipo_resultado = 2 - api fornecerá possíveis Autores
'tipo' : pk
}
$.get(url, formData).done(function(data) {
active('pesquisa');

8
sapl/templates/materia/autoria_form.html

@ -19,9 +19,13 @@
$("#id_autor option").remove()
var selected = $("#id_tipo_autor").val();
if (selected !== undefined && selected !== null) {
$.getJSON("/api/autor?tipo=" + selected, function(data){
var json_data = {
tipo : selected,
data_relativa : $("#id_data_relativa").val()
}
$.getJSON("/api/autor/possiveis", json_data, function(data){
if (data) {
var results = data.results.sort(compare);
var results = data.sort(compare);
if (results.length > 1) {
$("#id_autor").append("<option>-----</option>");
}

Loading…
Cancel
Save