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 @@