Browse Source

Conc refatoração no Cada de Autor e Tipos de Autor

pull/739/head
LeandroRoberto 8 years ago
parent
commit
2a4141bdb2
  1. 16
      sapl/api/serializers.py
  2. 4
      sapl/api/urls.py
  3. 10
      sapl/api/views.py
  4. 305
      sapl/base/forms.py
  5. 20
      sapl/base/migrations/0025_tipoautor_cria_usuario.py
  6. 19
      sapl/base/migrations/0026_remove_tipoautor_cria_usuario.py
  7. 22
      sapl/base/migrations/0027_auto_20161011_1624.py
  8. 7
      sapl/base/models.py
  9. 15
      sapl/base/urls.py
  10. 169
      sapl/base/views.py
  11. 1
      sapl/comissoes/models.py
  12. 2
      sapl/crispy_layout_mixin.py
  13. 13
      sapl/crud/base.py
  14. 9
      sapl/materia/forms.py
  15. 16
      sapl/materia/migrations/0056_merge.py
  16. 2
      sapl/materia/models.py
  17. 10
      sapl/materia/urls.py
  18. 30
      sapl/materia/views.py
  19. 5
      sapl/parlamentares/models.py
  20. 1
      sapl/protocoloadm/forms.py
  21. 8
      sapl/sessao/forms.py
  22. 7
      sapl/sessao/urls.py
  23. 10
      sapl/settings.py
  24. 1
      sapl/templates/base.html
  25. 28
      sapl/templates/base/autor_form.html
  26. 4
      sapl/templates/base/layouts.yaml
  27. 14
      sapl/templates/bootstrap3/layout/checkboxselectmultiple.html
  28. 19
      sapl/templates/bootstrap3/layout/radioselect.html
  29. 6
      sapl/test_urls.py
  30. 2
      sapl/urls.py
  31. 41
      sapl/utils.py

16
sapl/api/serializers.py

@ -1,8 +1,5 @@
from rest_framework import serializers from rest_framework import serializers
from sapl.comissoes.models import Comissao
from sapl.parlamentares.models import Parlamentar
class ChoiceSerializer(serializers.Serializer): class ChoiceSerializer(serializers.Serializer):
pk = serializers.IntegerField() pk = serializers.IntegerField()
@ -10,16 +7,3 @@ class ChoiceSerializer(serializers.Serializer):
def get_display(self, obj): def get_display(self, obj):
return str(obj) return str(obj)
"""
class ModelChoiceParlamentarSerializer(ModelChoiceSerializer):
class Meta:
model = Parlamentar
class ModelChoiceComissaoSerializer(ModelChoiceSerializer):
class Meta:
model = Comissao
"""

4
sapl/api/urls.py

@ -1,11 +1,9 @@
from django.conf.urls import include, url from django.conf.urls import url
from rest_framework.routers import DefaultRouter
from sapl.api.views import TipoAutorContentOfModelContentTypeView from sapl.api.views import TipoAutorContentOfModelContentTypeView
from .apps import AppConfig from .apps import AppConfig
app_name = AppConfig.name app_name = AppConfig.name

10
sapl/api/views.py

@ -1,10 +1,7 @@
from django.db.models import Q from django.db.models import Q
from django.http import Http404 from django.http import Http404
from rest_framework import mixins, viewsets from rest_framework.generics import ListAPIView, get_object_or_404
from rest_framework.generics import ListAPIView, GenericAPIView,\ from rest_framework.permissions import IsAuthenticated
get_object_or_404
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from sapl.api.serializers import ChoiceSerializer from sapl.api.serializers import ChoiceSerializer
@ -14,7 +11,8 @@ from sapl.utils import SaplGenericRelation
class TipoAutorContentOfModelContentTypeView(ListAPIView): class TipoAutorContentOfModelContentTypeView(ListAPIView):
serializer_class = ChoiceSerializer serializer_class = ChoiceSerializer
permission_classes = (AllowAny,) # FIXME aplicar permissão correta de usuário
permission_classes = (IsAuthenticated,)
queryset = TipoAutor.objects.all() queryset = TipoAutor.objects.all()
model = TipoAutor model = TipoAutor
pagination_class = None pagination_class = None

305
sapl/base/forms.py

