all: fully switch to Invitation
This commit is contained in:
parent
57f285ae54
commit
d0099edac4
|
@ -35,9 +35,10 @@ urlpatterns = [
|
||||||
path('providers/<int:pk>/delete/',
|
path('providers/<int:pk>/delete/',
|
||||||
providers.ProviderDeleteView.as_view(), name='provider-delete'),
|
providers.ProviderDeleteView.as_view(), name='provider-delete'),
|
||||||
# Invitations
|
# Invitations
|
||||||
path('invitations/', invitations.InviteListView.as_view(), name='invitations'),
|
path('invitations/', invitations.InvitationListView.as_view(), name='invitations'),
|
||||||
path('invitations/create/', invitations.InviteCreateView.as_view(), name='invitation-create'),
|
path('invitations/create/',
|
||||||
|
invitations.InvitationCreateView.as_view(), name='invitation-create'),
|
||||||
path('invitations/<uuid:pk>/delete/',
|
path('invitations/<uuid:pk>/delete/',
|
||||||
invitations.InviteDeleteView.as_view(), name='invitation-delete'),
|
invitations.InvitationDeleteView.as_view(), name='invitation-delete'),
|
||||||
# path('api/v1/', include('passbook.admin.api.v1.urls'))
|
# path('api/v1/', include('passbook.admin.api.v1.urls'))
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,38 +1,40 @@
|
||||||
"""passbook Invite administration"""
|
"""passbook Invitation administration"""
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
from django.views.generic import CreateView, DeleteView, ListView
|
||||||
|
|
||||||
from passbook.admin.mixins import AdminRequiredMixin
|
from passbook.admin.mixins import AdminRequiredMixin
|
||||||
from passbook.core.forms.invitations import InviteForm
|
from passbook.core.forms.invitations import InvitationForm
|
||||||
from passbook.core.models import Invite
|
from passbook.core.models import Invitation
|
||||||
|
|
||||||
|
|
||||||
class InviteListView(AdminRequiredMixin, ListView):
|
class InvitationListView(AdminRequiredMixin, ListView):
|
||||||
"""Show list of all invitations"""
|
"""Show list of all invitations"""
|
||||||
|
|
||||||
model = Invite
|
model = Invitation
|
||||||
template_name = 'administration/invitation/list.html'
|
template_name = 'administration/invitation/list.html'
|
||||||
|
|
||||||
|
|
||||||
class InviteCreateView(SuccessMessageMixin, AdminRequiredMixin, CreateView):
|
class InvitationCreateView(SuccessMessageMixin, AdminRequiredMixin, CreateView):
|
||||||
"""Create new Invite"""
|
"""Create new Invitation"""
|
||||||
|
|
||||||
template_name = 'generic/create.html'
|
template_name = 'generic/create.html'
|
||||||
success_url = reverse_lazy('passbook_admin:invitations')
|
success_url = reverse_lazy('passbook_admin:invitations')
|
||||||
success_message = _('Successfully created Invite')
|
success_message = _('Successfully created Invitation')
|
||||||
form_class = InviteForm
|
form_class = InvitationForm
|
||||||
|
|
||||||
def get_initial(self):
|
def form_valid(self, form):
|
||||||
return {
|
obj = form.save(commit=False)
|
||||||
'created_by': self.request.user
|
obj.created_by = self.request.user
|
||||||
}
|
obj.save()
|
||||||
|
return HttpResponseRedirect(self.success_url)
|
||||||
|
|
||||||
class InviteDeleteView(SuccessMessageMixin, AdminRequiredMixin, DeleteView):
|
class InvitationDeleteView(SuccessMessageMixin, AdminRequiredMixin, DeleteView):
|
||||||
"""Delete invitation"""
|
"""Delete invitation"""
|
||||||
|
|
||||||
model = Invite
|
model = Invitation
|
||||||
template_name = 'generic/delete.html'
|
template_name = 'generic/delete.html'
|
||||||
success_url = reverse_lazy('passbook_admin:invitations')
|
success_url = reverse_lazy('passbook_admin:invitations')
|
||||||
success_message = _('Successfully updated Invite')
|
success_message = _('Successfully updated Invitation')
|
||||||
|
|
18
passbook/audit/migrations/0004_auto_20181210_1348.py
Normal file
18
passbook/audit/migrations/0004_auto_20181210_1348.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.1.4 on 2018-12-10 13:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('passbook_audit', '0003_auto_20181210_1213'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='auditentry',
|
||||||
|
name='action',
|
||||||
|
field=models.TextField(choices=[('login', 'login'), ('login_failed', 'login_failed'), ('logout', 'logout'), ('authorize_application', 'authorize_application'), ('suspicious_request', 'suspicious_request'), ('sign_up', 'sign_up'), ('password_reset', 'password_reset'), ('invitation_created', 'invitation_created'), ('invitation_used', 'invitation_used')]),
|
||||||
|
),
|
||||||
|
]
|
|
@ -25,12 +25,12 @@ def on_user_signed_up(sender, request, user, **kwargs):
|
||||||
|
|
||||||
@receiver(invitation_created)
|
@receiver(invitation_created)
|
||||||
def on_invitation_created(sender, request, invitation, **kwargs):
|
def on_invitation_created(sender, request, invitation, **kwargs):
|
||||||
"""Log Invite creation"""
|
"""Log Invitation creation"""
|
||||||
AuditEntry.create(AuditEntry.ACTION_INVITE_CREATED, request, invitation_uuid=invitation.uuid)
|
AuditEntry.create(AuditEntry.ACTION_INVITE_CREATED, request, invitation_uuid=invitation.uuid)
|
||||||
|
|
||||||
@receiver(invitation_used)
|
@receiver(invitation_used)
|
||||||
def on_invitation_used(sender, request, invitation, **kwargs):
|
def on_invitation_used(sender, request, invitation, **kwargs):
|
||||||
"""Log Invite usage"""
|
"""Log Invitation usage"""
|
||||||
AuditEntry.create(AuditEntry.ACTION_INVITE_USED, request, invitation_uuid=invitation.uuid)
|
AuditEntry.create(AuditEntry.ACTION_INVITE_USED, request, invitation_uuid=invitation.uuid)
|
||||||
|
|
||||||
@receiver(user_login_failed)
|
@receiver(user_login_failed)
|
||||||
|
|
|
@ -2,22 +2,21 @@
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from passbook.core.models import Invite
|
from passbook.core.models import Invitation
|
||||||
|
|
||||||
|
|
||||||
class InviteForm(forms.ModelForm):
|
class InvitationForm(forms.ModelForm):
|
||||||
"""InviteForm"""
|
"""InvitationForm"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = Invite
|
model = Invitation
|
||||||
fields = ['created_by', 'expires', 'fixed_username', 'fixed_email']
|
fields = ['expires', 'fixed_username', 'fixed_email']
|
||||||
labels = {
|
labels = {
|
||||||
'fixed_username': "Force user's username (optional)",
|
'fixed_username': "Force user's username (optional)",
|
||||||
'fixed_email': "Force user's email (optional)",
|
'fixed_email': "Force user's email (optional)",
|
||||||
}
|
}
|
||||||
widgets = {
|
widgets = {
|
||||||
'created_by': forms.Select(attrs={'disabled': 'disabled'}),
|
|
||||||
'fixed_username': forms.TextInput(),
|
'fixed_username': forms.TextInput(),
|
||||||
'fixed_email': forms.TextInput(),
|
'fixed_email': forms.TextInput(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ class Migration(migrations.Migration):
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Invite',
|
name='Invitation',
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||||
('expires', models.DateTimeField(blank=True, default=None, null=True)),
|
('expires', models.DateTimeField(blank=True, default=None, null=True)),
|
||||||
|
@ -24,7 +24,7 @@ class Migration(migrations.Migration):
|
||||||
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Invite',
|
'verbose_name': 'Invitation',
|
||||||
'verbose_name_plural': 'Invitations',
|
'verbose_name_plural': 'Invitations',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -8,6 +8,7 @@ from uuid import uuid4
|
||||||
import reversion
|
import reversion
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from model_utils.managers import InheritanceManager
|
from model_utils.managers import InheritanceManager
|
||||||
|
|
||||||
|
@ -250,7 +251,7 @@ class DebugRule(Rule):
|
||||||
verbose_name = _('Debug Rule')
|
verbose_name = _('Debug Rule')
|
||||||
verbose_name_plural = _('Debug Rules')
|
verbose_name_plural = _('Debug Rules')
|
||||||
|
|
||||||
class Invite(UUIDModel):
|
class Invitation(UUIDModel):
|
||||||
"""Single-use invitation link"""
|
"""Single-use invitation link"""
|
||||||
|
|
||||||
created_by = models.ForeignKey('User', on_delete=models.CASCADE)
|
created_by = models.ForeignKey('User', on_delete=models.CASCADE)
|
||||||
|
@ -258,10 +259,15 @@ class Invite(UUIDModel):
|
||||||
fixed_username = models.TextField(blank=True, default=None)
|
fixed_username = models.TextField(blank=True, default=None)
|
||||||
fixed_email = models.TextField(blank=True, default=None)
|
fixed_email = models.TextField(blank=True, default=None)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def link(self):
|
||||||
|
"""Get link to use invitation"""
|
||||||
|
return reverse_lazy('passbook_core:auth-sign-up') + '?invitation=%s' % self.uuid
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Invite %s created by %s" % (self.uuid, self.created_by)
|
return "Invitation %s created by %s" % (self.uuid, self.created_by)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
verbose_name = _('Invite')
|
verbose_name = _('Invitation')
|
||||||
verbose_name_plural = _('Invitations')
|
verbose_name_plural = _('Invitations')
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.core.signals import Signal
|
||||||
|
|
||||||
# from django.db.models.signals import post_save, pre_delete
|
# from django.db.models.signals import post_save, pre_delete
|
||||||
# from django.dispatch import receiver
|
# from django.dispatch import receiver
|
||||||
# from passbook.core.models import Invite, User
|
# from passbook.core.models import Invitation, User
|
||||||
|
|
||||||
user_signed_up = Signal(providing_args=['request', 'user'])
|
user_signed_up = Signal(providing_args=['request', 'user'])
|
||||||
# TODO: Send this signal in admin interface
|
# TODO: Send this signal in admin interface
|
||||||
|
|
|
@ -12,7 +12,7 @@ from django.views import View
|
||||||
from django.views.generic import FormView
|
from django.views.generic import FormView
|
||||||
|
|
||||||
from passbook.core.forms.authentication import LoginForm, SignUpForm
|
from passbook.core.forms.authentication import LoginForm, SignUpForm
|
||||||
from passbook.core.models import Invite, User
|
from passbook.core.models import Invitation, User
|
||||||
from passbook.core.signals import invitation_used, user_signed_up
|
from passbook.core.signals import invitation_used, user_signed_up
|
||||||
from passbook.lib.config import CONFIG
|
from passbook.lib.config import CONFIG
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ class SignUpView(UserPassesTestMixin, FormView):
|
||||||
template_name = 'login/form.html'
|
template_name = 'login/form.html'
|
||||||
form_class = SignUpForm
|
form_class = SignUpForm
|
||||||
success_url = '.'
|
success_url = '.'
|
||||||
# Invite insatnce, if invitation link was used
|
# Invitation insatnce, if invitation link was used
|
||||||
_invitation = None
|
_invitation = None
|
||||||
# Instance of newly created user
|
# Instance of newly created user
|
||||||
_user = None
|
_user = None
|
||||||
|
@ -134,7 +134,7 @@ class SignUpView(UserPassesTestMixin, FormView):
|
||||||
"""Check if sign-up is enabled or invitation link given"""
|
"""Check if sign-up is enabled or invitation link given"""
|
||||||
allowed = False
|
allowed = False
|
||||||
if 'invitation' in request.GET:
|
if 'invitation' in request.GET:
|
||||||
invitations = Invite.objects.filter(uuid=request.GET.get('invitation'))
|
invitations = Invitation.objects.filter(uuid=request.GET.get('invitation'))
|
||||||
allowed = invitations.exists()
|
allowed = invitations.exists()
|
||||||
if allowed:
|
if allowed:
|
||||||
self._invitation = invitations.first()
|
self._invitation = invitations.first()
|
||||||
|
@ -145,6 +145,16 @@ class SignUpView(UserPassesTestMixin, FormView):
|
||||||
return redirect(reverse('passbook_core:auth-login'))
|
return redirect(reverse('passbook_core:auth-login'))
|
||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
if self._invitation:
|
||||||
|
initial = {}
|
||||||
|
if self._invitation.fixed_username:
|
||||||
|
initial['username'] = self._invitation.fixed_username
|
||||||
|
if self._invitation.fixed_email:
|
||||||
|
initial['e-mail'] = self._invitation.fixed_email
|
||||||
|
return initial
|
||||||
|
return super().get_initial()
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs['config'] = CONFIG.get('passbook')
|
kwargs['config'] = CONFIG.get('passbook')
|
||||||
kwargs['is_login'] = True
|
kwargs['is_login'] = True
|
||||||
|
|
Reference in a new issue