Browse Source

Ref Autor, TipoAutor, cria app api DRF

- Autor e TipoAutor migrados para app base.
- Foram refatorados para GR - Generic Relations
- Em TipoAutor: passou se a apontar também para um ContentType que
é usado para contextualização de dados da GR em Autor.
- A captura da combo de ContentTypes é feita através do apontamento
reverso nos models que se queira disponibilizar conceitualmente como
Autor
- Em Autor: neste commit, o form de create está em desenvolvimento, com
o buscador de possiveis autores baseados na seleção do usuário de
TipoAutor que, se não possui ContentType, abre o campo nome para
insersão, se possui ContentType, abre caixa de busca com atualização
jquery de radiobox's para o usuário selecionar um possível autor.
- api rest: para a busca funcionar e como objetivo de futuras
implementações em DRF, a app api foi criada, anotada nas configurações
gerais de sapl.urls com o prefixo /api.
- na api foi criada a uma ListAPIView para pesquisa de possiveis autores
baseados no tipo autor enviado, url /api/autor/possiveis/?P<pk>[0-9]*)$
que sem pk devolve a lista de TipoAutor e, com pk, devolve a lista dos
registros ligados ao ContentType, filtrados pelo parametro q
pull/739/head
LeandroRoberto 8 years ago
parent
commit
980e1a5fc5
  1. 1
      sapl/api/__init__.py
  2. 0
      sapl/api/admin.py
  3. 8
      sapl/api/apps.py
  4. 0
      sapl/api/forms.py
  5. 0
      sapl/api/migrations/__init__.py
  6. 25
      sapl/api/serializers.py
  7. 20
      sapl/api/urls.py
  8. 36
      sapl/api/views.py
  9. 214
      sapl/base/forms.py
  10. 55
      sapl/base/migrations/0022_auto_20161009_1222.py
  11. 25
      sapl/base/migrations/0023_auto_20161009_1852.py
  12. 64
      sapl/base/models.py
  13. 30
      sapl/base/urls.py
  14. 120
      sapl/base/views.py
  15. 4
      sapl/comissoes/models.py
  16. 7
      sapl/crispy_layout_mixin.py
  17. 125
      sapl/materia/forms.py
  18. 53
      sapl/materia/migrations/0054_auto_20161009_1222.py
  19. 32
      sapl/materia/migrations/0055_auto_20161009_1418.py
  20. 85
      sapl/materia/models.py
  21. 8
      sapl/materia/urls.py
  22. 118
      sapl/materia/views.py
  23. 4
      sapl/parlamentares/models.py
  24. 26
      sapl/protocoloadm/migrations/0003_auto_20161009_1222.py
  25. 33
      sapl/rest_pagination.py
  26. 9
      sapl/sessao/forms.py
  27. 1
      sapl/sessao/urls.py
  28. 24
      sapl/settings.py
  29. 1
      sapl/static/styles/app.scss
  30. 61
      sapl/templates/base/autor_form.html
  31. 13
      sapl/templates/base/layouts.yaml
  32. 20
      sapl/templates/base/tipoautor_form.html
  33. 17
      sapl/templates/materia/layouts.yaml
  34. 7
      sapl/templates/sistema.html
  35. 3
      sapl/urls.py

1
sapl/api/__init__.py

@ -0,0 +1 @@
default_app_config = 'sapl.api.apps.AppConfig'

0
sapl/api/admin.py

8
sapl/api/apps.py

@ -0,0 +1,8 @@
from django import apps
from django.utils.translation import ugettext_lazy as _
class AppConfig(apps.AppConfig):
name = 'sapl.api'
label = 'api'
verbose_name = _('API Rest')

0
sapl/api/forms.py

0
sapl/api/migrations/__init__.py

25
sapl/api/serializers.py

@ -0,0 +1,25 @@
from rest_framework import serializers
from sapl.comissoes.models import Comissao
from sapl.parlamentares.models import Parlamentar
class ChoiceSerializer(serializers.Serializer):
pk = serializers.IntegerField()
display = serializers.SerializerMethodField()
def get_display(self, obj):
return str(obj)
"""
class ModelChoiceParlamentarSerializer(ModelChoiceSerializer):
class Meta:
model = Parlamentar
class ModelChoiceComissaoSerializer(ModelChoiceSerializer):
class Meta:
model = Comissao
"""

20
sapl/api/urls.py

@ -0,0 +1,20 @@
from django.conf.urls import include, url
from rest_framework.routers import DefaultRouter
from sapl.api.views import TipoAutorContentOfModelContentTypeView
from .apps import AppConfig
app_name = AppConfig.name
# router = DefaultRouter()
urlpatterns = [
url(r'^autor/possiveis/(?P<pk>[0-9]*)$',
TipoAutorContentOfModelContentTypeView.as_view(),
name='autores_possiveis_pelo_tipo'),
]
# urlpatterns += router.urls

36
sapl/api/views.py

@ -0,0 +1,36 @@
from django.http import Http404
from rest_framework import mixins, viewsets
from rest_framework.generics import ListAPIView, GenericAPIView,\
get_object_or_404
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from sapl.api.serializers import ChoiceSerializer
from sapl.base.models import Autor, TipoAutor
class TipoAutorContentOfModelContentTypeView(ListAPIView):
serializer_class = ChoiceSerializer
permission_classes = (AllowAny,)
queryset = TipoAutor.objects.all()
model = TipoAutor
pagination_class = None
def get_queryset(self):
queryset = ModelViewSet.get_queryset(self)
if not self.kwargs['pk']:
return queryset
obj = get_object_or_404(queryset, pk=self.kwargs['pk'])
if not obj.content_type:
raise Http404
q = self.request.GET.get('q', None)
if not q:
return []
else:
return obj.content_type.model_class().objects.filter(
nome__icontains=q)[:10]

214
sapl/base/forms.py