@ -1,23 +1,23 @@
from crispy_forms.bootstrap import FieldWithButtons, StrictButton import django_filters
from crispy_forms.bootstrap import FieldWithButtons, InlineRadios, StrictButton
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Fieldset, Layout, Field, Div, Row from crispy_forms.layout import HTML, Button, Div, Field, Fieldset, Layout, Row
from crispy_forms.templatetags.crispy_forms_field import css_class
from django import forms from django import forms
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.contrib.auth.password_validation import validate_password from django.contrib.auth.password_validation import validate_password
from django.contrib.contenttypes.fields import GenericRel from django.contrib.contenttypes.fields import GenericRel
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError, ObjectDoesNotExist from django.core.exceptions import ValidationError
from django.db import models, transaction from django.db import models, transaction
from django.forms import ModelForm, widgets from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.base.models import Autor, TipoAutor from sapl.base.models import Autor, TipoAutor
from sapl.crispy_layout_mixin import form_actions, to_row, SaplFormLayout,\ from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
to_column to_row)
from sapl.materia.models import MateriaLegislativa from sapl.materia.models import MateriaLegislativa
from sapl.sessao.models import SessaoPlenaria from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MAX_IMAGE_UPLOAD_SIZE from sapl.settings import MAX_IMAGE_UPLOAD_SIZE
@ -26,6 +26,12 @@ from sapl.utils import (RANGE_ANOS, ImageThumbnailFileInput,
from .models import AppConfig, CasaLegislativa from .models import AppConfig, CasaLegislativa
ACTION_CREATE_USERS_AUTOR_CHOICE = [
('C', _('Criar novo Usuário')),
('A', _('Associar um usuário existente')),
('N', _('Autor sem Usuário de Acesso ao Sapl')),
]
class TipoAutorForm(ModelForm): class TipoAutorForm(ModelForm):
@ -37,7 +43,7 @@ class TipoAutorForm(ModelForm):
class Meta: class Meta:
model = TipoAutor model = TipoAutor
fields = ['descricao', fields = ['descricao',
'content_type', ] 'content_type']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -61,47 +67,65 @@ class TipoAutorForm(ModelForm):
(ct.pk, ct) for key, ct in content_types.items()] (ct.pk, ct) for key, ct in content_types.items()]
class ChoiceWithoutValidationField(forms.ChoiceField):
def validate(self, value):
if self.required and not value:
raise ValidationError(
self.error_messages['required'], code='required')
class AutorForm(ModelForm): class AutorForm(ModelForm):
"""senha = forms.CharField( senha = forms.CharField(
max_length=20, max_length=20,
label=_('Senha'), label=_('Senha'),
required=True, required=False,
widget=forms.PasswordInput()) widget=forms.PasswordInput())
senha_confirma = forms.CharField( senha_confirma = forms.CharField(
max_length=20, max_length=20,
label=_('Confirmar Senha'), label=_('Confirmar Senha'),
required=True, required=False,
widget=forms.PasswordInput()) widget=forms.PasswordInput())
email = forms.EmailField(
required=False,
label=_('Email'))
confirma_email = forms.EmailField( confirma_email = forms.EmailField(
required=True, required=False,
label=_('Confirmar Email')) label=_('Confirmar Email'))
username = forms.CharField( username = forms.CharField(
required=True, required=False,
max_length=50 max_length=50)
)"""
q = forms.CharField( q = forms.CharField(
max_length=50, required=False, max_length=50, required=False,
label='Pesquise o nome do Autor com o ' label='Pesquise o nome do Autor com o '
'tipo Selecionado e marque o escolhido.') 'tipo Selecionado e marque o escolhido.')
autor_related = forms.ChoiceField(label='',
required=False, autor_related = ChoiceWithoutValidationField(label='',
widget=forms.RadioSelect()) required=False,
widget=forms.RadioSelect())
action_user = forms.ChoiceField(
label=_('Usuário de acesso ao Sistema para este Autor'),
choices=ACTION_CREATE_USERS_AUTOR_CHOICE,
widget=forms.RadioSelect())
class Meta: class Meta:
model = Autor model = Autor
fields = ['tipo', fields = ['tipo',
'nome', 'nome',
'autor_related', 'autor_related',
'q'] 'q',
'action_user',
'username']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
autor_related = Div( autor_related = Div(
FieldWithButtons( FieldWithButtons(
Field('q', Field('q',
placeholder=_('Pesquisar por possíveis autores para ' placeholder=_('Pesquisar por possíveis autores para '
@ -109,110 +133,195 @@ class AutorForm(ModelForm):
StrictButton( StrictButton(
_('Filtrar'), css_class='btn-default btn-filtrar-autor', _('Filtrar'), css_class='btn-default btn-filtrar-autor',
type='button')), type='button')),
Field('autor_related'), Field('autor_related'),
css_class='hidden', css_class='hidden',
data_action='create', data_action='create',
data_application='AutorSearch', data_application='AutorSearch',
data_field='autor_related') data_field='autor_related')
row1 = to_row([ autor_select = Row(to_column(('tipo', 4)),
('tipo', 4), to_column(('nome', 8)),
('nome', 8), to_column((autor_related, 8)))
(autor_related, 8),
row2 = Row(to_column((InlineRadios('action_user'), 8)),
]) to_column(('username', 4)))
row3 = Row(to_column(('senha', 3)),
to_column(('senha_confirma', 3)),
to_column(('email', 3)),
to_column(('confirma_email', 3)),
css_class='new_user_fields hidden')
controle_acesso = Fieldset(
_('Controle de Acesso do Autor'),
row2, row3
)
self.helper = FormHelper() self.helper = FormHelper()
self.helper.layout = SaplFormLayout(row1) self.helper.layout = SaplFormLayout(autor_select, controle_acesso)
super(AutorForm, self).__init__(*args, **kwargs) super(AutorForm, self).__init__(*args, **kwargs)
self.fields['autor_related'].choices = [] self.fields['action_user'].initial = 'N'
if self.instance and self.instance.autor_related: self.fields['action_user'].inline_class = True
self.fields['autor_related'].choices = [
(self.instance.autor_related.pk, if self.instance.pk:
self.instance.autor_related)] if self.instance.autor_related:
self.fields['autor_related'].choices = [
(self.instance.autor_related.pk,
self.instance.autor_related)]
self.fields['q'].initial = self.instance.nome
if self.instance.user:
self.fields['username'].initial = self.instance.user.username
self.fields['action_user'].initial = 'A'
def valida_igualdade(self, texto1, texto2, msg): def valida_igualdade(self, texto1, texto2, msg):
if texto1 != texto2: if texto1 != texto2:
raise ValidationError(msg) raise ValidationError(msg)
return True return True
def valida_email_existente(self): def clean(self):
return get_user_model().objects.filter( User = get_user_model()
email=self.cleaned_data['email']).exists() cd = self.cleaned_data
def clea(self): if 'username' not in cd:
raise ValidationError(_('O username deve ser informado.'))
if 'username' not in self.cleaned_data:
raise ValidationError(_('Favor informar o username')) if 'action_user' not in cd:
raise ValidationError(_('Informe se o Autor terá usuário '
if ('senha' not in self.cleaned_data or 'para acesso ao Sistema.'))
'senha_confirma' not in self.cleaned_data):
raise ValidationError(_('Favor informar as senhas')) qs_user = User.objects.all()
qs_autor = Autor.objects.all()
msg = _('As senhas não conferem.')
self.valida_igualdade( if self.instance.pk:
self.cleaned_data['senha'], qs_autor = qs_autor.exclude(pk=self.instance.pk)
self.cleaned_data['senha_confirma'], if self.instance.user:
msg) qs_user = qs_user.exclude(pk=self.instance.user.pk)
if ('email' not in self.cleaned_data or if cd['action_user'] == 'C':
'confirma_email' not in self.cleaned_data): if User.objects.filter(username=cd['username']).exists():
raise ValidationError(_('Favor informar endereços de email')) raise ValidationError(
_('Já existe usuário com o username "%s". '
msg = _('Os emails não conferem.') 'Para usá-lo você deve selecionar '
self.valida_igualdade( '"Associar um usuário existente".') % cd['username'])
self.cleaned_data['email'],
self.cleaned_data['confirma_email'], if ('senha' not in cd or 'senha_confirma' not in cd or
msg) not cd['senha'] or not cd['senha_confirma']):
raise ValidationError(_(
email_existente = self.valida_email_existente() 'A senha e sua confirmação devem ser informadas.'))
msg = _('As senhas não conferem.')
if (Autor.objects.filter( self.valida_igualdade(cd['senha'], cd['senha_confirma'], msg)
username=self.cleaned_data['username']).exists()):
raise ValidationError(_('Já existe um autor para este usuário')) try:
validate_password(self.cleaned_data['senha'])
if email_existente: except ValidationError as error:
msg = _('Este email já foi cadastrado.') raise ValidationError(error)
raise ValidationError(msg)
if ('email' not in cd or 'confirma_email' not in cd or
try: not cd['email'] or not cd['confirma_email']):
validate_password(self.cleaned_data['senha']) raise ValidationError(_(
except ValidationError as error: 'O email e sua confirmação devem ser informados.'))
raise ValidationError(error) msg = _('Os emails não conferem.')
self.valida_igualdade(cd['email'], cd['confirma_email'], msg)
try:
get_user_model().objects.get( if qs_user.filter(email=cd['email']).exists():
username=self.cleaned_data['username'], raise ValidationError(_('Este email já foi cadastrado.'))
email=self.cleaned_data['email'])
except ObjectDoesNotExist: if qs_autor.filter(user__email=cd['email']).exists():
msg = _('Este nome de usuario não está cadastrado. ' + raise ValidationError(
'Por favor, cadastre-o no Administrador do ' + _('Já existe um Autor com este email.'))
'Sistema antes de adicioná-lo como Autor')
raise ValidationError(msg) elif cd['action_user'] == 'A':
if not User.objects.filter(username=cd['username']).exists():
raise ValidationError(
_('Não existe usuário com username "%s". '
'Para usá-lo você deve selecionar '
'"Criar novo Usuário".') % cd['username'])
if cd['action_user'] != 'N':
if qs_autor.filter(user__username=cd['username']).exists():
raise ValidationError(
_('Já existe um Autor para este usuário.'))
"""
'if' não é necessário por ser campo obrigatório e o framework
mostrar a mensagem de obrigatório junto ao campo. mas foi colocado
ainda assim para renderizar um message.danger no topo do form.
"""
if 'tipo' not in cd or not cd['tipo']:
raise ValidationError(
_('O Tipo do Autor deve ser selecionado.'))
tipo = cd['tipo']
if not tipo.content_type:
if 'nome' not in cd or not cd['nome']:
raise ValidationError(
_('O Nome do Autor deve ser informado.'))
else:
if 'autor_related' not in cd or not cd['autor_related']:
raise ValidationError(
_('Um registro de %s deve ser escolhido para ser '
'vinculado ao cadastro de Autor') % tipo.descricao)
if not tipo.content_type.model_class().objects.filter(
pk=cd['autor_related']).exists():
raise ValidationError(
_('O Registro definido (%s-%s) não está na base de %s.'
) % (cd['autor_related'], cd['q'], tipo.descricao))
if qs_autor.filter(object_id=cd['autor_related']).exists():
autor = qs_autor.filter(object_id=cd['autor_related']).first()
raise ValidationError(
_('Já existe um autor Cadastrado para %s'
) % autor.autor_related)
return self.cleaned_data return self.cleaned_data
@transaction.atomic @transaction.atomic
def sav(self, commit=False): def save(self, commit=False):
print('aqui')
autor = super(AutorForm, self).save(commit) autor = super(AutorForm, self).save(commit)
u = get_user_model().objects.get( user_old = autor.user if autor.user_id else None
username=autor.username,
email=autor.email)
u.set_password(self.cleaned_data['senha']) if self.cleaned_data['action_user'] == 'A':
u.is_active = False u = get_user_model().objects.get(
u.save() username=self.cleaned_data['username'])
autor.user = u
autor.user = u elif self.cleaned_data['action_user'] == 'C':
u = get_user_model().objects.create(
username=self.cleaned_data['username'],
email=self.cleaned_data['email'])
u.set_password(self.cleaned_data['senha'])
# Define usuário como ativo em ambiente de desenvolvimento
# pode logar sem a necessidade de passar pela validação de email
u.is_active = settings.DEBUG
u.save()
autor.user = u
if not autor.tipo.content_type:
autor.content_type = None
autor.object_id = None
autor.autor_related = None
else:
autor.autor_related = autor.tipo.content_type.model_class(
).objects.get(pk=self.cleaned_data['autor_related'])
autor.nome = str(autor.autor_related)
autor.save() autor.save()
grupo = Group.objects.filter(name='Autor')[0] if self.cleaned_data['action_user'] != 'N':
u.groups.add(grupo) # FIXME melhorar captura de grupo de Autor, levando em conta
# tradução
grupo = Group.objects.filter(name='Autor')[0]
autor.user.groups.add(grupo)
if user_old and user_old != autor.user:
user_old.groups.remove(grupo)
return autor return autor

20
sapl/base/migrations/0025_tipoautor_cria_usuario.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-11 14:38
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('base', '0024_auto_20161010_1002'),
]
operations = [
migrations.AddField(
model_name='tipoautor',
name='cria_usuario',
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, help_text='Criação de Usuários víncula e libera o acesso de Autores ao sistema. Vincular um Autor a um tipo que esta opção está marcada como "Não", o Autor não terá username associado.', verbose_name='Criação de Usuários'),
),
]

19
sapl/base/migrations/0026_remove_tipoautor_cria_usuario.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-11 18:08
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('base', '0025_tipoautor_cria_usuario'),
]
operations = [
migrations.RemoveField(
model_name='tipoautor',
name='cria_usuario',
),
]

22
sapl/base/migrations/0027_auto_20161011_1624.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-11 19:24
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 = [
('base', '0026_remove_tipoautor_cria_usuario'),
]
operations = [
migrations.AlterField(
model_name='autor',
name='user',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
]

7
sapl/base/models.py

@ -7,12 +7,11 @@ from django.contrib.contenttypes.models import ContentType
from django.core import exceptions from django.core import exceptions
from django.db import models, router from django.db import models, router
from django.db.utils import DEFAULT_DB_ALIAS from django.db.utils import DEFAULT_DB_ALIAS
from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat
from sapl.utils import UF, YES_NO_CHOICES, get_settings_auth_user_model from sapl.utils import UF, YES_NO_CHOICES, get_settings_auth_user_model
TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensivo')), TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensivo')),
('R', _('Restritivo'))) ('R', _('Restritivo')))
@ -151,7 +150,9 @@ class TipoAutor(models.Model):
class Autor(models.Model): class Autor(models.Model):
user = models.OneToOneField(get_settings_auth_user_model()) user = models.OneToOneField(get_settings_auth_user_model(),
on_delete=models.SET_NULL,
null=True)
tipo = models.ForeignKey(TipoAutor, verbose_name=_('Tipo do Autor')) tipo = models.ForeignKey(TipoAutor, verbose_name=_('Tipo do Autor'))

