diff --git a/sapl/base/forms.py b/sapl/base/forms.py index f12508c86..d2dff4e70 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -10,10 +10,10 @@ from django.contrib.auth import get_user_model from django.contrib.auth.forms import (AuthenticationForm, PasswordResetForm, SetPasswordForm) from django.contrib.auth.models import Group, User -from django.core.exceptions import ValidationError +from django.core.exceptions import ValidationError, ObjectDoesNotExist from django.db import models, transaction from django.db.models import Q -from django.forms import Form, ModelForm +from django.forms import Form, ModelForm, widgets from django.utils import timezone from django.utils.translation import string_concat from django.utils.translation import ugettext_lazy as _ @@ -38,7 +38,7 @@ from sapl.utils import (autor_label, autor_modal, ChoiceWithoutValidationField, ImageThumbnailFileInput, models_with_gr_for_model, qs_override_django_filter, RangeWidgetOverride, RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter) -from .models import AppConfig, CasaLegislativa +from .models import AppConfig, CasaLegislativa, AutorUser from operator import xor @@ -1883,3 +1883,62 @@ class RelatorioNormasPorAutorFilterSet(django_filters.FilterSet): row3, form_actions(label='Pesquisar')) ) + + +class AutorUserForm(ModelForm): + + username = forms.CharField(label=get_user_model()._meta.get_field( + get_user_model().USERNAME_FIELD).verbose_name.capitalize(), + required=True, + max_length=50) + + nome_autor = forms.CharField( + label='Autor', + widget=widgets.TextInput(attrs={'readonly': 'readonly'}) + ) + + class Meta: + model = AutorUser + exclude = ['user'] + widgets = { + 'autor': forms.HiddenInput(), + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + row1 = to_row( + [('nome_autor', 6),('username', 6),]) + row2 = to_row( + [('autor', 6)] + ) + + actions = [HTML('Cancelar')] + + self.helper = SaplFormHelper() + self.helper.layout = Layout( + Fieldset(_('Vincular Usuário ao Autor'), + row1, row2, + HTML(" "), + form_actions(more=actions) + ) + ) + + def clean(self): + cd = super().clean() + + if not self.is_valid(): + return cd + + username = cd['username'] + try: + user = User.objects.get(username=username) + except ObjectDoesNotExist as e: + raise ValidationError("Este usuário não existe.") + + if AutorUser.objects.filter(user=user).exists(): + raise ValidationError("Este usuário ({}) já está vinculado a um Autor ({}).".format( + username, AutorUser.objects.get(user=user).autor)) + + \ No newline at end of file diff --git a/sapl/base/migrations/0039_auto_20190910_1109.py b/sapl/base/migrations/0039_auto_20190910_1109.py new file mode 100644 index 000000000..62f56f741 --- /dev/null +++ b/sapl/base/migrations/0039_auto_20190910_1109.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-09-10 14:09 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('base', '0038_auto_20190604_1109'), + ] + + operations = [ + migrations.CreateModel( + name='AutorUser', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('autor', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='base.Autor', verbose_name='Autor')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='Usuário')), + ], + options={ + 'verbose_name': 'Autor - Usuário', + 'verbose_name_plural': 'Autores - Usuários', + 'ordering': ('autor__nome',), + }, + ), + migrations.AlterUniqueTogether( + name='autoruser', + unique_together=set([('autor', 'user')]), + ), + ] diff --git a/sapl/base/migrations/0040_auto_20190910_1113.py b/sapl/base/migrations/0040_auto_20190910_1113.py new file mode 100644 index 000000000..0041e4722 --- /dev/null +++ b/sapl/base/migrations/0040_auto_20190910_1113.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-09-10 14:13 +from __future__ import unicode_literals + +from django.db import migrations +from sapl.utils import get_settings_auth_user_model + +def migra_autores_usuarios(apps, schema_editor): + Autor = apps.get_model('base', 'Autor') + AutorUser = apps.get_model('base', 'AutorUser') + + for a in Autor.objects.filter(user__isnull=False): + AutorUser.objects.create(autor=a, user=a.user) + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0039_auto_20190910_1109'), + ] + + operations = [ + migrations.RunPython(migra_autores_usuarios) + ] diff --git a/sapl/base/models.py b/sapl/base/models.py index b152b1711..3b64fb33f 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -229,7 +229,7 @@ class Autor(models.Model): nome = models.CharField( max_length=120, blank=True, verbose_name=_('Nome do Autor')) - cargo = models.CharField(max_length=50, blank=True) + cargo = models.CharField(max_length=50, blank=True, verbose_name=_('Cargo')) class Meta: verbose_name = _('Autor') @@ -249,3 +249,26 @@ class Autor(models.Model): if self.user: return str(self.user.username) return '?' + + +@reversion.register() +class AutorUser(models.Model): + autor = models.ForeignKey( + Autor, + verbose_name=_('Autor'), + on_delete=models.PROTECT + ) + user = models.ForeignKey( + get_settings_auth_user_model(), + verbose_name=_('Usuário'), + on_delete=models.PROTECT + ) + + class Meta: + verbose_name = _('Autor - Usuário') + verbose_name_plural = _('Autores - Usuários') + unique_together = (('autor', 'user'), ) + ordering = ('autor__nome',) + + def __str__(self): + return str(self.autor) + ' - ' + str(self.user) \ No newline at end of file diff --git a/sapl/base/urls.py b/sapl/base/urls.py index 3f572acc9..40af9e569 100644 --- a/sapl/base/urls.py +++ b/sapl/base/urls.py @@ -39,7 +39,7 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud, ListarLegislaturaInfindavelView, ListarAnexadasCiclicasView, ListarAnexadosCiclicosView, pesquisa_textual, RelatorioHistoricoTramitacaoAdmView, RelatorioDocumentosAcessoriosView, - RelatorioNormasPorAutorView) + RelatorioNormasPorAutorView, AutorUserCrud, AutorUserFormView) app_name = AppConfig.name @@ -233,5 +233,8 @@ urlpatterns = [ url(r'^(sapl/)?sapl_documentos/props_sapl/logo_casa', LogotipoView.as_view(), name='logotipo'), + url(r'^sistema/autor/(?P\d+)/vincular-usuario/create$', + AutorUserFormView.as_view(), name='vincular-usuario-autor'), + ] + recuperar_senha + alterar_senha + admin_user + channels_url diff --git a/sapl/base/views.py b/sapl/base/views.py index 3ec3a37a6..8dcfd0ae1 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -76,8 +76,8 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm, EstatisticasAcessoNormasForm, UsuarioFilterSet, RelatorioHistoricoTramitacaoAdmFilterSet, RelatorioDocumentosAcessoriosFilterSet, - RelatorioNormasPorAutorFilterSet) -from .models import AppConfig, CasaLegislativa + RelatorioNormasPorAutorFilterSet, AutorUserForm) +from .models import AppConfig, CasaLegislativa, AutorUser def chanel_index(request): @@ -116,6 +116,9 @@ def get_casalegislativa(): return CasaLegislativa.objects.first() +AutorUserCrud = CrudAux.build(AutorUser, 'autor_user') + + class ConfirmarEmailView(TemplateView): template_name = "email/confirma.html" @@ -326,6 +329,13 @@ class AutorCrud(CrudAux): return url_reverse + class DetailView(CrudAux.DetailView): + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['autor_user'] = AutorUser.objects.filter(autor=context['object']) + return context + class RelatoriosListView(TemplateView): template_name = 'base/relatorios_list.html' @@ -2266,3 +2276,25 @@ class RelatorioNormasPorAutorView(RelatorioMixin, FilterView): ' - ' + self.request.GET['data_1']) return context + + +class AutorUserFormView(FormView): + form_class = AutorUserForm + template_name = 'base/autoruser_form.html' + success_url = '/' + + def get_initial(self): + initial = super().get_initial() + autor_pk = self.kwargs['autor_pk'] + autor = Autor.objects.get(id=autor_pk) + initial['nome_autor'] = autor.nome + initial['autor'] = autor + return initial + + def form_valid(self, form): + super().form_valid(form) + + @property + def cancel_url(self): + return reverse('sapl.base:autor_detail', + kwargs={'pk': self.kwargs['autor_pk']}) \ No newline at end of file diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index ecc64c49c..89bf73ef9 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -234,6 +234,7 @@ rules_group_geral = { [RP_ADD], __perms_publicas__), (base.TipoAutor, __base__, __perms_publicas__), (base.Autor, __base__, __perms_publicas__), + (base.AutorUser, __base__, __perms_publicas__), (protocoloadm.StatusTramitacaoAdministrativo, __base__, set()), (protocoloadm.TipoDocumentoAdministrativo, __base__, set()), diff --git a/sapl/templates/base.html b/sapl/templates/base.html index 8eaaede66..000a74cdf 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -63,7 +63,7 @@