@ -1,14 +1,23 @@
import django_filters
from crispy_forms.bootstrap import FieldWithButtons, StrictButton
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Fieldset, Layout
from crispy_forms.layout import HTML, Button, Fieldset, Layout, Field, Div, Row
from crispy_forms.templatetags.crispy_forms_field import css_class
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm
from django.core.exceptions import ValidationError
from django.db import models
from django.forms import ModelForm
from django.contrib.auth.models import Group
from django.contrib.auth.password_validation import validate_password
from django.contrib.contenttypes.fields import GenericRel
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError, ObjectDoesNotExist
from django.db import models, transaction
from django.forms import ModelForm, widgets
from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.crispy_layout_mixin import form_actions, to_row
from sapl.base.models import Autor, TipoAutor
from sapl.crispy_layout_mixin import form_actions, to_row, SaplFormLayout,\
to_column
from sapl.materia.models import MateriaLegislativa
from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MAX_IMAGE_UPLOAD_SIZE
@ -18,6 +27,199 @@ from sapl.utils import (RANGE_ANOS, ImageThumbnailFileInput,
from .models import AppConfig, CasaLegislativa
class TipoAutorForm(ModelForm):
content_type = forms.ModelChoiceField(
queryset=ContentType.objects.all(),
label=TipoAutor._meta.get_field('content_type').verbose_name,
required=False)
class Meta:
model = TipoAutor
fields = ['descricao',
'content_type', ]
def __init__(self, *args, **kwargs):
super(TipoAutorForm, self).__init__(*args, **kwargs)
# Models que apontaram uma GenericRelation com Autor
models_of_generic_relations = list(map(
lambda x: x.related_model,
filter(
lambda obj: obj.is_relation and
hasattr(obj, 'field') and
isinstance(obj, GenericRel),
Autor._meta.get_fields(include_hidden=True))
))
content_types = ContentType.objects.get_for_models(
*models_of_generic_relations)
self.fields['content_type'].choices = [
('', _('Outros (Especifique)'))] + [
(ct.pk, ct) for key, ct in content_types.items()]
class AutorForm(ModelForm):
"""senha = forms.CharField(
max_length=20,
label=_('Senha'),
required=True,
widget=forms.PasswordInput())
senha_confirma = forms.CharField(
max_length=20,
label=_('Confirmar Senha'),
required=True,
widget=forms.PasswordInput())
confirma_email = forms.EmailField(
required=True,
label=_('Confirmar Email'))
username = forms.CharField(
required=True,
max_length=50
)"""
q = forms.CharField(
max_length=50, required=False,
label='Pesquise o nome do Autor com o tipo Selecionado')
content_object = forms.ChoiceField(label='',
required=False,
widget=forms.RadioSelect())
class Meta:
model = Autor
fields = ['tipo',
'nome',
'content_object',
'q']
def __init__(self, *args, **kwargs):
content_object = Div(
FieldWithButtons(
Field('q',
placeholder=_('Pesquisar por possíveis autores para '
'o Tipo de Autor selecionado.')),
StrictButton(
_('Filtrar'), css_class='btn-default btn-filtrar-autor',
type='button')),
Field('content_object'),
css_class='hidden',
data_action='create',
data_application='AutorSearch',
data_field='content_object')
row1 = to_row([
('tipo', 4),
('nome', 8),
(content_object, 8),
])
self.helper = FormHelper()
self.helper.layout = SaplFormLayout(row1)
super(AutorForm, self).__init__(*args, **kwargs)
self.fields['content_object'].choices = [('1', 'teste')]
if self.instance and self.instance.content_object:
self.fields['content_object'].choices = [
(self.instance.content_object.pk,
self.instance.content_object)]
def valida_igualdade(self, texto1, texto2, msg):
if texto1 != texto2:
raise ValidationError(msg)
return True
def valida_email_existente(self):
return get_user_model().objects.filter(
email=self.cleaned_data['email']).exists()
def clea(self):
if 'username' not in self.cleaned_data:
raise ValidationError(_('Favor informar o username'))
if ('senha' not in self.cleaned_data or
'senha_confirma' not in self.cleaned_data):
raise ValidationError(_('Favor informar as senhas'))
msg = _('As senhas não conferem.')
self.valida_igualdade(
self.cleaned_data['senha'],
self.cleaned_data['senha_confirma'],
msg)
if ('email' not in self.cleaned_data or
'confirma_email' not in self.cleaned_data):
raise ValidationError(_('Favor informar endereços de email'))
msg = _('Os emails não conferem.')
self.valida_igualdade(
self.cleaned_data['email'],
self.cleaned_data['confirma_email'],
msg)
email_existente = self.valida_email_existente()
if (Autor.objects.filter(
username=self.cleaned_data['username']).exists()):
raise ValidationError(_('Já existe um autor para este usuário'))
if email_existente:
msg = _('Este email já foi cadastrado.')
raise ValidationError(msg)
try:
validate_password(self.cleaned_data['senha'])
except ValidationError as error:
raise ValidationError(error)
try:
get_user_model().objects.get(
username=self.cleaned_data['username'],
email=self.cleaned_data['email'])
except ObjectDoesNotExist:
msg = _('Este nome de usuario não está cadastrado. ' +
'Por favor, cadastre-o no Administrador do ' +
'Sistema antes de adicioná-lo como Autor')
raise ValidationError(msg)
return self.cleaned_data
@transaction.atomic
def sav(self, commit=False):
autor = super(AutorForm, self).save(commit)
u = get_user_model().objects.get(
username=autor.username,
email=autor.email)
u.set_password(self.cleaned_data['senha'])
u.is_active = False
u.save()
autor.user = u
autor.save()
grupo = Group.objects.filter(name='Autor')[0]
u.groups.add(grupo)
return autor
class RelatorioAtasFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {

55
sapl/base/migrations/0022_auto_20161009_1222.py

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-09 15:22
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('contenttypes', '0002_remove_content_type_name'),
('base', '0021_auto_20161006_1019'),
]
operations = [
migrations.CreateModel(
name='Autor',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('object_id', models.PositiveIntegerField(blank=True, default=None, null=True)),
('nome', models.CharField(blank=True, max_length=50, verbose_name='Autor')),
('cargo', models.CharField(blank=True, max_length=50)),
('content_type', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
],
options={
'verbose_name': 'Autor',
'verbose_name_plural': 'Autores',
},
),
migrations.CreateModel(
name='TipoAutor',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('descricao', models.CharField(max_length=50, verbose_name='Descrição')),
('content_type', models.OneToOneField(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType', verbose_name='Modelo do Tipo de Autor')),
],
options={
'verbose_name': 'Tipo de Autor',
'verbose_name_plural': 'Tipos de Autor',
},
),
migrations.AddField(
model_name='autor',
name='tipo',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='base.TipoAutor', verbose_name='Tipo'),
),
migrations.AddField(
model_name='autor',
name='user',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]

25
sapl/base/migrations/0023_auto_20161009_1852.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-09 21:52
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('base', '0022_auto_20161009_1222'),
]
operations = [
migrations.AlterField(
model_name='tipoautor',
name='content_type',
field=models.OneToOneField(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType', verbose_name='Modelagem no SAPL'),
),
migrations.AlterUniqueTogether(
name='autor',
unique_together=set([('content_type', 'object_id')]),
),
]

64
sapl/base/models.py

@ -7,10 +7,11 @@ from django.contrib.contenttypes.models import ContentType
from django.core import exceptions
from django.db import models, router
from django.db.utils import DEFAULT_DB_ALIAS
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _
from sapl.utils import UF, YES_NO_CHOICES, get_settings_auth_user_model
from sapl.utils import UF, YES_NO_CHOICES
TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensivo')),
('R', _('Restritivo')))
@ -132,6 +133,65 @@ class AppConfig(models.Model):
'id': self.id}
class TipoAutor(models.Model):
descricao = models.CharField(max_length=50, verbose_name=_('Descrição'))
content_type = models.OneToOneField(
ContentType,
null=True, default=None,
verbose_name=_('Modelagem no SAPL'))
class Meta:
verbose_name = _('Tipo de Autor')
verbose_name_plural = _('Tipos de Autor')
def __str__(self):
return self.descricao
class Autor(models.Model):
user = models.OneToOneField(get_settings_auth_user_model())
tipo = models.ForeignKey(TipoAutor, verbose_name=_('Tipo do Autor'))
content_type = models.ForeignKey(
ContentType,
blank=True, null=True, default=None)
object_id = models.PositiveIntegerField(
blank=True, null=True, default=None)
content_object = GenericForeignKey('content_type', 'object_id')
nome = models.CharField(
max_length=50, blank=True, verbose_name=_('Nome do Autor'))
cargo = models.CharField(max_length=50, blank=True)
class Meta:
verbose_name = _('Autor')
verbose_name_plural = _('Autores')
unique_together = (('content_type', 'object_id'), )
def __str__(self):
if self.content_object:
return str(self.content_object)
else:
if str(self.cargo):
return _('%(nome)s - %(cargo)s') % {
'nome': self.nome, 'cargo': self.cargo}
else:
return str(self.nome)
"""if str(self.tipo) == 'Parlamentar' and self.parlamentar:
return self.parlamentar.nome_parlamentar
elif str(self.tipo) == 'Comissao' and self.comissao:
return str(self.comissao)
elif str(self.tipo) == 'Partido' and self.partido:
return str(self.partido)
else:
"""
def create_proxy_permissions(
app_config, verbosity=2, interactive=True,
using=DEFAULT_DB_ALIAS, **kwargs):