15
sapl/base/urls.py

@ -14,21 +14,18 @@ from .views import (AppConfigCrud, CasaLegislativaCrud, HelpView,
RelatorioMateriasTramitacaoView, RelatorioMateriasTramitacaoView,
RelatorioPresencaSessaoView) RelatorioPresencaSessaoView)
app_name = AppConfig.name app_name = AppConfig.name
urlpatterns = [ urlpatterns = [
<<<<<<< 6123d2617726dd220c02c2bb3b3c27ed4b136df1
=======
url(r'^sistema/autor/tipo/', include(TipoAutorCrud.get_urls())), url(r'^sistema/autor/tipo/', include(TipoAutorCrud.get_urls())),
url(r'^sistema/autor/', include(AutorCrud.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/', TemplateView.as_view(template_name='ajuda.html')),
url(r'^sistema/ajuda/(?P<topic>\w+)$', url(r'^sistema/ajuda/(?P<topic>\w+)$',
HelpView.as_view(), name='help_topic'), HelpView.as_view(), name='help_topic'),
url(r'^sistema/ajuda/', TemplateView.as_view(template_name='ajuda/index.html'), url(r'^sistema/ajuda/',
TemplateView.as_view(template_name='ajuda/index.html'),
name='help_base'), name='help_base'),
url(r'^sistema/casa-legislativa/', include(CasaLegislativaCrud.get_urls()), url(r'^sistema/casa-legislativa/', include(CasaLegislativaCrud.get_urls()),
name="casa_legislativa"), name="casa_legislativa"),
@ -55,21 +52,13 @@ urlpatterns = [
RelatorioAtasView.as_view(), RelatorioAtasView.as_view(),
name='atas'), name='atas'),
<<<<<<< 6123d2617726dd220c02c2bb3b3c27ed4b136df1
=======
# todos os sublink s de sistema devem vir acima deste # 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') url(r'^sistema/', permission_required('base.view_tabelas_auxiliares')
(TemplateView.as_view(template_name='sistema.html'))), (TemplateView.as_view(template_name='sistema.html'))),
<<<<<<< 6123d2617726dd220c02c2bb3b3c27ed4b136df1
=======
url(r'^login/$', views.login, { url(r'^login/$', views.login, {
'template_name': 'base/login.html', 'authentication_form': LoginForm}, 'template_name': 'base/login.html', 'authentication_form': LoginForm},
name='login'), name='login'),
url(r'^logout/$', views.logout, {'next_page': '/login'}, name='logout'), url(r'^logout/$', views.logout, {'next_page': '/login'}, name='logout'),
>>>>>>> Ref Autor, TipoAutor, cria app api DRF
] ]

