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 sapl.comissoes.models import Comissao
from sapl.parlamentares.models import Parlamentar
class ChoiceSerializer(serializers.Serializer):
pk = serializers.IntegerField()
@ -10,16 +7,3 @@ class ChoiceSerializer(serializers.Serializer):
def get_display(self, 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 rest_framework.routers import DefaultRouter
from django.conf.urls import url
from sapl.api.views import TipoAutorContentOfModelContentTypeView
from .apps import AppConfig
app_name = AppConfig.name

10
sapl/api/views.py

@ -1,10 +1,7 @@
from django.db.models import Q
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.generics import ListAPIView, get_object_or_404
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ModelViewSet
from sapl.api.serializers import ChoiceSerializer
@ -14,7 +11,8 @@ from sapl.utils import SaplGenericRelation
class TipoAutorContentOfModelContentTypeView(ListAPIView):
serializer_class = ChoiceSerializer
permission_classes = (AllowAny,)
# FIXME aplicar permissão correta de usuário
permission_classes = (IsAuthenticated,)
queryset = TipoAutor.objects.all()
model = TipoAutor
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.layout import HTML, Button, Fieldset, Layout, Field, Div, Row
from crispy_forms.templatetags.crispy_forms_field import css_class
from crispy_forms.layout import HTML, Button, Div, Field, Fieldset, Layout, Row
from django import forms
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm
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.core.exceptions import ValidationError
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 _
import django_filters
from sapl.base.models import Autor, TipoAutor
from sapl.crispy_layout_mixin import form_actions, to_row, SaplFormLayout,\
to_column
from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
to_row)
from sapl.materia.models import MateriaLegislativa
from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MAX_IMAGE_UPLOAD_SIZE
@ -26,6 +26,12 @@ from sapl.utils import (RANGE_ANOS, ImageThumbnailFileInput,
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):
@ -37,7 +43,7 @@ class TipoAutorForm(ModelForm):
class Meta:
model = TipoAutor
fields = ['descricao',
'content_type', ]
'content_type']
def __init__(self, *args, **kwargs):
@ -61,47 +67,65 @@ class TipoAutorForm(ModelForm):
(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):
"""senha = forms.CharField(
senha = forms.CharField(
max_length=20,
label=_('Senha'),
required=True,
required=False,
widget=forms.PasswordInput())
senha_confirma = forms.CharField(
max_length=20,
label=_('Confirmar Senha'),
required=True,
required=False,
widget=forms.PasswordInput())
email = forms.EmailField(
required=False,
label=_('Email'))
confirma_email = forms.EmailField(
required=True,
required=False,
label=_('Confirmar Email'))
username = forms.CharField(
required=True,
max_length=50
)"""
required=False,
max_length=50)
q = forms.CharField(
max_length=50, required=False,
label='Pesquise o nome do Autor com o '
'tipo Selecionado e marque o escolhido.')
autor_related = forms.ChoiceField(label='',
required=False,
widget=forms.RadioSelect())
autor_related = ChoiceWithoutValidationField(label='',
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:
model = Autor
fields = ['tipo',
'nome',
'autor_related',
'q']
'q',
'action_user',
'username']
def __init__(self, *args, **kwargs):
autor_related = Div(
FieldWithButtons(
Field('q',
placeholder=_('Pesquisar por possíveis autores para '
@ -109,110 +133,195 @@ class AutorForm(ModelForm):
StrictButton(
_('Filtrar'), css_class='btn-default btn-filtrar-autor',
type='button')),
Field('autor_related'),
css_class='hidden',
data_action='create',
data_application='AutorSearch',
data_field='autor_related')
row1 = to_row([
('tipo', 4),
('nome', 8),
(autor_related, 8),
])
autor_select = Row(to_column(('tipo', 4)),
to_column(('nome', 8)),
to_column((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.layout = SaplFormLayout(row1)
self.helper.layout = SaplFormLayout(autor_select, controle_acesso)
super(AutorForm, self).__init__(*args, **kwargs)
self.fields['autor_related'].choices = []
if self.instance and self.instance.autor_related:
self.fields['autor_related'].choices = [
(self.instance.autor_related.pk,
self.instance.autor_related)]
self.fields['action_user'].initial = 'N'
self.fields['action_user'].inline_class = True
if self.instance.pk:
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):
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)
def clean(self):
User = get_user_model()
cd = self.cleaned_data
if 'username' not in cd:
raise ValidationError(_('O username deve ser informado.'))
if 'action_user' not in cd:
raise ValidationError(_('Informe se o Autor terá usuário '
'para acesso ao Sistema.'))
qs_user = User.objects.all()
qs_autor = Autor.objects.all()
if self.instance.pk:
qs_autor = qs_autor.exclude(pk=self.instance.pk)
if self.instance.user:
qs_user = qs_user.exclude(pk=self.instance.user.pk)
if cd['action_user'] == 'C':
if User.objects.filter(username=cd['username']).exists():
raise ValidationError(
_('Já existe usuário com o username "%s". '
'Para usá-lo você deve selecionar '
'"Associar um usuário existente".') % cd['username'])
if ('senha' not in cd or 'senha_confirma' not in cd or
not cd['senha'] or not cd['senha_confirma']):
raise ValidationError(_(
'A senha e sua confirmação devem ser informadas.'))
msg = _('As senhas não conferem.')
self.valida_igualdade(cd['senha'], cd['senha_confirma'], msg)
try:
validate_password(self.cleaned_data['senha'])
except ValidationError as error:
raise ValidationError(error)
if ('email' not in cd or 'confirma_email' not in cd or
not cd['email'] or not cd['confirma_email']):
raise ValidationError(_(
'O email e sua confirmação devem ser informados.'))
msg = _('Os emails não conferem.')
self.valida_igualdade(cd['email'], cd['confirma_email'], msg)
if qs_user.filter(email=cd['email']).exists():
raise ValidationError(_('Este email já foi cadastrado.'))
if qs_autor.filter(user__email=cd['email']).exists():
raise ValidationError(
_('Já existe um Autor com este email.'))
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
@transaction.atomic
def sav(self, commit=False):
def save(self, commit=False):
print('aqui')
autor = super(AutorForm, self).save(commit)
u = get_user_model().objects.get(
username=autor.username,
email=autor.email)
user_old = autor.user if autor.user_id else None
u.set_password(self.cleaned_data['senha'])
u.is_active = False
u.save()
autor.user = u
if self.cleaned_data['action_user'] == 'A':
u = get_user_model().objects.get(
username=self.cleaned_data['username'])
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()
grupo = Group.objects.filter(name='Autor')[0]
u.groups.add(grupo)
if self.cleaned_data['action_user'] != 'N':
# 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

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.db import models, router
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 string_concat
from sapl.utils import UF, YES_NO_CHOICES, get_settings_auth_user_model
TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensivo')),
('R', _('Restritivo')))
@ -151,7 +150,9 @@ class TipoAutor(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'))

15
sapl/base/urls.py

@ -14,21 +14,18 @@ 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/', TemplateView.as_view(template_name='ajuda/index.html'),
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"),
@ -55,21 +52,13 @@ 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
]

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.contrib.auth import get_user_model
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.core.mail import send_mail
from django.core.urlresolvers import reverse
@ -16,13 +14,11 @@ 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.base.models import Autor, TipoAutor
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,
@ -38,41 +34,6 @@ 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'
@ -89,61 +50,97 @@ class AutorCrud(CrudAux):
class BaseMixin(CrudAux.BaseMixin):
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):
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
def form_valid(self, form):
# devido a implement do form o form_valid do Crud deve ser pulado
return super(CrudAux.UpdateView, self).form_valid(form)
def get_success_url(self):
# FIXME try except - testar envio de emails
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):
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)
def form_valid(self, form):
# devido a implement do form o form_valid do Crud deve ser pulado
return super(CrudAux.CreateView, self).form_valid(form)
def get_success_url(self):
pk_autor = self.object.id
try:
# FIXME try except - testar envio de emails
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})"""
kwargs={'pk': pk_autor})
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.utils.translation import ugettext_lazy as _
from model_utils import Choices

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

13
sapl/crud/base.py

@ -13,8 +13,8 @@ from django.db import models
from django.http.response import Http404
from django.utils.decorators import classonlymethod
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 string_concat
from django.views.generic import (CreateView, DeleteView, DetailView, ListView,
UpdateView)
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.utils import normalize
logger = logging.getLogger(__name__)
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
a permissão base.view_tabelas_auxiliares está definada class Meta
do model sapl.base.models.AppConfig que, naturalmente é um arquivo
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
do model sapl.base.models.AppConfig que, naturalmente é um arquivo
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
criar essa permissão apenas para o perfil Operador Geral.
"""
permission_required = ('base.view_tabelas_auxiliares',)
@ -895,8 +894,8 @@ class CrudAux(Crud):
def __init__(self, **kwargs):
super().__init__(**kwargs)
"""
Mantem as permissões individuais geradas pelo Crud através do
Modelo e adiciona a obrigatoriedade de permissão para view
Mantem as permissões individuais geradas pelo Crud através do
Modelo e adiciona a obrigatoriedade de permissão para view
tabelas auxiliares.
"""
self.permission_required = self.permission_required + \