30
sapl/base/urls.py

@ -3,6 +3,8 @@ from django.contrib.auth import views
from django.contrib.auth.decorators import permission_required
from django.views.generic.base import TemplateView
from sapl.base.views import AutorCrud, TipoAutorCrud
from .apps import AppConfig
from .forms import LoginForm
from .views import (AppConfigCrud, CasaLegislativaCrud, HelpView,
@ -12,23 +14,26 @@ from .views import (AppConfigCrud, CasaLegislativaCrud, HelpView,
RelatorioMateriasTramitacaoView,
RelatorioPresencaSessaoView)
app_name = AppConfig.name
urlpatterns = [
<<<<<<< 6123d2617726dd220c02c2bb3b3c27ed4b136df1
=======
url(r'^sistema/autor/tipo/', include(TipoAutorCrud.get_urls())),
url(r'^sistema/autor/', include(AutorCrud.get_urls())),
>>>>>>> Ref Autor, TipoAutor, cria app api DRF
url(r'^sistema/ajuda/', TemplateView.as_view(template_name='ajuda.html')),
url(r'^sistema/ajuda/(?P<topic>\w+)$', HelpView.as_view(), name='help_topic'),
url(r'^sistema/ajuda/(?P<topic>\w+)$',
HelpView.as_view(), name='help_topic'),
url(r'^sistema/ajuda/', TemplateView.as_view(template_name='ajuda/index.html'),
name='help_base'),
url(r'^sistema/casa-legislativa/', include(CasaLegislativaCrud.get_urls()),
name="casa_legislativa"),
url(r'^sistema/app-config/', include(AppConfigCrud.get_urls())),
url(r'^login/$', views.login, {
'template_name': 'base/login.html', 'authentication_form': LoginForm},
name='login'),
url(r'^logout/$', views.logout, {'next_page': '/login'}, name='logout'),
# TODO mover estas telas para a app 'relatorios'
url(r'^sistema/relatorios/$', TemplateView.as_view(
template_name='base/relatorios_list.html')),
@ -50,8 +55,21 @@ urlpatterns = [
RelatorioAtasView.as_view(),
name='atas'),
<<<<<<< 6123d2617726dd220c02c2bb3b3c27ed4b136df1
=======
# todos os sublink s de sistema devem vir acima deste
>>>>>>> Ref Autor, TipoAutor, cria app api DRF
url(r'^sistema/', permission_required('base.view_tabelas_auxiliares')
(TemplateView.as_view(template_name='sistema.html'))),
<<<<<<< 6123d2617726dd220c02c2bb3b3c27ed4b136df1
=======
url(r'^login/$', views.login, {
'template_name': 'base/login.html', 'authentication_form': LoginForm},
name='login'),
url(r'^logout/$', views.logout, {'next_page': '/login'}, name='logout'),
>>>>>>> Ref Autor, TipoAutor, cria app api DRF
]

120
sapl/base/views.py

@ -1,16 +1,28 @@
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.tokens import default_token_generator
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from django.db.models import Count, Q
from django.http import HttpResponseRedirect
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateView
from django_filters.views import FilterView
from sapl.base.forms import AutorForm, TipoAutorForm
from sapl.base.models import TipoAutor, Autor
from sapl.crispy_layout_mixin import to_row, SaplFormLayout, form_actions
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 autor_label, autor_modal
from .forms import (CasaLegislativaForm, ConfiguracoesAppForm,
RelatorioAtasFilterSet,
@ -26,6 +38,114 @@ def get_casalegislativa():
return CasaLegislativa.objects.first()
def montar_row_autor(name):
autor_row = to_row(
[(name, 0),
(Button('pesquisar',
'Pesquisar Autor',
css_class='btn btn-primary btn-sm'), 2),
(Button('limpar',
'Limpar Autor',
css_class='btn btn-primary btn-sm'), 10)])
return autor_row
def montar_helper_autor(self):
autor_row = montar_row_autor('nome')
self.helper = FormHelper()
self.helper.layout = SaplFormLayout(*self.get_layout())
# Adiciona o novo campo 'autor' e mecanismo de busca
self.helper.layout[0][0].append(HTML(autor_label))
self.helper.layout[0][0].append(HTML(autor_modal))
self.helper.layout[0][1] = autor_row
# Adiciona espaço entre o novo campo e os botões
# self.helper.layout[0][4][1].append(HTML('<br /><br />'))
# Remove botões que estão fora do form
self.helper.layout[1].pop()
# Adiciona novos botões dentro do form
self.helper.layout[0][4][0].insert(2, form_actions(more=[
HTML('<a href="{{ view.cancel_url }}"'
' class="btn btn-inverse">Cancelar</a>')]))
class TipoAutorCrud(CrudAux):
model = TipoAutor
help_path = 'tipo-autor'
class BaseMixin(CrudAux.BaseMixin):
list_field_names = ['descricao', 'content_type']
form_class = TipoAutorForm
class AutorCrud(CrudAux):
model = Autor
help_path = 'autor'
class BaseMixin(CrudAux.BaseMixin):
list_field_names = ['tipo', 'nome', 'user__username']
class UpdateView(CrudAux.UpdateView):
layout_key = None
form_class = AutorForm
def __init__(self, *args, **kwargs):
# montar_helper_autor(self)
super(CrudAux.UpdateView, self).__init__(*args, **kwargs)
def get_context_data(self, **kwargs):
context = super(
CrudAux.UpdateView, self).get_context_data(**kwargs)
#context['helper'] = self.helper
return context
class CreateView(CrudAux.CreateView):
form_class = AutorForm
layout_key = None
"""def __init__(self, *args, **kwargs):
montar_helper_autor(self)
super(CrudAux.CreateView, self).__init__(*args, **kwargs)"""
"""def get_context_data(self, **kwargs):
context = super(
CrudAux.CreateView, self).get_context_data(**kwargs)
context['helper'] = self.helper
return context"""
"""def get_success_url(self):
pk_autor = Autor.objects.get(
email=self.request.POST.get('email')).id
kwargs = {}
user = get_user_model().objects.get(
email=self.request.POST.get('email'))
kwargs['token'] = default_token_generator.make_token(user)
kwargs['uidb64'] = urlsafe_base64_encode(force_bytes(user.pk))
assunto = "SAPL - Confirmação de Conta"
full_url = self.request.get_raw_uri()
url_base = full_url[:full_url.find('sistema') - 1]
mensagem = ("Este e-mail foi utilizado para fazer cadastro no " +
"SAPL com o perfil de Autor. Agora você pode " +
"criar/editar/enviar Proposições.\n" +
"Seu nome de usuário é: " +
self.request.POST['username'] + "\n"
"Caso você não tenha feito este cadastro, por favor " +
"ignore esta mensagem. Caso tenha, clique " +
"no link abaixo\n" + url_base +
reverse('sapl.materia:confirmar_email', kwargs=kwargs))
remetente = settings.EMAIL_SEND_USER
destinatario = [self.request.POST.get('email')]
send_mail(assunto, mensagem, remetente, destinatario,
fail_silently=False)
return reverse('sapl.base:autor_detail',
kwargs={'pk': pk_autor})"""
class RelatorioAtasView(FilterView):
model = SessaoPlenaria
filterset_class = RelatorioAtasFilterSet

4
sapl/comissoes/models.py

@ -1,8 +1,10 @@
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
from sapl.base.models import Autor
from sapl.parlamentares.models import Parlamentar
from sapl.utils import YES_NO_CHOICES
@ -79,6 +81,8 @@ class Comissao(models.Model):
choices=YES_NO_CHOICES,
verbose_name=_('Comissão Ativa?'))
autor = GenericRelation(Autor)
class Meta:
verbose_name = _('Comissão')
verbose_name_plural = _('Comissões')

7
sapl/crispy_layout_mixin.py

@ -1,12 +1,12 @@
from math import ceil
import rtyaml
from crispy_forms.bootstrap import FormActions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit
from django import template
from django.utils import formats
from django.utils.translation import ugettext as _
import rtyaml
def heads_and_tails(list_of_lists):
@ -138,8 +138,9 @@ class CrispyLayoutFormMixin:
# simply return None if there is no get_form on super
pass
else:
form.helper = FormHelper()
form.helper.layout = SaplFormLayout(*self.get_layout())
if self.layout_key:
form.helper = FormHelper()
form.helper.layout = SaplFormLayout(*self.get_layout())
return form
@property

125
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
@ -508,7 +508,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
'data_apresentacao',
'data_publicacao',
'autoria__autor__tipo',
'autoria__autor__partido',
#'autoria__autor__partido',
'relatoria__parlamentar_id',
'local_origem_externa',
'tramitacao__unidade_tramitacao_destino',
@ -544,7 +544,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['autoria__autor__tipo'].label = 'Tipo de Autor'
self.filters['autoria__autor__partido'].label = 'Partido do Autor'
# self.filters['autoria__autor__partido'].label = 'Partido do Autor'
self.filters['relatoria__parlamentar_id'].label = 'Relatoria'
row1 = to_row(
@ -566,7 +566,8 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
css_class='btn btn-primary btn-sm'), 10)])
row5 = to_row(
[('autoria__autor__tipo', 6),
('autoria__autor__partido', 6)])
# ('autoria__autor__partido', 6)
])
row6 = to_row(
[('relatoria__parlamentar_id', 6),
('local_origem_externa', 6)])
@ -666,122 +667,6 @@ class AutoriaForm(ModelForm):
return self.cleaned_data
class AutorForm(ModelForm):
senha = forms.CharField(
max_length=20,
label=_('Senha'),
required=True,
widget=forms.PasswordInput())
senha_confirma = forms.CharField(
max_length=20,
label=_('Confirmar Senha'),
required=True,
widget=forms.PasswordInput())
confirma_email = forms.EmailField(
required=True,
label=_('Confirmar Email'))
username = forms.CharField(
required=True,
max_length=50
)
class Meta:
model = Autor
fields = ['username',
'senha',
'email',
'nome',
'tipo',
'cargo']
widgets = {'nome': forms.HiddenInput()}
def valida_igualdade(self, texto1, texto2, msg):
if texto1 != texto2:
raise ValidationError(msg)
return True
def valida_email_existente(self):
return get_user_model().objects.filter(
email=self.cleaned_data['email']).exists()
def clean(self):
if 'username' not in self.cleaned_data:
raise ValidationError(_('Favor informar o username'))
if ('senha' not in self.cleaned_data or
'senha_confirma' not in self.cleaned_data):
raise ValidationError(_('Favor informar as senhas'))
msg = _('As senhas não conferem.')
self.valida_igualdade(
self.cleaned_data['senha'],
self.cleaned_data['senha_confirma'],
msg)
if ('email' not in self.cleaned_data or
'confirma_email' not in self.cleaned_data):
raise ValidationError(_('Favor informar endereços de email'))
msg = _('Os emails não conferem.')
self.valida_igualdade(
self.cleaned_data['email'],
self.cleaned_data['confirma_email'],
msg)
email_existente = self.valida_email_existente()
if (Autor.objects.filter(
username=self.cleaned_data['username']).exists()):
raise ValidationError(_('Já existe um autor para este usuário'))
if email_existente:
msg = _('Este email já foi cadastrado.')
raise ValidationError(msg)
try:
validate_password(self.cleaned_data['senha'])
except ValidationError as error:
raise ValidationError(error)
try:
User.objects.get(
username=self.cleaned_data['username'],
email=self.cleaned_data['email'])
except ObjectDoesNotExist:
msg = _('Este nome de usuario não está cadastrado. ' +
'Por favor, cadastre-o no Administrador do ' +
'Sistema antes de adicioná-lo como Autor')
raise ValidationError(msg)
return self.cleaned_data
@transaction.atomic
def save(self, commit=False):
autor = super(AutorForm, self).save(commit)
u = User.objects.get(
username=autor.username,
email=autor.email)
u.set_password(self.cleaned_data['senha'])
u.is_active = False
u.save()
autor.user = u
autor.save()
grupo = Group.objects.filter(name='Autor')[0]
u.groups.add(grupo)
return autor
class AcessorioEmLoteFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {

53
sapl/materia/migrations/0054_auto_20161009_1222.py

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-09 15:22
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0003_auto_20161009_1222'),
('materia', '0053_auto_20161004_1854'),
]
operations = [
migrations.RemoveField(
model_name='autor',
name='comissao',
),
migrations.RemoveField(
model_name='autor',
name='parlamentar',
),
migrations.RemoveField(
model_name='autor',
name='partido',
),
migrations.RemoveField(
model_name='autor',
name='tipo',
),
migrations.RemoveField(
model_name='autor',
name='user',
),
migrations.AlterField(
model_name='autoria',
name='autor',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='base.Autor', verbose_name='Autor'),
),
migrations.AlterField(
model_name='proposicao',
name='autor',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='base.Autor'),
),
migrations.DeleteModel(
name='Autor',
),
migrations.DeleteModel(
name='TipoAutor',
),
]