169
sapl/base/views.py

@ -1,9 +1,7 @@
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.models import Group
from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.tokens import default_token_generator
from django.core.mail import send_mail from django.core.mail import send_mail
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
@ -16,13 +14,11 @@ from django.views.generic.base import TemplateView
from django_filters.views import FilterView from django_filters.views import FilterView
from sapl.base.forms import AutorForm, TipoAutorForm from sapl.base.forms import AutorForm, TipoAutorForm
from sapl.base.models import TipoAutor, Autor from sapl.base.models import Autor, TipoAutor
from sapl.crispy_layout_mixin import to_row, SaplFormLayout, form_actions
from sapl.crud.base import CrudAux from sapl.crud.base import CrudAux
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.parlamentares.models import Parlamentar from sapl.parlamentares.models import Parlamentar
from sapl.sessao.models import OrdemDia, SessaoPlenaria from sapl.sessao.models import OrdemDia, SessaoPlenaria
from sapl.utils import autor_label, autor_modal
from .forms import (CasaLegislativaForm, ConfiguracoesAppForm, from .forms import (CasaLegislativaForm, ConfiguracoesAppForm,
RelatorioAtasFilterSet, RelatorioAtasFilterSet,
@ -38,41 +34,6 @@ def get_casalegislativa():
return CasaLegislativa.objects.first() 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): class TipoAutorCrud(CrudAux):
model = TipoAutor model = TipoAutor
help_path = 'tipo-autor' help_path = 'tipo-autor'
@ -89,61 +50,97 @@ class AutorCrud(CrudAux):
class BaseMixin(CrudAux.BaseMixin): class BaseMixin(CrudAux.BaseMixin):
list_field_names = ['tipo', 'nome', 'user__username'] list_field_names = ['tipo', 'nome', 'user__username']
class DeleteView(CrudAux.DeleteView):
def delete(self, *args, **kwargs):
self.object = self.get_object()
# FIXME melhorar captura de grupo de Autor, levando em conta trad
grupo = Group.objects.filter(name='Autor')[0]
self.object.user.groups.remove(grupo)
return CrudAux.DeleteView.delete(self, *args, **kwargs)
class UpdateView(CrudAux.UpdateView): class UpdateView(CrudAux.UpdateView):
layout_key = None layout_key = None
form_class = AutorForm form_class = AutorForm
def __init__(self, *args, **kwargs): def form_valid(self, form):
# montar_helper_autor(self) # devido a implement do form o form_valid do Crud deve ser pulado
super(CrudAux.UpdateView, self).__init__(*args, **kwargs) return super(CrudAux.UpdateView, self).form_valid(form)
def get_context_data(self, **kwargs): def get_success_url(self):
context = super(
CrudAux.UpdateView, self).get_context_data(**kwargs) # FIXME try except - testar envio de emails
#context['helper'] = self.helper
return context pk_autor = self.object.id
try:
kwargs = {}
user = self.object.user
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 = [user.email]
send_mail(assunto, mensagem, remetente, destinatario,
fail_silently=False)
except:
pass
return reverse('sapl.base:autor_detail',
kwargs={'pk': pk_autor})
class CreateView(CrudAux.CreateView): class CreateView(CrudAux.CreateView):
form_class = AutorForm form_class = AutorForm
layout_key = None layout_key = None
"""def __init__(self, *args, **kwargs): def form_valid(self, form):
montar_helper_autor(self) # devido a implement do form o form_valid do Crud deve ser pulado
super(CrudAux.CreateView, self).__init__(*args, **kwargs)""" return super(CrudAux.CreateView, self).form_valid(form)
"""def get_context_data(self, **kwargs): def get_success_url(self):
context = super( pk_autor = self.object.id
CrudAux.CreateView, self).get_context_data(**kwargs) try:
context['helper'] = self.helper # FIXME try except - testar envio de emails
return context""" kwargs = {}
user = self.object.user
"""def get_success_url(self): kwargs['token'] = default_token_generator.make_token(user)
pk_autor = Autor.objects.get( kwargs['uidb64'] = urlsafe_base64_encode(force_bytes(user.pk))
email=self.request.POST.get('email')).id assunto = "SAPL - Confirmação de Conta"
kwargs = {} full_url = self.request.get_raw_uri()
user = get_user_model().objects.get( url_base = full_url[:full_url.find('sistema') - 1]
email=self.request.POST.get('email'))
kwargs['token'] = default_token_generator.make_token(user) mensagem = (
kwargs['uidb64'] = urlsafe_base64_encode(force_bytes(user.pk)) "Este e-mail foi utilizado para fazer cadastro no " +
assunto = "SAPL - Confirmação de Conta" "SAPL com o perfil de Autor. Agora você pode " +
full_url = self.request.get_raw_uri() "criar/editar/enviar Proposições.\n" +
url_base = full_url[:full_url.find('sistema') - 1] "Seu nome de usuário é: " +
self.request.POST['username'] + "\n"
mensagem = ("Este e-mail foi utilizado para fazer cadastro no " + "Caso você não tenha feito este cadastro, por favor " +
"SAPL com o perfil de Autor. Agora você pode " + "ignore esta mensagem. Caso tenha, clique " +
"criar/editar/enviar Proposições.\n" + "no link abaixo\n" + url_base +
"Seu nome de usuário é: " + reverse('sapl.materia:confirmar_email', kwargs=kwargs))
self.request.POST['username'] + "\n" remetente = settings.EMAIL_SEND_USER
"Caso você não tenha feito este cadastro, por favor " + destinatario = [user.email]
"ignore esta mensagem. Caso tenha, clique " + send_mail(assunto, mensagem, remetente, destinatario,
"no link abaixo\n" + url_base + fail_silently=False)
reverse('sapl.materia:confirmar_email', kwargs=kwargs)) except:
remetente = settings.EMAIL_SEND_USER pass
destinatario = [self.request.POST.get('email')]
send_mail(assunto, mensagem, remetente, destinatario,
fail_silently=False)
return reverse('sapl.base:autor_detail', return reverse('sapl.base:autor_detail',
kwargs={'pk': pk_autor})""" kwargs={'pk': pk_autor})
class RelatorioAtasView(FilterView): class RelatorioAtasView(FilterView):