9
sapl/materia/forms.py

@ -1,17 +1,14 @@
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
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.db import models, transaction
from django.db import models
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 +505,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',

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.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,
get_settings_auth_user_model,
restringe_tipos_de_arquivo_txt)

10
sapl/materia/urls.py

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

30
sapl/materia/views.py

@ -3,12 +3,10 @@ from random import choice
from string import ascii_letters, digits
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button
from django.conf import settings
from crispy_forms.layout import HTML
from django.contrib import messages
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.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
@ -17,17 +15,15 @@ from django.http import JsonResponse
from django.http.response import HttpResponseRedirect
from django.shortcuts import redirect
from django.template import Context, loader
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
from django.utils.http import urlsafe_base64_decode
from django.utils.translation import ugettext_lazy as _
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, Autor, TipoAutor
from sapl.base.views import montar_row_autor
from sapl.base.models import AppConfig, Autor, CasaLegislativa, TipoAutor
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,
ACTION_LIST, ACTION_UPDATE, RP_DETAIL, RP_LIST,
Crud, CrudAux, CrudDetailView, MasterDetailCrud,
@ -37,8 +33,13 @@ from sapl.materia.forms import AnexadaForm, LegislacaoCitadaForm
from sapl.norma.models import LegislacaoCitada
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
autor_modal, gerar_hash_arquivo, get_base_url,
<<<<<<< 3276eb12726b741df770d5a6ed2a9a1a83c15849
permissoes_autor, permissoes_materia,
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,
ConfirmarProposicaoForm, DocumentoAcessorioForm,
@ -48,13 +49,12 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status,
filtra_tramitacao_status)
from .models import (AcompanhamentoMateria, Anexada, Autoria,
DespachoInicial, DocumentoAcessorio, MateriaLegislativa,
Numeracao, Orgao, Origem, Proposicao, RegimeTramitacao,
Relatoria, StatusTramitacao, TipoDocumento,
TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao,
Tramitacao, UnidadeTramitacao)
from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial,
DocumentoAcessorio, MateriaLegislativa, Numeracao, Orgao,
Origem, Proposicao, RegimeTramitacao, Relatoria,
StatusTramitacao, TipoDocumento, TipoFimRelatoria,
TipoMateriaLegislativa, TipoProposicao, Tramitacao,
UnidadeTramitacao)
OrigemCrud = Crud.build(Origem, '')