32
sapl/materia/migrations/0055_auto_20161009_1418.py

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-09 17:18
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('base', '0022_auto_20161009_1222'),
('materia', '0054_auto_20161009_1222'),
]
operations = [
migrations.AddField(
model_name='materialegislativa',
name='autores',
field=models.ManyToManyField(through='materia.Autoria', to='base.Autor'),
),
migrations.AlterField(
model_name='autoria',
name='autor',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='base.Autor', verbose_name='Autor'),
),
migrations.AlterField(
model_name='autoria',
name='materia',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa', verbose_name='Matéria Legislativa'),
),
]

85
sapl/materia/models.py

@ -3,6 +3,7 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
from sapl.base.models import Autor
from sapl.comissoes.models import Comissao
from sapl.parlamentares.models import Parlamentar, Partido
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
@ -143,6 +144,12 @@ class MateriaLegislativa(models.Model):
verbose_name=_('Texto Original (PDF)'),
validators=[restringe_tipos_de_arquivo_txt])
autores = models.ManyToManyField(
Autor,
through='Autoria',
through_fields=('materia', 'autor'),
symmetrical=False,)
class Meta:
verbose_name = _('Matéria Legislativa')
verbose_name_plural = _('Matérias Legislativas')
@ -153,6 +160,22 @@ class MateriaLegislativa(models.Model):
'tipo': self.tipo, 'numero': self.numero, 'ano': self.ano}
class Autoria(models.Model):
autor = models.ForeignKey(Autor, verbose_name=_('Autor'))
materia = models.ForeignKey(
MateriaLegislativa, verbose_name=_('Matéria Legislativa'))
primeiro_autor = models.BooleanField(verbose_name=_('Primeiro Autor'),
choices=YES_NO_CHOICES)
class Meta:
verbose_name = _('Autoria')
verbose_name_plural = _('Autorias')
def __str__(self):
return _('%(autor)s - %(materia)s') % {
'autor': self.autor, 'materia': self.materia}
class AcompanhamentoMateria(models.Model):
usuario = models.CharField(max_length=50)
materia = models.ForeignKey(MateriaLegislativa)
@ -204,68 +227,6 @@ class AssuntoMateria(models.Model):
return self.assunto
class TipoAutor(models.Model):
descricao = models.CharField(max_length=50, verbose_name=_('Descrição'))
class Meta:
verbose_name = _('Tipo de Autor')
verbose_name_plural = _('Tipos de Autor')
def __str__(self):
return self.descricao
class Autor(models.Model):
user = models.ForeignKey(
get_settings_auth_user_model(), blank=True, null=True)
partido = models.ForeignKey(Partido, blank=True, null=True)
comissao = models.ForeignKey(Comissao, blank=True, null=True)
parlamentar = models.ForeignKey(Parlamentar, blank=True, null=True)
tipo = models.ForeignKey(TipoAutor, verbose_name=_('Tipo'))
nome = models.CharField(
max_length=50, blank=True, verbose_name=_('Autor'))
cargo = models.CharField(max_length=50, blank=True)
username = models.CharField(
max_length=50,
blank=True,
verbose_name=_('Nome de Usuário'))
email = models.EmailField(
verbose_name=_('Email'))
class Meta:
verbose_name = _('Autor')
verbose_name_plural = _('Autores')
def __str__(self):
if str(self.tipo) == 'Parlamentar' and self.parlamentar:
return self.parlamentar.nome_parlamentar
elif str(self.tipo) == 'Comissao' and self.comissao:
return str(self.comissao)
elif str(self.tipo) == 'Partido' and self.partido:
return str(self.partido)
else:
if str(self.cargo):
return _('%(nome)s - %(cargo)s') % {
'nome': self.nome, 'cargo': self.cargo}
else:
return str(self.nome)
class Autoria(models.Model):
autor = models.ForeignKey(Autor, verbose_name=_('Autor'))
materia = models.ForeignKey(MateriaLegislativa)
primeiro_autor = models.BooleanField(verbose_name=_('Primeiro Autor'),
choices=YES_NO_CHOICES)
class Meta:
verbose_name = _('Autoria')
verbose_name_plural = _('Autorias')
def __str__(self):
return _('%(autor)s - %(materia)s') % {
'autor': self.autor, 'materia': self.materia}
class DespachoInicial(models.Model):
# TODO M2M?
materia = models.ForeignKey(MateriaLegislativa)