1
sapl/comissoes/models.py

@ -1,5 +1,4 @@
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from model_utils import Choices from model_utils import Choices

2
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):

13
sapl/crud/base.py

@ -13,8 +13,8 @@ from django.db import models
from django.http.response import Http404 from django.http.response import Http404
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 string_concat
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat
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
@ -23,7 +23,6 @@ from django.views.generic.list import MultipleObjectMixin
from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display
from sapl.utils import normalize from sapl.utils import normalize
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \ ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \
@ -882,9 +881,9 @@ class CrudAux(Crud):
""" """
Checa permissão para ver qualquer dado de tabela auxiliar Checa permissão para ver qualquer dado de tabela auxiliar
a permissão base.view_tabelas_auxiliares está definada class Meta a permissão base.view_tabelas_auxiliares está definada class Meta
do model sapl.base.models.AppConfig que, naturalmente é um arquivo do model sapl.base.models.AppConfig que, naturalmente é um arquivo
de configuração geral e pode ser acessado através das Tabelas de configuração geral e pode ser acessado através das Tabelas
Auxiliares... Com isso o script de geração de perfis acaba que por Auxiliares... Com isso o script de geração de perfis acaba que por
criar essa permissão apenas para o perfil Operador Geral. criar essa permissão apenas para o perfil Operador Geral.
""" """
permission_required = ('base.view_tabelas_auxiliares',) permission_required = ('base.view_tabelas_auxiliares',)
@ -895,8 +894,8 @@ class CrudAux(Crud):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
""" """
Mantem as permissões individuais geradas pelo Crud através do Mantem as permissões individuais geradas pelo Crud através do
Modelo e adiciona a obrigatoriedade de permissão para view Modelo e adiciona a obrigatoriedade de permissão para view
tabelas auxiliares. tabelas auxiliares.
""" """
self.permission_required = self.permission_required + \ self.permission_required = self.permission_required + \

9
sapl/materia/forms.py