5
sapl/parlamentares/models.py

@ -1,14 +1,13 @@
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, SaplGenericRelation)
SaplGenericRelation, intervalos_tem_intersecao,
restringe_tipos_de_arquivo_img)
class Legislatura(models.Model):

1
sapl/protocoloadm/forms.py

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

8
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,7 @@ 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),

7
sapl/sessao/urls.py

@ -11,10 +11,9 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
PesquisarPautaSessaoView,
PesquisarSessaoPlenariaView,
PresencaOrdemDiaView, PresencaView, ResumoView,
SessaoCrud,
TipoExpedienteCrud, TipoResultadoVotacaoCrud,
TipoSessaoCrud, VotacaoEditView,
VotacaoExpedienteEditView,
SessaoCrud, TipoExpedienteCrud,
TipoResultadoVotacaoCrud, TipoSessaoCrud,
VotacaoEditView, VotacaoExpedienteEditView,
VotacaoExpedienteView, VotacaoNominalEditView,
VotacaoNominalExpedienteEditView,
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!
SECRET_KEY = config('SECRET_KEY', default='')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = config('DEBUG', default=False, cast=bool)
@ -35,6 +34,9 @@ ALLOWED_HOSTS = ['*']
LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/login/?next='
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# SAPL business apps in dependency order
SAPL_APPS = (
'sapl.base',
@ -48,7 +50,7 @@ SAPL_APPS = (
'sapl.painel',
'sapl.protocoloadm',
'sapl.compilacao',
'sapl.api'
'sapl.api'
)
INSTALLED_APPS = (
@ -72,8 +74,8 @@ INSTALLED_APPS = (
) + SAPL_APPS
if DEBUG:
INSTALLED_APPS += ('debug_toolbar',)
# if DEBUG:
# INSTALLED_APPS += ('debug_toolbar',)
MIDDLEWARE_CLASSES = (
'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/radio.js' %}"></script>
<script src="{% static 'tinymce/tinymce.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) {
var radios = $("#div_id_autor_related .controls").html('');
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);
});
if (data.length > 1) {
$('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();
});
}
else {
$('input[name=autor_related]').prop('checked', 'checked')
$('input[name=autor_related]').prop('checked', 'checked');
$('input[name=autor_related]').closest('.radio').addClass('checked');
}
}
else{
@ -52,7 +55,6 @@ $(document).ready(function(){
active('nome');
});
}
$('#id_tipo').change(function(event) {
if (event.target.selectedIndex == 0) {
$('#id_nome, #id_q').val('');
@ -68,6 +70,24 @@ $(document).ready(function(){
var pk = $('#id_tipo').val();
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:
{% trans 'Tipo Autor' %}:
- content_type descricao:7
- content_type:4 descricao
Autor:
{% trans 'Autor' %}:
- tipo:3 nome
- username:6 cargo
- user:6 cargo
AutorCreate:
{% 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.contrib.auth import get_user_model
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.utils.translation import string_concat
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.materia.views import recuperar_materia
@ -15,7 +16,6 @@ from scripts.lista_urls import lista_urls
from .settings import SAPL_APPS
pytestmark = pytest.mark.django_db
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
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
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.static import serve as view_static_server
import sapl.api.urls
import sapl.base.urls
import sapl.comissoes.urls
import sapl.compilacao.urls
@ -31,7 +32,6 @@ 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')),

41
sapl/utils.py

@ -4,6 +4,9 @@ from unicodedata import normalize as unicodedata_normalize
import hashlib
import logging
import magic
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button
from django import forms
from django.apps import apps
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.utils.translation import ugettext_lazy as _
from floppyforms import ClearableFileInput
import magic
from sapl.settings import BASE_DIR
sapl_logger = logging.getLogger(BASE_DIR.name)
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
def normalize(txt):
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):
def __init__(self, to, fields_search=(), **kwargs):

Loading…
Cancel
Save