8
sapl/materia/urls.py

@ -3,7 +3,7 @@ from django.conf.urls import include, url
from sapl.materia.views import (AcompanhamentoConfirmarView,
AcompanhamentoExcluirView,
AcompanhamentoMateriaView, AnexadaCrud,
AutorCrud, AutoriaCrud, ConfirmarEmailView,
AutoriaCrud, ConfirmarEmailView,
ConfirmarProposicao, DespachoInicialCrud,
DocumentoAcessorioCrud,
DocumentoAcessorioEmLoteView,
@ -15,7 +15,7 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
ProposicaoRecebida, ProposicaoTaView,
ReceberProposicao, ReciboProposicaoView,
RegimeTramitacaoCrud, RelatoriaCrud,
StatusTramitacaoCrud, TipoAutorCrud,
StatusTramitacaoCrud,
TipoDocumentoCrud, TipoFimRelatoriaCrud,
TipoMateriaCrud, TipoProposicaoCrud,
TramitacaoCrud, TramitacaoEmLoteView,
@ -78,6 +78,8 @@ urlpatterns_proposicao = [
name='proposicao-devolvida'),
url(r'^proposicao/confirmar/(?P<pk>\d+)', ConfirmarProposicao.as_view(),
name='proposicao-confirmar'),
url(r'^sistema/proposicao/tipo/',
include(TipoProposicaoCrud.get_urls())),
url(r'^proposicao/(?P<pk>[0-9]+)/ta$',
ProposicaoTaView.as_view(), name='proposicao_ta'),
@ -89,7 +91,6 @@ urlpatterns_sistema = [
url(r'^sistema/materia/tipo/', include(TipoMateriaCrud.get_urls())),
url(r'^sistema/materia/regime-tramitacao/',
include(RegimeTramitacaoCrud.get_urls())),
url(r'^sistema/materia/tipo-autor/', include(TipoAutorCrud.get_urls())),
url(r'^sistema/materia/tipo-documento/',
include(TipoDocumentoCrud.get_urls())),
url(r'^sistema/materia/tipo-fim-relatoria/',
@ -97,7 +98,6 @@ urlpatterns_sistema = [
url(r'^sistema/materia/unidade-tramitacao/',
include(UnidadeTramitacaoCrud.get_urls())),
url(r'^sistema/materia/origem/', include(OrigemCrud.get_urls())),
url(r'^sistema/materia/autor/', include(AutorCrud.get_urls())),
url(r'^sistema/materia/status-tramitacao/',
include(StatusTramitacaoCrud.get_urls())),
url(r'^sistema/materia/orgao/', include(OrgaoCrud.get_urls())),

118
sapl/materia/views.py

@ -24,7 +24,8 @@ from django.views.generic import CreateView, ListView, TemplateView, UpdateView
from django.views.generic.base import RedirectView
from django_filters.views import FilterView
from sapl.base.models import AppConfig, CasaLegislativa
from sapl.base.models import AppConfig, CasaLegislativa, Autor, TipoAutor
from sapl.base.views import montar_row_autor
from sapl.compilacao.views import IntegracaoTaView
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
from sapl.crud.base import (ACTION_CREATE, ACTION_DELETE, ACTION_DETAIL,
@ -40,17 +41,17 @@ from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
permissoes_protocoloadm, permission_required_for_app)
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AutorForm, ConfirmarProposicaoForm, DocumentoAcessorioForm,
ConfirmarProposicaoForm, DocumentoAcessorioForm,
MateriaLegislativaFilterSet,
PrimeiraTramitacaoEmLoteFilterSet, ProposicaoForm,
ReceberProposicaoForm, TramitacaoEmLoteFilterSet,
filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status,
filtra_tramitacao_status)
from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria,
from .models import (AcompanhamentoMateria, Anexada, Autoria,
DespachoInicial, DocumentoAcessorio, MateriaLegislativa,
Numeracao, Orgao, Origem, Proposicao, RegimeTramitacao,
Relatoria, StatusTramitacao, TipoAutor, TipoDocumento,
Relatoria, StatusTramitacao, TipoDocumento,
TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao,
Tramitacao, UnidadeTramitacao)
@ -69,20 +70,17 @@ TipoDocumentoCrud = CrudAux.build(
TipoFimRelatoriaCrud = CrudAux.build(
TipoFimRelatoria, 'fim_relatoria')
TipoAutorCrud = CrudAux.build(
TipoAutor, 'regime_tramitacao')
class MateriaTaView(IntegracaoTaView):
model = MateriaLegislativa
model_type_foreignkey = TipoMateriaLegislativa
"""
Para manter a app compilacao isolada das outras aplicações,
este get foi implementado para tratar uma prerrogativa externa
de usuário.
"""
def get(self, request, *args, **kwargs):
"""
Para manter a app compilacao isolada das outras aplicações,
este get foi implementado para tratar uma prerrogativa externa
de usuário.
"""
if AppConfig.attr('texto_articulado_materia'):
return IntegracaoTaView.get(self, request, *args, **kwargs)
else:
@ -118,89 +116,6 @@ def recuperar_materia(request):
return response
def montar_helper_autor(self):
autor_row = montar_row_autor('nome')
self.helper = FormHelper()
self.helper.layout = SaplFormLayout(*self.get_layout())
# Adiciona o novo campo 'autor' e mecanismo de busca
self.helper.layout[0][0].append(HTML(autor_label))
self.helper.layout[0][0].append(HTML(autor_modal))
self.helper.layout[0][1] = autor_row
# Adiciona espaço entre o novo campo e os botões
# self.helper.layout[0][4][1].append(HTML('<br /><br />'))
# Remove botões que estão fora do form
self.helper.layout[1].pop()
# Adiciona novos botões dentro do form
self.helper.layout[0][4][0].insert(2, form_actions(more=[
HTML('<a href="{{ view.cancel_url }}"'
' class="btn btn-inverse">Cancelar</a>')]))
class AutorCrud(CrudAux):
model = Autor
help_path = 'autor'
class BaseMixin(CrudAux.BaseMixin):
list_field_names = ['tipo', 'nome']
class UpdateView(CrudAux.UpdateView):
layout_key = 'AutorCreate'
def __init__(self, *args, **kwargs):
montar_helper_autor(self)
super(UpdateView, self).__init__(*args, **kwargs)
def get_context_data(self, **kwargs):
context = super(UpdateView, self).get_context_data(**kwargs)
context['helper'] = self.helper
return context
class CreateView(CrudAux.CreateView):
form_class = AutorForm
layout_key = 'AutorCreate'
def __init__(self, *args, **kwargs):
montar_helper_autor(self)
super(CreateView, self).__init__(*args, **kwargs)
def get_context_data(self, **kwargs):
context = super(CreateView, self).get_context_data(**kwargs)
context['helper'] = self.helper
return context
def get_success_url(self):
pk_autor = Autor.objects.get(
email=self.request.POST.get('email')).id
kwargs = {}
user = get_user_model().objects.get(
email=self.request.POST.get('email'))
kwargs['token'] = default_token_generator.make_token(user)
kwargs['uidb64'] = urlsafe_base64_encode(force_bytes(user.pk))
assunto = "SAPL - Confirmação de Conta"
full_url = self.request.get_raw_uri()
url_base = full_url[:full_url.find('sistema') - 1]
mensagem = ("Este e-mail foi utilizado para fazer cadastro no " +
"SAPL com o perfil de Autor. Agora você pode " +
"criar/editar/enviar Proposições.\n" +
"Seu nome de usuário é: " +
self.request.POST['username'] + "\n"
"Caso você não tenha feito este cadastro, por favor " +
"ignore esta mensagem. Caso tenha, clique " +
"no link abaixo\n" + url_base +
reverse('sapl.materia:confirmar_email', kwargs=kwargs))
remetente = settings.EMAIL_SEND_USER
destinatario = [self.request.POST.get('email')]
send_mail(assunto, mensagem, remetente, destinatario,
fail_silently=False)
return reverse('sapl.materia:autor_detail',
kwargs={'pk': pk_autor})
class ConfirmarEmailView(TemplateView):
template_name = "confirma_email.html"
@ -661,19 +576,6 @@ class TramitacaoCrud(MasterDetailCrud):
return HttpResponseRedirect(url)
def montar_row_autor(name):
autor_row = to_row(
[(name, 0),
(Button('pesquisar',
'Pesquisar Autor',
css_class='btn btn-primary btn-sm'), 2),
(Button('limpar',
'Limpar Autor',
css_class='btn btn-primary btn-sm'), 10)])
return autor_row
def montar_helper_documento_acessorio(self):
autor_row = montar_row_autor('autor')
self.helper = FormHelper()

4
sapl/parlamentares/models.py

@ -1,9 +1,11 @@
from datetime import datetime
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
from sapl.base.models import Autor
from sapl.utils import (INDICADOR_AFASTAMENTO, UF, YES_NO_CHOICES,
intervalos_tem_intersecao,
restringe_tipos_de_arquivo_img)
@ -262,6 +264,8 @@ class Parlamentar(models.Model):
verbose_name=_('Fotografia'),
validators=[restringe_tipos_de_arquivo_img])
autor = GenericRelation(Autor)
class Meta:
verbose_name = _('Parlamentar')
verbose_name_plural = _('Parlamentares')

26
sapl/protocoloadm/migrations/0003_auto_20161009_1222.py

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-09 15:22
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0002_delete_tipoinstituicao'),
]
operations = [
migrations.AlterField(
model_name='documentoadministrativo',
name='autor',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='base.Autor'),
),
migrations.AlterField(
model_name='protocolo',
name='autor',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='base.Autor'),
),
]