@ -1,17 +1,14 @@
from datetime import datetime from datetime import datetime
import django_filters
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout
from django import forms from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group, User
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models, transaction from django.db import models
from django.db.models import Max from django.db.models import Max
from django.forms import ModelForm from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
from sapl.crispy_layout_mixin import form_actions, to_row from sapl.crispy_layout_mixin import form_actions, to_row
@ -508,7 +505,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
'data_apresentacao', 'data_apresentacao',
'data_publicacao', 'data_publicacao',
'autoria__autor__tipo', 'autoria__autor__tipo',
#'autoria__autor__partido', # 'autoria__autor__partido',
'relatoria__parlamentar_id', 'relatoria__parlamentar_id',
'local_origem_externa', 'local_origem_externa',
'tramitacao__unidade_tramitacao_destino', 'tramitacao__unidade_tramitacao_destino',

16
sapl/materia/migrations/0056_merge.py

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-11 19:45
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('materia', '0055_auto_20161009_1418'),
('materia', '0054_auto_20161011_0904'),
]
operations = [
]

2
sapl/materia/models.py

@ -5,7 +5,7 @@ from model_utils import Choices
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.parlamentares.models import Parlamentar, Partido from sapl.parlamentares.models import Parlamentar
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
get_settings_auth_user_model, get_settings_auth_user_model,
restringe_tipos_de_arquivo_txt) restringe_tipos_de_arquivo_txt)

10
sapl/materia/urls.py

@ -15,11 +15,11 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
ProposicaoRecebida, ProposicaoTaView, ProposicaoRecebida, ProposicaoTaView,
ReceberProposicao, ReciboProposicaoView, ReceberProposicao, ReciboProposicaoView,
RegimeTramitacaoCrud, RelatoriaCrud, RegimeTramitacaoCrud, RelatoriaCrud,
StatusTramitacaoCrud, StatusTramitacaoCrud, TipoDocumentoCrud,
TipoDocumentoCrud, TipoFimRelatoriaCrud, TipoFimRelatoriaCrud, TipoMateriaCrud,
TipoMateriaCrud, TipoProposicaoCrud, TipoProposicaoCrud, TramitacaoCrud,
TramitacaoCrud, TramitacaoEmLoteView, TramitacaoEmLoteView, UnidadeTramitacaoCrud,
UnidadeTramitacaoCrud, recuperar_materia) recuperar_materia)
from .apps import AppConfig from .apps import AppConfig

30
sapl/materia/views.py

@ -3,12 +3,10 @@ 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, Button from crispy_forms.layout import HTML
from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.tokens import default_token_generator
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.core.mail import send_mail from django.core.mail import send_mail
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
@ -17,17 +15,15 @@ from django.http import JsonResponse
from django.http.response import HttpResponseRedirect from django.http.response import HttpResponseRedirect
from django.shortcuts import redirect from django.shortcuts import redirect
from django.template import Context, loader from django.template import Context, loader
from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_decode
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import CreateView, ListView, TemplateView, UpdateView from django.views.generic import CreateView, ListView, TemplateView, UpdateView
from django.views.generic.base import RedirectView from django.views.generic.base import RedirectView
from django_filters.views import FilterView from django_filters.views import FilterView
from sapl.base.models import AppConfig, CasaLegislativa, Autor, TipoAutor from sapl.base.models import AppConfig, Autor, CasaLegislativa, TipoAutor
from sapl.base.views import montar_row_autor
from sapl.compilacao.views import IntegracaoTaView from sapl.compilacao.views import IntegracaoTaView
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row 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,
ACTION_LIST, ACTION_UPDATE, RP_DETAIL, RP_LIST, ACTION_LIST, ACTION_UPDATE, RP_DETAIL, RP_LIST,
Crud, CrudAux, CrudDetailView, MasterDetailCrud, Crud, CrudAux, CrudDetailView, MasterDetailCrud,
@ -37,8 +33,13 @@ from sapl.materia.forms import AnexadaForm, LegislacaoCitadaForm
from sapl.norma.models import LegislacaoCitada from sapl.norma.models import LegislacaoCitada
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label, from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
autor_modal, gerar_hash_arquivo, get_base_url, autor_modal, gerar_hash_arquivo, get_base_url,
<<<<<<< 3276eb12726b741df770d5a6ed2a9a1a83c15849
permissoes_autor, permissoes_materia, permissoes_autor, permissoes_materia,
permissoes_protocoloadm, permission_required_for_app) permissoes_protocoloadm, permission_required_for_app)
=======
montar_row_autor, permissoes_autor, permissoes_materia,
permissoes_protocoloadm)
>>>>>>> Conc refatoração no Cada de Autor e Tipos de Autor
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
ConfirmarProposicaoForm, DocumentoAcessorioForm, ConfirmarProposicaoForm, DocumentoAcessorioForm,
@ -48,13 +49,12 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
filtra_tramitacao_destino, filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status, filtra_tramitacao_destino_and_status,
filtra_tramitacao_status) filtra_tramitacao_status)
from .models import (AcompanhamentoMateria, Anexada, Autoria, from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial,
DespachoInicial, DocumentoAcessorio, MateriaLegislativa, DocumentoAcessorio, MateriaLegislativa, Numeracao, Orgao,
Numeracao, Orgao, Origem, Proposicao, RegimeTramitacao, Origem, Proposicao, RegimeTramitacao, Relatoria,
Relatoria, StatusTramitacao, TipoDocumento, StatusTramitacao, TipoDocumento, TipoFimRelatoria,
TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao, TipoMateriaLegislativa, TipoProposicao, Tramitacao,
Tramitacao, UnidadeTramitacao) UnidadeTramitacao)
OrigemCrud = Crud.build(Origem, '') OrigemCrud = Crud.build(Origem, '')

5
sapl/parlamentares/models.py

@ -1,14 +1,13 @@
from datetime import datetime from datetime import datetime
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from model_utils import Choices from model_utils import Choices
from sapl.base.models import Autor from sapl.base.models import Autor
from sapl.utils import (INDICADOR_AFASTAMENTO, UF, YES_NO_CHOICES, from sapl.utils import (INDICADOR_AFASTAMENTO, UF, YES_NO_CHOICES,
intervalos_tem_intersecao, SaplGenericRelation, intervalos_tem_intersecao,
restringe_tipos_de_arquivo_img, SaplGenericRelation) restringe_tipos_de_arquivo_img)
class Legislatura(models.Model): class Legislatura(models.Model):

