Browse Source

refatora autor e impl form e view para operadores

pull/3371/head
Leandro Roberto 5 years ago
parent
commit
e55e7d5d1a
  1. 227
      sapl/base/forms.py
  2. 1
      sapl/base/migrations/0046_auto_20210314_1532.py
  3. 5
      sapl/base/models.py
  4. 6
      sapl/base/urls.py
  5. 202
      sapl/base/views.py
  6. 10
      sapl/rules/apps.py
  7. 47
      sapl/templates/base/autor_form.html
  8. 5
      sapl/templates/base/layouts.yaml
  9. 5
      sapl/templates/base/subnav_autor.yaml
  10. 27
      sapl/utils.py

227
sapl/base/forms.py

@ -19,7 +19,7 @@ from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.audiencia.models import AudienciaPublica
from sapl.base.models import Autor, TipoAutor
from sapl.base.models import Autor, TipoAutor, OperadorAutor
from sapl.comissoes.models import Reuniao
from sapl.crispy_layout_mixin import (form_actions, to_column, to_row,
SaplFormHelper, SaplFormLayout)
@ -445,11 +445,6 @@ class AutorForm(ModelForm):
required=False,
label=_('Confirmar Email'))
username = forms.CharField(label=get_user_model()._meta.get_field(
get_user_model().USERNAME_FIELD).verbose_name.capitalize(),
required=False,
max_length=50)
q = forms.CharField(
max_length=120, required=False,
label='Pesquise o nome do Autor com o '
@ -459,20 +454,13 @@ class AutorForm(ModelForm):
required=False,
widget=forms.RadioSelect())
action_user = forms.ChoiceField(
label=_('Usuário com acesso ao Sistema para este Autor'),
choices=ACTION_CREATE_USERS_AUTOR_CHOICE,
widget=forms.RadioSelect())
class Meta:
model = Autor
fields = ['tipo',
'nome',
'cargo',
'autor_related',
'q',
'action_user',
'username']
'q', ]
def __init__(self, *args, **kwargs):
@ -499,73 +487,11 @@ class AutorForm(ModelForm):
css_class='radiogroup-autor-related hidden'),
12)))
row2 = Row(to_column((InlineRadios('action_user'), 8)),
to_column((Div('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')
row4 = Row(to_column((
Div(InlineRadios('status_user'),
css_class='radiogroup-status hidden'),
12))) if 'status_user' in self.Meta.fields else None
controle_acesso = [row2, row3]
if row4:
controle_acesso.append(row4)
controle_acesso = Fieldset(_('Controle de Acesso do Autor'),
*controle_acesso)
self.helper = SaplFormHelper()
self.helper.layout = SaplFormLayout(autor_select, controle_acesso)
self.helper.layout = SaplFormLayout(autor_select)
super(AutorForm, self).__init__(*args, **kwargs)
self.fields['action_user'].initial = 'N'
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.fields['autor_related'].initial = self.instance.autor_related
if self.instance.user:
self.fields['username'].initial = getattr(
self.instance.user,
get_user_model().USERNAME_FIELD)
self.fields['action_user'].initial = 'A'
self.fields['username'].label = "{} ({})".format(self.fields['username'].label,
getattr(self.instance.user,
get_user_model().USERNAME_FIELD))
if 'status_user' in self.Meta.fields:
self.fields['status_user'].initial = 'R'
self.fields['status_user'].label = "{} ({})".format(self.fields['status_user'].label,
getattr(self.instance.user,
get_user_model().USERNAME_FIELD))
self.fields['username'].widget.attrs.update({
'data': getattr(
self.instance.user,
get_user_model().USERNAME_FIELD)
if self.instance.user else ''})
if 'status_user' in self.Meta.fields:
self.fields['status_user'].widget.attrs.update({
'data': getattr(
self.instance.user,
get_user_model().USERNAME_FIELD)
if self.instance.user else ''})
def valida_igualdade(self, texto1, texto2, msg):
if texto1 != texto2:
self.logger.warning(
@ -583,73 +509,11 @@ class AutorForm(ModelForm):
User = get_user_model()
cd = self.cleaned_data
if 'action_user' not in cd or not cd['action_user']:
self.logger.warning(
'Não Informado se o Autor terá usuário '
'vinculado para acesso ao Sistema.'
)
raise ValidationError(_('Informe se o Autor terá usuário '
'vinculado para acesso ao Sistema.'))
if 'status_user' in self.Meta.fields:
if self.instance.pk and self.instance.user_id:
if getattr(
self.instance.user,
get_user_model().USERNAME_FIELD) != cd['username']:
if 'status_user' not in cd or not cd['status_user']:
self.logger.warning(
'Foi trocado ou removido o usuário deste Autor ({}), '
'mas não foi informado como se deve proceder '
'com o usuário que está sendo desvinculado? ({})'.format(
cd['username'], get_user_model().USERNAME_FIELD
)
)
raise ValidationError(
_('Foi trocado ou removido o usuário deste Autor, '
'mas não foi informado como se deve proceder '
'com o usuário que está sendo desvinculado?'))
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'] == 'A':
param_username = {get_user_model().USERNAME_FIELD: cd['username']}
if not User.objects.filter(**param_username).exists():
self.logger.warning(
'Não existe usuário com username "%s". ' % cd['username']
)
raise ValidationError(
_('Não existe usuário com username "%s". '
'Para utilizar esse username você deve selecionar '
'"Criar novo Usuário".') % cd['username'])
if cd['action_user'] != 'N':
if 'username' not in cd or not cd['username']:
self.logger.warning('Username não informado.')
raise ValidationError(_('O username deve ser informado.'))
param_username = {
'user__' + get_user_model().USERNAME_FIELD: cd['username']}
autor_vinculado = qs_autor.filter(**param_username)
if autor_vinculado.exists():
nome = autor_vinculado[0].nome
error_msg = 'Já existe um autor para este ' \
'usuário ({}): {}'.format(cd['username'], nome)
self.logger.warning(error_msg)
raise ValidationError(_(error_msg))
"""
'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']:
self.logger.warning('Tipo do Autor não selecionado.')
raise ValidationError(
@ -702,19 +566,6 @@ class AutorForm(ModelForm):
def save(self, commit=False):
autor = super(AutorForm, self).save(commit)
user_old = autor.user if autor.user_id else None
u = None
param_username = {
get_user_model().USERNAME_FIELD: self.cleaned_data['username']}
if self.cleaned_data['action_user'] == 'A':
u = get_user_model().objects.get(**param_username)
if not u.is_active:
u.is_active = settings.DEBUG
u.save()
autor.user = u
if not autor.tipo.content_type:
autor.content_type = None
autor.object_id = None
@ -726,32 +577,6 @@ class AutorForm(ModelForm):
autor.save()
# FIXME melhorar captura de grupo de Autor, levando em conta,
# no mínimo, a tradução.
grupo = Group.objects.filter(name='Autor')[0]
if self.cleaned_data['action_user'] != 'N':
autor.user.groups.add(grupo)
if user_old and user_old != autor.user:
user_old.groups.remove(grupo)
else:
if 'status_user' in self.Meta.fields:
if 'status_user' in self.cleaned_data and user_old:
if self.cleaned_data['status_user'] == 'X':
user_old.delete()
elif self.cleaned_data['status_user'] == 'D':
user_old.groups.remove(grupo)
user_old.is_active = False
user_old.save()
elif self.cleaned_data['status_user'] == 'R':
user_old.groups.remove(grupo)
elif user_old:
user_old.groups.remove(grupo)
elif user_old:
user_old.groups.remove(grupo)
return autor
@ -776,26 +601,36 @@ class AutorFilterSet(django_filters.FilterSet):
form_actions(label='Pesquisar')))
class AutorFormForAdmin(AutorForm):
status_user = forms.ChoiceField(
label=_('Bloqueio do Usuário Existente'),
choices=STATUS_USER_CHOICE,
widget=forms.RadioSelect(),
required=False,
help_text=_('Se vc está trocando ou removendo o usuário deste Autor, '
'como o Sistema deve proceder com o usuário que está sendo'
' desvinculado?'))
class OperadorAutorForm(ModelForm):
class Meta:
model = Autor
fields = ['tipo',
'nome',
'cargo',
'autor_related',
'q',
'action_user',
'username',
'status_user']
model = OperadorAutor
fields = ['user', ]
def __init__(self, *args, **kwargs):
row = to_row([('user', 12)])
self.helper = SaplFormHelper()
self.helper.layout = SaplFormLayout(
Fieldset(_('Operador'), row))
super(OperadorAutorForm, self).__init__(*args, **kwargs)
self.fields['user'].choices = [
(
u.id,
'{} - {} - {}'.format(
u.get_full_name(),
getattr(u, u.USERNAME_FIELD),
u.email
)
)
for u in get_user_model().objects.all().order_by(
get_user_model().USERNAME_FIELD
)
]
self.fields['user'].widget = forms.RadioSelect()
class RelatorioDocumentosAcessoriosFilterSet(django_filters.FilterSet):

1
sapl/base/migrations/0046_auto_20210314_1532.py

@ -42,6 +42,7 @@ class Migration(migrations.Migration):
'unique_together': {('user', 'autor')},
},
),
migrations.AddField(
model_name='autor',
name='operadores',

5
sapl/base/models.py

@ -263,7 +263,8 @@ class Autor(models.Model):
through='OperadorAutor',
through_fields=('autor', 'user'),
symmetrical=False,
related_name='autor_set')
related_name='autor_set',
verbose_name='Operadores')
tipo = models.ForeignKey(
TipoAutor,
@ -325,7 +326,7 @@ class OperadorAutor(models.Model):
@property
def user_name(self):
return '%s - %s' % (
self.user.get_display_name(),
self.user,
self.user.email)
class Meta:

6
sapl/base/urls.py

@ -9,7 +9,7 @@ from django.views.generic.base import RedirectView, TemplateView
from sapl.base.views import (AutorCrud, ConfirmarEmailView, TipoAutorCrud, get_estatistica,
PesquisarAutorView, RecuperarSenhaEmailView, RecuperarSenhaFinalizadoView,
RecuperarSenhaConfirmaView, RecuperarSenhaCompletoView, RelatorioMateriaAnoAssuntoView,
IndexView, UserCrud)
IndexView, UserCrud, OperadorAutorCrud)
from sapl.settings import MEDIA_URL, LOGOUT_REDIRECT_URL
from .apps import AppConfig
@ -58,7 +58,9 @@ urlpatterns = [
url(r'^$', IndexView.as_view(template_name='index.html'), name='sapl_index'),
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() +
OperadorAutorCrud.get_urls())),
url(r'^sistema/autor/pesquisar-autor/',
PesquisarAutorView.as_view(), name='pesquisar_autor'),

202
sapl/base/views.py

@ -8,16 +8,17 @@ import os
from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.models import Group, User
from django.contrib.auth.models import Group
from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.views import (PasswordResetView, PasswordResetConfirmView, PasswordResetCompleteView,
PasswordResetDoneView)
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied, ValidationError
from django.core.mail import send_mail
from django.db import connection
from django.db.models import Count, Q, ProtectedError, Max, F
from django.db.models import Count, Q, Max, F
from django.forms.utils import ErrorList
from django.http import Http404, HttpResponseRedirect, JsonResponse
from django.shortcuts import render, redirect
from django.shortcuts import redirect
from django.template import TemplateDoesNotExist
from django.template.loader import get_template
from django.urls import reverse, reverse_lazy
@ -25,22 +26,21 @@ from django.utils import timezone
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
from django.utils.translation import ugettext_lazy as _
from django.views.generic import (
CreateView, DetailView, DeleteView, FormView, ListView, UpdateView)
from django.views.generic import (FormView, ListView)
from django.views.generic.base import RedirectView, TemplateView
from django_filters.views import FilterView
from haystack.query import SearchQuerySet
from haystack.views import SearchView
from rest_framework.authtoken.models import Token
from sapl import settings
from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica
from sapl.base.forms import (AutorForm, AutorFormForAdmin, TipoAutorForm, AutorFilterSet, RecuperarSenhaForm,
NovaSenhaForm, UserAdminForm)
from sapl.base.models import Autor, TipoAutor
from sapl.base.forms import (AutorForm, TipoAutorForm, AutorFilterSet, RecuperarSenhaForm,
NovaSenhaForm, UserAdminForm,
OperadorAutorForm)
from sapl.base.models import Autor, TipoAutor, OperadorAutor
from sapl.comissoes.models import Comissao, Reuniao
from sapl.crud.base import CrudAux, make_pagination, Crud,\
ListWithSearchForm
ListWithSearchForm, MasterDetailCrud
from sapl.materia.models import (Anexada, Autoria, DocumentoAcessorio, MateriaEmTramitacao, MateriaLegislativa,
Proposicao, StatusTramitacao, TipoDocumento, TipoMateriaLegislativa, UnidadeTramitacao,
MateriaAssunto)
@ -61,7 +61,8 @@ from sapl.sessao.models import (
from sapl.settings import EMAIL_SEND_USER
from sapl.utils import (gerar_hash_arquivo, intervalos_tem_intersecao, mail_service_configured, parlamentares_ativos,
SEPARADOR_HASH_PROPOSICAO, show_results_filter_set, num_materias_por_tipo,
google_recaptcha_configured, sapl_as_sapn)
google_recaptcha_configured, sapl_as_sapn,
groups_remove_user, groups_add_user)
from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, RelatorioAtasFilterSet,
RelatorioAudienciaFilterSet, RelatorioDataFimPrazoTramitacaoFilterSet,
@ -193,20 +194,30 @@ class AutorCrud(CrudAux):
help_topic = 'autor'
class BaseMixin(CrudAux.BaseMixin):
list_field_names = ['tipo', 'nome', 'user']
list_field_names = ['tipo', 'nome', 'operadores']
class DetailView(CrudAux.DetailView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['subnav_template_name'] = 'base/subnav_autor.yaml'
return context
class DeleteView(CrudAux.DeleteView):
def delete(self, *args, **kwargs):
self.object = self.get_object()
if self.object.user:
# FIXME melhorar captura de grupo de Autor, levando em conta
# trad
grupo = Group.objects.filter(name='Autor')[0]
self.object.user.groups.remove(grupo)
grupo = Group.objects.filter(name='Autor')[0]
lista_operadores = list(self.object.operadores.all())
return CrudAux.DeleteView.delete(self, *args, **kwargs)
response = CrudAux.DeleteView.delete(self, *args, **kwargs)
if not Autor.objects.filter(pk=kwargs['pk']).exists():
for u in lista_operadores:
u.groups.remove(grupo)
return response
class UpdateView(CrudAux.UpdateView):
logger = logging.getLogger(__name__)
@ -217,87 +228,48 @@ class AutorCrud(CrudAux):
# devido a implement do form o form_valid do Crud deve ser pulado
return super(CrudAux.UpdateView, self).form_valid(form)
def post(self, request, *args, **kwargs):
if request.user.is_superuser:
self.form_class = AutorFormForAdmin
return CrudAux.UpdateView.post(self, request, *args, **kwargs)
def get(self, request, *args, **kwargs):
if request.user.is_superuser:
self.form_class = AutorFormForAdmin
return CrudAux.UpdateView.get(self, request, *args, **kwargs)
def get_success_url(self):
"""def get_success_url(self):
username = self.request.user.username
pk_autor = self.object.id
url_reverse = reverse('sapl.base:autor_detail',
kwargs={'pk': pk_autor})
if not mail_service_configured():
self.logger.warning(_('Registro de Autor sem envio de email. '
'Servidor de email não configurado.'))
return url_reverse
try:
self.logger.debug('user={}. Enviando email na edição '
'de Autores.'.format(username))
kwargs = {}
user = self.object.user
if not user:
return url_reverse
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.base:confirmar_email', kwargs=kwargs))
remetente = settings.EMAIL_SEND_USER
destinatario = [user.email]
send_mail(assunto, mensagem, remetente, destinatario,
fail_silently=False)
except Exception as e:
self.logger.error('user={}. Erro no envio de email na edição de'
' Autores. {}'.format(username, str(e)))
return url_reverse
return url_reverse"""
class CreateView(CrudAux.CreateView):
logger = logging.getLogger(__name__)
form_class = AutorForm
layout_key = None
def post(self, request, *args, **kwargs):
if request.user.is_superuser:
self.form_class = AutorFormForAdmin
return CrudAux.CreateView.post(self, request, *args, **kwargs)
def get(self, request, *args, **kwargs):
if request.user.is_superuser:
self.form_class = AutorFormForAdmin
return CrudAux.CreateView.get(self, request, *args, **kwargs)
def get_success_url(self):
"""def get_success_url(self):
username = self.request.user.username
pk_autor = self.object.id
url_reverse = reverse('sapl.base:autor_detail',
kwargs={'pk': pk_autor})
return url_reverse"""
class OperadorAutorCrud(MasterDetailCrud):
parent_field = 'autor'
model = OperadorAutor
help_path = 'operadorautor'
class BaseMixin(MasterDetailCrud.BaseMixin):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context[
'subnav_template_name'] = 'base/subnav_autor.yaml'
return context
def send_mail_operador(self):
username = self.request.user.username
if not mail_service_configured():
self.logger.warning(_('Registro de Autor sem envio de email. '
'Servidor de email não configurado.'))
return url_reverse
return
try:
self.logger.debug('user=' + username +
@ -306,8 +278,11 @@ class AutorCrud(CrudAux):
kwargs = {}
user = self.object.user
if not user:
return url_reverse
if not user.email:
self.logger.warning(
_('Registro de Autor sem envio de email. '
'Usuário sem um email cadastrado.'))
return
kwargs['token'] = default_token_generator.make_token(user)
kwargs['uidb64'] = urlsafe_base64_encode(force_bytes(user.pk))
@ -335,7 +310,68 @@ class AutorCrud(CrudAux):
self.logger.error(
'user=' + username + '. Erro no envio de email na criação de Autores. ' + str(e))
return url_reverse
class UpdateView(MasterDetailCrud.UpdateView):
form_class = OperadorAutorForm
# TODO tornar operador readonly na edição
def form_valid(self, form):
old = OperadorAutor.objects.get(pk=self.object.pk)
groups_remove_user(old.user, 'Autor')
response = super().form_valid(form)
groups_add_user(self.object.user, 'Autor')
self.send_mail_operador()
return response
class CreateView(MasterDetailCrud.CreateView):
form_class = OperadorAutorForm
def form_valid(self, form):
self.object = form.save(commit=False)
oper = OperadorAutor.objects.filter(
user_id=self.object.user_id,
autor_id=self.object.autor_id
).exists()
if oper:
form._errors['user'] = ErrorList([_(
'Este Operador já está registrado '
'para este Autor.')])
return self.form_invalid(form)
oper = OperadorAutor.objects.filter(
user_id=self.object.user_id).exclude(
autor_id=self.object.autor_id
).exists()
if oper:
form._errors['user'] = ErrorList([_(
'Este Operador já está registrado '
'para outro Autor.')])
return self.form_invalid(form)
response = super().form_valid(form)
groups_add_user(self.object.user, 'Autor')
self.send_mail_operador()
return response
class DeleteView(MasterDetailCrud.DeleteView):
def post(self, request, *args, **kwargs):
self.object = self.get_object()
groups_remove_user(self.object.user, 'Autor')
return MasterDetailCrud.DeleteView.post(
self, request, *args, **kwargs)
class PesquisarAutorView(FilterView):

10
sapl/rules/apps.py

@ -167,6 +167,7 @@ def get_rules():
print(group_name, e)
def groups_add_user(self, user, groups_name):
if not isinstance(groups_name, list):
groups_name = [groups_name, ]
for group_name in groups_name:
@ -211,7 +212,8 @@ def get_rules():
def update_groups(self):
print('')
print("\033[93m\033[1m{}\033[0m".format(_('Atualizando grupos do SAPL:')))
print("\033[93m\033[1m{}\033[0m".format(
_('Atualizando grupos do SAPL:')))
for rules_group in self.rules_patterns:
group_name = rules_group['group']
rules_list = rules_group['rules']
@ -242,5 +244,7 @@ def revision_pre_delete_signal(sender, **kwargs):
models.signals.post_migrate.connect(receiver=update_groups)
models.signals.post_migrate.connect(receiver=create_proxy_permissions, dispatch_uid="django.contrib.auth.management.create_permissions")
models.signals.pre_delete.connect(receiver=revision_pre_delete_signal, dispatch_uid="pre_delete_signal")
models.signals.post_migrate.connect(
receiver=create_proxy_permissions, dispatch_uid="django.contrib.auth.management.create_permissions")
models.signals.pre_delete.connect(
receiver=revision_pre_delete_signal, dispatch_uid="pre_delete_signal")

47
sapl/templates/base/autor_form.html

@ -87,58 +87,11 @@ $(document).ready(function(){
update_search(pk);
});
$('input[name=action_user]').change(function(event) {
if (!this.checked)
return;
$('#div_id_username input').prop('readonly', '');
if (event.target.value == 'N') {
$('.new_user_fields').addClass('hidden');
if ($('input[name=username]').attr('data') != '')
$('.radiogroup-status').removeClass('hidden');
if (flag_create) {
$('#div_id_username').addClass('hidden');
}
else {
$('#div_id_username input').prop('readonly', 'readonly');
}
}
else {
$('.radiogroup-status').addClass('hidden');
$('#div_id_username').removeClass('hidden');
$('.new_user_fields').addClass('hidden');
}
if (!flag_create) {
var username = $('input[name=username]');
if (username.length == 1) {
if ((event.target.value == 'A' && username.attr('data') != '' && username[0].value != username.attr('data'))
|| (event.target.value == 'C' && username.attr('data') != ''))
$('.radiogroup-status').removeClass('hidden');
}
}
});
$('input[name=username]').keyup(function(event) {
if (!flag_create)
if (this.getAttribute('data') != '' && this.value != this.getAttribute('data'))
$('.radiogroup-status').removeClass('hidden');
else
$('.radiogroup-status').addClass('hidden');
});
$('input[name=action_user]:checked').trigger('change');
if (flag_create)
$('input[name=autor_related]').closest('.radio').remove();
var pk = $('#id_tipo').val();
if (pk)
update_search(pk, $('#id_q').val().length > 0)
});
</script>
{% endblock %}

5
sapl/templates/base/layouts.yaml

@ -72,7 +72,12 @@ Autor:
{% trans 'Autor' %}:
- tipo:3 nome
- cargo
- operadores
AutorCreate:
{% trans 'Cadastro de Usuários Autores' %}:
- tipo:3 search_autor
OperadorAutor:
{% trans 'Operador de Autor' %}:
- user

5
sapl/templates/base/subnav_autor.yaml

@ -0,0 +1,5 @@
{% load i18n %}
- title: {% trans 'Início' %}
url: autor_detail
- title: {% trans 'Operadores' %}
url: operadorautor_list

27
sapl/utils.py

@ -28,7 +28,6 @@ from django.db import models
from django.db.models import Q
from django.forms import BaseForm
from django.forms.widgets import SplitDateTimeWidget
from django.urls.base import clear_url_caches
from django.utils import six, timezone
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
@ -51,6 +50,32 @@ from sapl.settings import MAX_DOC_UPLOAD_SIZE
SEPARADOR_HASH_PROPOSICAO = 'K'
def groups_remove_user(user, groups_name):
from django.contrib.auth.models import Group
if not isinstance(groups_name, list):
groups_name = [groups_name, ]
for group_name in groups_name:
if not group_name or not user.groups.filter(
name=group_name).exists():
continue
g = Group.objects.get_or_create(name=group_name)[0]
user.groups.remove(g)
def groups_add_user(user, groups_name):
from django.contrib.auth.models import Group
if not isinstance(groups_name, list):
groups_name = [groups_name, ]
for group_name in groups_name:
if not group_name or user.groups.filter(
name=group_name).exists():
continue
g = Group.objects.get_or_create(name=group_name)[0]
user.groups.add(g)
def num_materias_por_tipo(qs, attr_tipo='tipo'):
"""
:argument um QuerySet em MateriaLegislativa

Loading…
Cancel
Save