33
sapl/rest_pagination.py

@ -0,0 +1,33 @@
from django.core.paginator import EmptyPage
from rest_framework import pagination
from rest_framework.response import Response
class StandardPagination(pagination.PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
max_page_size = 50
def get_paginated_response(self, data):
try:
previous_page_number = self.page.previous_page_number()
except EmptyPage:
previous_page_number = None
try:
next_page_number = self.page.next_page_number()
except EmptyPage:
next_page_number = None
return Response({
'pagination': {
'previous_page': previous_page_number,
'next_page': next_page_number,
'start_index': self.page.start_index(),
'end_index': self.page.end_index(),
'total_entries': self.page.paginator.count,
'total_pages': self.page.paginator.num_pages,
'page': self.page.number,
},
'models': data,
})

9
sapl/sessao/forms.py

@ -1,12 +1,12 @@
from datetime import datetime
import django_filters
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Fieldset, Layout
from django import forms
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.crispy_layout_mixin import form_actions, to_row
from sapl.materia.forms import MateriaLegislativaFilterSet
@ -212,7 +212,7 @@ class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet):
'data_apresentacao',
'data_publicacao',
'autoria__autor__tipo',
'autoria__autor__partido',
#'autoria__autor__partido',
'relatoria__parlamentar_id',
'local_origem_externa',
'em_tramitacao',
@ -231,7 +231,7 @@ class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet):
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['autoria__autor__tipo'].label = 'Tipo de Autor'
self.filters['autoria__autor__partido'].label = 'Partido do Autor'
#self.filters['autoria__autor__partido'].label = 'Partido do Autor'
self.filters['relatoria__parlamentar_id'].label = 'Relatoria'
row1 = to_row(
@ -253,7 +253,8 @@ class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet):
css_class='btn btn-primary btn-sm'), 10)])
row5 = to_row(
[('autoria__autor__tipo', 6),
('autoria__autor__partido', 6)])
#('autoria__autor__partido', 6)
])
row6 = to_row(
[('relatoria__parlamentar_id', 6),
('local_origem_externa', 6)])