1
sapl/protocoloadm/forms.py

@ -421,6 +421,7 @@ class ProtocoloMateriaForm(ModelForm):
super(ProtocoloMateriaForm, self).__init__( super(ProtocoloMateriaForm, self).__init__(
*args, **kwargs) *args, **kwargs)
self.fields['tipo_protocolo'].inline_class = True
class DocumentoAcessorioAdministrativoForm(ModelForm): class DocumentoAcessorioAdministrativoForm(ModelForm):

8
sapl/sessao/forms.py

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

7
sapl/sessao/urls.py

@ -11,10 +11,9 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
PesquisarPautaSessaoView, PesquisarPautaSessaoView,
PesquisarSessaoPlenariaView, PesquisarSessaoPlenariaView,
PresencaOrdemDiaView, PresencaView, ResumoView, PresencaOrdemDiaView, PresencaView, ResumoView,
SessaoCrud, SessaoCrud, TipoExpedienteCrud,
TipoExpedienteCrud, TipoResultadoVotacaoCrud, TipoResultadoVotacaoCrud, TipoSessaoCrud,
TipoSessaoCrud, VotacaoEditView, VotacaoEditView, VotacaoExpedienteEditView,
VotacaoExpedienteEditView,
VotacaoExpedienteView, VotacaoNominalEditView, VotacaoExpedienteView, VotacaoNominalEditView,
VotacaoNominalExpedienteEditView, VotacaoNominalExpedienteEditView,
VotacaoNominalExpedienteView, VotacaoNominalExpedienteView,

10
sapl/settings.py

