Browse Source

Add procedimento na alteração de username de Autor

Na edição de Autores foi adicionado o tratamento por opção do usuário do
que deve ser feito com o usuário que está sendo desvinculado no caso de
uma alteração do username de um Autor.

Foram dadas três opções:

1) Apenas retirar Perfil de Autor do Usuário que está sendo desvinculado
2) Retirar Perfil de Autor e desativar Usuário que está sendo desvinculado
3) Excluir Usuário
pull/739/head
LeandroRoberto 8 years ago
parent
commit
9db646df86
  1. 82
      sapl/base/forms.py
  2. 6
      sapl/materia/views.py
  3. 5
      sapl/templates/base.html
  4. 46
      sapl/templates/base/autor_form.html
  5. 7
      sapl/templates/bootstrap3/layout/radioselect.html
  6. 12
      sapl/templates/bootstrap3/layout/radioselect_inline.html
  7. 12
      scripts/inicializa_grupos_autorizacoes.py

82
sapl/base/forms.py

@ -12,7 +12,7 @@ from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.db import models, transaction
from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext_lazy as _, string_concat
import django_filters
from sapl.base.models import Autor, TipoAutor
@ -34,6 +34,15 @@ ACTION_CREATE_USERS_AUTOR_CHOICE = [
]
STATUS_USER_CHOICE = [
('R', _('Apenas retirar Perfil de Autor do Usuário que está sendo'
' desvinculado')),
('D', _('Retirar Perfil de Autor e desativar Usuário que está sendo'
' desvinculado')),
('X', _('Excluir Usuário')),
]
class TipoAutorForm(ModelForm):
content_type = forms.ModelChoiceField(
@ -97,7 +106,8 @@ class AutorForm(ModelForm):
required=False,
label=_('Confirmar Email'))
username = forms.CharField(
username = forms.CharField(label=get_user_model()._meta.get_field(
'username').verbose_name.capitalize(),
required=False,
max_length=50)
@ -111,10 +121,19 @@ class AutorForm(ModelForm):
widget=forms.RadioSelect())
action_user = forms.ChoiceField(
label=_('Usuário de acesso ao Sistema para este Autor'),
label=_('Usuário com acesso ao Sistema para este Autor'),
choices=ACTION_CREATE_USERS_AUTOR_CHOICE,
widget=forms.RadioSelect())
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 Meta:
model = Autor
fields = ['tipo',
@ -150,16 +169,19 @@ class AutorForm(ModelForm):
12)))
row2 = Row(to_column((InlineRadios('action_user'), 8)),
to_column(('username', 4)))
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)))
controle_acesso = Fieldset(
_('Controle de Acesso do Autor'),
row2, row3
row2, row3, row4
)
self.helper = FormHelper()
@ -168,7 +190,6 @@ class AutorForm(ModelForm):
super(AutorForm, self).__init__(*args, **kwargs)
self.fields['action_user'].initial = 'N'
self.fields['action_user'].inline_class = True
if self.instance.pk:
if self.instance.autor_related:
@ -180,6 +201,13 @@ class AutorForm(ModelForm):
if self.instance.user:
self.fields['username'].initial = self.instance.user.username
self.fields['action_user'].initial = 'A'
self.fields['status_user'].initial = 'R'
self.fields['username'].label = string_concat(
self.fields['username'].label,
' (', self.instance.user.username, ')')
self.fields['username'].widget.attrs.update({
'data': self.instance.user.username
if self.instance.user else ''})
def valida_igualdade(self, texto1, texto2, msg):
if texto1 != texto2:
@ -190,12 +218,20 @@ class AutorForm(ModelForm):
User = get_user_model()
cd = self.cleaned_data
if 'username' not in cd:
if 'username' not in cd or not cd['username']:
raise ValidationError(_('O username deve ser informado.'))
if 'action_user' not in cd:
if 'action_user' not in cd or not cd['action_user']:
raise ValidationError(_('Informe se o Autor terá usuário '
'para acesso ao Sistema.'))
'vinculado para acesso ao Sistema.'))
if self.instance.pk and self.instance.user_id:
if self.instance.user.username != cd['username']:
if 'status_user' not in cd or cd['status_user']:
raise ValidationError(
_('Foi trocado ou removido o usuário deste Autor, '
'mas não foi informado com se deve proceder com o '
'usuário que está sendo desvinculado?'))
qs_user = User.objects.all()
qs_autor = Autor.objects.all()
@ -209,7 +245,7 @@ class AutorForm(ModelForm):
if User.objects.filter(username=cd['username']).exists():
raise ValidationError(
_('Já existe usuário com o username "%s". '
'Para usá-lo você deve selecionar '
'Para utilizar esse username você deve selecionar '
'"Associar um usuário existente".') % cd['username'])
if ('senha' not in cd or 'senha_confirma' not in cd or
@ -242,7 +278,7 @@ class AutorForm(ModelForm):
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 '
'Para utilizar esse username você deve selecionar '
'"Criar novo Usuário".') % cd['username'])
if cd['action_user'] != 'N':
@ -292,10 +328,10 @@ class AutorForm(ModelForm):
user_old = autor.user if autor.user_id else None
u = None
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'],
@ -318,15 +354,29 @@ class AutorForm(ModelForm):
autor.save()
if self.cleaned_data['action_user'] != 'N':
# FIXME melhorar captura de grupo de Autor, levando em conta
# tradução
# 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.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)
else:
user_old.groups.remove(grupo)
return autor