1
sapl/sessao/urls.py

@ -30,6 +30,7 @@ from .apps import AppConfig
app_name = AppConfig.name
urlpatterns = [
url(r'^sessao/', include(SessaoCrud.get_urls() + OradorCrud.get_urls() +
OradorExpedienteCrud.get_urls() +

24
sapl/settings.py

@ -48,6 +48,7 @@ SAPL_APPS = (
'sapl.painel',
'sapl.protocoloadm',
'sapl.compilacao',
'sapl.api'
)
INSTALLED_APPS = (
@ -86,6 +87,29 @@ MIDDLEWARE_CLASSES = (
'django.middleware.security.SecurityMiddleware',
)
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES": (
"rest_framework.renderers.JSONRenderer",
# "rest_framework.renderers.BrowsableAPIRenderer",
),
"DEFAULT_PARSER_CLASSES": (
"rest_framework.parsers.JSONParser",
),
"DEFAULT_PERMISSION_CLASSES": (
"rest_framework.permissions.IsAuthenticated",
),
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework.authentication.SessionAuthentication",
),
"DEFAULT_PAGINATION_CLASS": "sapl.rest_pagination.StandardPagination",
"DEFAULT_FILTER_BACKENDS": (
"rest_framework.filters.SearchFilter",
"rest_framework.filters.DjangoFilterBackend",
),
}
ROOT_URLCONF = 'sapl.urls'
TEMPLATES = [

1
sapl/static/styles/app.scss

@ -88,6 +88,7 @@ h6, .h6 {
}
}
// #### CRUD DETAIL ########################################
p.control-label {
font-weight: bold;

61
sapl/templates/base/autor_form.html

@ -0,0 +1,61 @@
{% extends "crud/form.html" %}
{% load i18n %}
{% block extra_js %}
<script type="text/javascript">
$(document).ready(function(){
var active = function(str) {
if (str == 'nome') {
$('#id_q').val('');
$('#div_id_nome').removeClass('hidden');
$("[data-application='AutorSearch']").addClass('hidden');
$("#div_id_content_object .controls").html('');
}
else {
$('#id_nome').val('');
$('#div_id_nome').addClass('hidden');
$("[data-application='AutorSearch']").removeClass('hidden');
}
}
var update_search = function(pk) {
var q = $('#id_q').val();
var url = '{% url 'sapl.api:autores_possiveis_pelo_tipo' 0 %}'
url = url.replace('0', pk);
var formData = {
'q' : q,
'format' : 'json',
}
$.get(url, formData).done(function(data) {
var radios = $("#div_id_content_object .controls").html('');
active('pesquisa');
data.forEach(function (val, index) {
var html_radio = '<div class="radio"><label><input type="radio" name="content_object" id="id_content_object_'+index+'" value="'+val.pk+'">'+val.display+'</label></div>';
radios.append(html_radio);
});
}).fail(function(data) {
active('nome');
});
}
$('#id_tipo').change(function(event) {
if (event.target.selectedIndex == 0) {
$('#id_nome, #id_q').val('');
active('nome');
}
else {
var pk = this[event.target.selectedIndex].value;
update_search(pk);
}
});
$('.btn-filtrar-autor').click(function(event) {
var pk = $('#id_tipo').val();
update_search(pk);
});
});
</script>
{% endblock %}

13
sapl/templates/base/layouts.yaml

@ -15,3 +15,16 @@ AppConfig:
- documentos_administrativos sequencia_numeracao painel_aberto
{% trans 'Textos Articulados' %}:
- texto_articulado_proposicao texto_articulado_materia texto_articulado_norma
TipoAutor:
{% trans 'Tipo Autor' %}:
- content_type descricao:7
Autor:
{% trans 'Autor' %}:
- tipo:3 nome
- username:6 cargo
AutorCreate:
{% trans 'Cadastro de Usuários Autores' %}:
- tipo:3 search_autor

20
sapl/templates/base/tipoautor_form.html

@ -0,0 +1,20 @@
{% extends "crud/form.html" %}
{% load i18n %}
{% block extra_js %}
<script type="text/javascript">
$(document).ready(function(){
$('#id_content_type').change(function(event) {
if (event.target.selectedIndex == 0)
$('#id_descricao').val('');
else
$('#id_descricao').val(this[event.target.selectedIndex].text);
});
});
</script>
{% endblock %}

17
sapl/templates/materia/layouts.yaml

@ -47,23 +47,6 @@ AnexadaDetail:
- materia_anexada
- data_anexacao data_desanexacao
TipoAutor:
{% trans 'Tipo Autor' %}:
- descricao
Autor:
{% trans 'Autor' %}:
- tipo:3 nome
- username:6 cargo
AutorCreate:
Autor:
- tipo
- nome
- username:4 senha:4 senha_confirma:4
- email:6 confirma_email:6
- cargo
Autoria:
{% trans 'Autoria' %}:
- autor primeiro_autor

7
sapl/templates/sistema.html

@ -3,10 +3,12 @@
{% block base_content %}
<h2>Configuração Inicial</h2>
<h2>Configuração Gerais</h2>
<div class="row">
<div class="col-md-6"><a href="{% url 'sapl.base:casalegislativa_list' %}" class="btn btn-link">Casa Legislativa</a></div>
<div class="col-md-6"><a href="{% url 'sapl.base:autor_list' %}" class="btn btn-link">Autor</a></div>
<div class="col-md-6"><a href="{% url 'sapl.base:appconfig_list' %}" class="btn btn-link">Configurações da Aplicação</a></div>
<div class="col-md-6"><a href="{% url 'sapl.base:tipoautor_list' %}" class="btn btn-link">Tipo de Autor</a></div>
</div>
<hr />
@ -49,7 +51,6 @@
<h2>Módulo Proposições</h2>
<div class="row">
<div class="col-md-6"><a href="{% url 'sapl.materia:tipoproposicao_list' %}" class="btn btn-link">Tipo de Proposição</a></div>
<div class="col-md-6"><a href="{% url 'sapl.materia:autor_list' %}" class="btn btn-link">Autor</a></div>
</div>
<hr />
@ -57,12 +58,10 @@
<div class="row">
<div class="col-md-6"><a href="{% url 'sapl.materia:tipomaterialegislativa_list' %}" class="btn btn-link">Tipo de Matéria Legislativa</a></div>
<div class="col-md-6"><a href="{% url 'sapl.materia:regimetramitacao_list' %}" class="btn btn-link">Regime de Tramitação</a></div>
<div class="col-md-6"><a href="{% url 'sapl.materia:tipoautor_list' %}" class="btn btn-link">Tipo de Autor</a></div>
<div class="col-md-6"><a href="{% url 'sapl.materia:tipodocumento_list' %}" class="btn btn-link">Tipo de Documento</a></div>
<div class="col-md-6"><a href="{% url 'sapl.materia:tipofimrelatoria_list' %}" class="btn btn-link">Tipo de fim de Relatoria</a></div>
<div class="col-md-6"><a href="{% url 'sapl.materia:unidadetramitacao_list' %}" class="btn btn-link">Unidade de Tramitação</a></div>
<div class="col-md-6"><a href="{% url 'sapl.materia:origem_list' %}" class="btn btn-link">Origem</a></div>
<div class="col-md-6"><a href="{% url 'sapl.materia:autor_list' %}" class="btn btn-link">Autor</a></div>
<div class="col-md-6"><a href="{% url 'sapl.materia:statustramitacao_list' %}" class="btn btn-link">Status da Tramitação</a></div>
<div class="col-md-6"><a href="{% url 'sapl.materia:orgao_list' %}" class="btn btn-link">Órgão</a></div>
</div>

3
sapl/urls.py

@ -31,6 +31,7 @@ import sapl.parlamentares.urls
import sapl.protocoloadm.urls
import sapl.relatorios.urls
import sapl.sessao.urls
import sapl.api.urls
urlpatterns = [
url(r'^$', TemplateView.as_view(template_name='index.html')),
@ -50,6 +51,8 @@ urlpatterns = [
# must come at the end
# so that base /sistema/ url doesn't capture its children
url(r'', include(sapl.base.urls)),
url(r'^api/', include(sapl.api.urls)),
]

Loading…
Cancel
Save