@ -26,7 +26,6 @@ PROJECT_DIR = Path(__file__).ancestor(2)
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config('SECRET_KEY', default='') SECRET_KEY = config('SECRET_KEY', default='')
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = config('DEBUG', default=False, cast=bool) DEBUG = config('DEBUG', default=False, cast=bool)
@ -35,6 +34,9 @@ ALLOWED_HOSTS = ['*']
LOGIN_REDIRECT_URL = '/' LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/login/?next=' LOGIN_URL = '/login/?next='
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# SAPL business apps in dependency order # SAPL business apps in dependency order
SAPL_APPS = ( SAPL_APPS = (
'sapl.base', 'sapl.base',
@ -48,7 +50,7 @@ SAPL_APPS = (
'sapl.painel', 'sapl.painel',
'sapl.protocoloadm', 'sapl.protocoloadm',
'sapl.compilacao', 'sapl.compilacao',
'sapl.api' 'sapl.api'
) )
INSTALLED_APPS = ( INSTALLED_APPS = (
@ -72,8 +74,8 @@ INSTALLED_APPS = (
) + SAPL_APPS ) + SAPL_APPS
if DEBUG: # if DEBUG:
INSTALLED_APPS += ('debug_toolbar',) # INSTALLED_APPS += ('debug_toolbar',)
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',

1
sapl/templates/base.html

@ -287,7 +287,6 @@
<script type="text/javascript" src="{% static 'drunken-parrot-flat-ui/js/checkbox.js' %}"></script> <script type="text/javascript" src="{% static 'drunken-parrot-flat-ui/js/checkbox.js' %}"></script>
<script type="text/javascript" src="{% static 'drunken-parrot-flat-ui/js/radio.js' %}"></script> <script type="text/javascript" src="{% static 'drunken-parrot-flat-ui/js/radio.js' %}"></script>
<script src="{% static 'tinymce/tinymce.min.js' %}"></script> <script src="{% static 'tinymce/tinymce.min.js' %}"></script>
<script type="text/javascript" src="{% static 'jsdiff/diff.min.js' %}"></script> <script type="text/javascript" src="{% static 'jsdiff/diff.min.js' %}"></script>

28
sapl/templates/base/autor_form.html

@ -32,17 +32,20 @@ $(document).ready(function(){
if (atualizar) { if (atualizar) {
var radios = $("#div_id_autor_related .controls").html(''); var radios = $("#div_id_autor_related .controls").html('');
data.forEach(function (val, index) { data.forEach(function (val, index) {
var html_radio = '<div class="radio"><label><input type="radio" name="autor_related" id="id_autor_related_'+index+'" value="'+val.pk+'">'+val.display+'</label></div>'; var html_radio = '<label class="radio"><span class="icons"><span class="first-icon"></span><span class="second-icon"></span></span><input type="radio" name="autor_related" id="id_autor_related_'+index+'" value="'+val.pk+'">'+val.display+'</label>';
radios.append(html_radio); radios.append(html_radio);
}); });
if (data.length > 1) { if (data.length > 1) {
$('input[name=autor_related]').change(function(event){ $('input[name=autor_related]').change(function(event){
$('#id_q').val(event.target.parentElement.textContent); if (this.checked)
$('#id_q').val(event.target.parentElement.textContent);
//$('input[name=autor_related]:not(:checked)').closest('.radio').remove(); //$('input[name=autor_related]:not(:checked)').closest('.radio').remove();
}); });
} }
else { else {
$('input[name=autor_related]').prop('checked', 'checked') $('input[name=autor_related]').prop('checked', 'checked');
$('input[name=autor_related]').closest('.radio').addClass('checked');
} }
} }
else{ else{
@ -52,7 +55,6 @@ $(document).ready(function(){
active('nome'); active('nome');
}); });
} }
$('#id_tipo').change(function(event) { $('#id_tipo').change(function(event) {
if (event.target.selectedIndex == 0) { if (event.target.selectedIndex == 0) {
$('#id_nome, #id_q').val(''); $('#id_nome, #id_q').val('');
@ -68,6 +70,24 @@ $(document).ready(function(){
var pk = $('#id_tipo').val(); var pk = $('#id_tipo').val();
update_search(pk); update_search(pk);
}); });
$('input[name=action_user]').change(function(event) {
if (event.target.value == 'C')
$('.new_user_fields, #div_id_username').removeClass('hidden');
else if (event.target.value == 'N')
$('.new_user_fields, #div_id_username').addClass('hidden');
else {
$('#div_id_username').removeClass('hidden');
$('.new_user_fields').addClass('hidden');
}
});
$('input[name=action_user]:checked').trigger('change');
$('input[name=autor_related]').closest('.radio').remove();
var pk = $('#id_tipo').val();
if (pk)
update_search(pk, $('#id_q').val().length > 0)
}); });

4
sapl/templates/base/layouts.yaml

@ -18,12 +18,12 @@ AppConfig:
TipoAutor: TipoAutor:
{% trans 'Tipo Autor' %}: {% trans 'Tipo Autor' %}:
- content_type descricao:7 - content_type:4 descricao
Autor: Autor:
{% trans 'Autor' %}: {% trans 'Autor' %}:
- tipo:3 nome - tipo:3 nome
- username:6 cargo - user:6 cargo
AutorCreate: AutorCreate:
{% trans 'Cadastro de Usuários Autores' %}: {% trans 'Cadastro de Usuários Autores' %}:

14
sapl/templates/bootstrap3/layout/checkboxselectmultiple.html

@ -0,0 +1,14 @@
{% load crispy_forms_filters %}
{% load l10n %}
<div class="controls controls-checkbox {{ field_class }}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
{% include 'bootstrap3/layout/field_errors_block.html' %}
{% for choice in field.field.choices %}
<label class="checkbox{% if field.field.inline_class %} checkbox-inline{% endif %}{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|stringformat:"s" %} checked{% endif %}" for="id_{{ field.html_name }}_{{ forloop.counter }}">
<span class="icons"><span class="first-icon"></span><span class="second-icon fa fa-check"></span></span>
<input type="checkbox"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
</label>
{% endfor %}
{% include 'bootstrap3/layout/help_text.html' %}
</div>

19
sapl/templates/bootstrap3/layout/radioselect.html

@ -0,0 +1,19 @@
{% load crispy_forms_filters %}
{% load l10n %}
<div class="controls controls-radio {{ field_class }}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
{% include 'bootstrap3/layout/field_errors_block.html' %}
{% for choice in field.field.choices %}
<label class="radio{% if field.field.inline_class %} radio-inline{% endif %}{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|stringformat:"s" %} checked{% endif %}" for="id_{{ field.html_name }}_{{ forloop.counter }}">
<span class="icons">
<span class="first-icon"></span>
<span class="second-icon"></span>
</span>
<input type="radio"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
</label>
{% endfor %}
{% include 'bootstrap3/layout/help_text.html' %}
</div>

6
sapl/test_urls.py

@ -1,3 +1,4 @@
import pytest
from django.apps import apps from django.apps import apps
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.management import _get_all_permissions from django.contrib.auth.management import _get_all_permissions
@ -6,7 +7,7 @@ from django.contrib.contenttypes.models import ContentType
from django.db import transaction from django.db import transaction
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 _
import pytest from django.utils.translation import string_concat
from sapl.crud.base import PermissionRequiredForAppCrudMixin from sapl.crud.base import PermissionRequiredForAppCrudMixin
from sapl.materia.views import recuperar_materia from sapl.materia.views import recuperar_materia
@ -15,7 +16,6 @@ from scripts.lista_urls import lista_urls
from .settings import SAPL_APPS from .settings import SAPL_APPS
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db
sapl_appconfs = [apps.get_app_config(n[5:]) for n in SAPL_APPS] sapl_appconfs = [apps.get_app_config(n[5:]) for n in SAPL_APPS]
@ -335,7 +335,7 @@ urls_publicas_excecoes = {
""" """
# gerar uma instancia de teste para cada usuário não foi possível. São 500 # gerar uma instancia de teste para cada usuário não foi possível. São 500
urls para cada operador. Isso fez com que o Travis estourasse o tempo de urls para cada operador. Isso fez com que o Travis estourasse o tempo de
processamento do teste... passando de 2hs... até outro modo, a estratégia de processamento do teste... passando de 2hs... até outro modo, a estratégia de
encapsular apenas as urls e testar em loop os operadores será mantida. encapsular apenas as urls e testar em loop os operadores será mantida.

2
sapl/urls.py

@ -20,6 +20,7 @@ from django.contrib import admin
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.views.static import serve as view_static_server from django.views.static import serve as view_static_server
import sapl.api.urls
import sapl.base.urls import sapl.base.urls
import sapl.comissoes.urls import sapl.comissoes.urls
import sapl.compilacao.urls import sapl.compilacao.urls
@ -31,7 +32,6 @@ import sapl.parlamentares.urls
import sapl.protocoloadm.urls import sapl.protocoloadm.urls
import sapl.relatorios.urls import sapl.relatorios.urls
import sapl.sessao.urls import sapl.sessao.urls
import sapl.api.urls
urlpatterns = [ urlpatterns = [
url(r'^$', TemplateView.as_view(template_name='index.html')), url(r'^$', TemplateView.as_view(template_name='index.html')),

41
sapl/utils.py

@ -4,6 +4,9 @@ from unicodedata import normalize as unicodedata_normalize
import hashlib import hashlib
import logging import logging
import magic
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button
from django import forms from django import forms
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
@ -15,12 +18,13 @@ from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied, ValidationError from django.core.exceptions import PermissionDenied, ValidationError
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from floppyforms import ClearableFileInput from floppyforms import ClearableFileInput
import magic
from sapl.settings import BASE_DIR from sapl.settings import BASE_DIR
sapl_logger = logging.getLogger(BASE_DIR.name) sapl_logger = logging.getLogger(BASE_DIR.name)
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
def normalize(txt): def normalize(txt):
return unicodedata_normalize( return unicodedata_normalize(
@ -56,6 +60,41 @@ autor_modal = '''
''' '''
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 SaplGenericRelation(GenericRelation): class SaplGenericRelation(GenericRelation):
def __init__(self, to, fields_search=(), **kwargs): def __init__(self, to, fields_search=(), **kwargs):

Loading…
Cancel
Save