6
sapl/materia/views.py

@ -313,6 +313,12 @@ class ConfirmarProposicao(PermissionRequiredMixin, CreateView):
class ProposicaoCrud(Crud):
"""
TODO: Entre outros comportamento gerais, mesmo que um usuário tenha
Perfil de Autor o Crud de proposição não deverá permitir acesso a
proposições. O acesso deve ser permitido se existe um Autor registrado
e vinculado ao usuário. Essa tarefa deve ser realizada nas Tabelas Aux.
"""
model = Proposicao
help_path = ''

5
sapl/templates/base.html

@ -277,6 +277,9 @@
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="{% static 'jquery/dist/jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'bootstrap-sass/assets/javascripts/bootstrap.min.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 'jquery-ui/jquery-ui.min.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-ui/ui/i18n/datepicker-pt-BR.js' %}"></script>
@ -284,8 +287,6 @@
<script type="text/javascript" src="{% static 'js/jquery.runner.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-mask-plugin/dist/jquery.mask.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 src="{% static 'tinymce/tinymce.min.js' %}"></script>
<script type="text/javascript" src="{% static 'jsdiff/diff.min.js' %}"></script>

46
sapl/templates/base/autor_form.html

@ -5,6 +5,11 @@
<script type="text/javascript">
$(document).ready(function(){
var flag_create = false;
if (location.href.indexOf('create') > 0) {
$('.radiogroup-status').remove();
flag_create = true
}
var active = function(str) {
if (str == 'nome') {
$('#id_nome, #id_q').val('');
@ -77,14 +82,49 @@ $(document).ready(function(){
update_search(pk);
});
$('input[name=action_user]').change(function(event) {
if (event.target.value == 'C')
if (!this.checked)
return;
$('#div_id_username input').prop('readonly', '');
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');
$('input[name=username]').val('');
}
else 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');

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

@ -3,15 +3,14 @@
<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 }}">
<label class="radio {% if inline_class %}radio-{{ inline_class }}{% 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 }}
<input type="radio"{% if 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 %}

12
sapl/templates/bootstrap3/layout/radioselect_inline.html

@ -0,0 +1,12 @@
{% if field.is_hidden %}
{{ field }}
{% else %}
<div id="div_{{ field.auto_id }}" class="form-group{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label %}
<label for="{{ field.auto_id }}" class="control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
{% include 'bootstrap3/layout/radioselect.html' %}
</div>
{% endif %}

12
scripts/inicializa_grupos_autorizacoes.py

@ -120,8 +120,16 @@ class InicializaGruposAutorizacoes():
for p in perms_autor:
grupo.permissions.add(p)
nome_usuario = 'operador_autor'
self.cria_usuario(nome_usuario, grupo)
"""
Mesmo para teste, um usuário com perfil Autor criado via /admin
não deverá ser criado pois esse é um papel do operador_geral fazer
nas tabelas auxiliares.
A tentativa de acesso a qualquer container (hoje apenas proposições)
do SAPL de Usuários com perfil Autor mas sem um Autor cadastrado
nas tabelas auxiliares será negado e notificado via front-end.
"""
# nome_usuario = 'operador_autor'
# self.cria_usuario(nome_usuario, grupo)
def __call__(self):
self.cria_grupos_permissoes()

Loading…
Cancel
Save