all: invites -> invitations
This commit is contained in:
parent
89c2b8d49c
commit
545795ebc6
|
@ -20,8 +20,8 @@
|
||||||
<li class="{% is_active 'passbook_admin:rules' 'passbook_admin:rule-create' 'passbook_admin:rule-update' 'passbook_admin:rule-delete' 'passbook_admin:rule-test' %}">
|
<li class="{% is_active 'passbook_admin:rules' 'passbook_admin:rule-create' 'passbook_admin:rule-update' 'passbook_admin:rule-delete' 'passbook_admin:rule-test' %}">
|
||||||
<a href="{% url 'passbook_admin:rules' %}">{% trans 'Rules' %}</a>
|
<a href="{% url 'passbook_admin:rules' %}">{% trans 'Rules' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="{% is_active 'passbook_admin:invites' 'passbook_admin:invite-create' 'passbook_admin:invite-update' 'passbook_admin:invite-delete' 'passbook_admin:invite-test' %}">
|
<li class="{% is_active 'passbook_admin:invitations' 'passbook_admin:invitation-create' 'passbook_admin:invitation-update' 'passbook_admin:invitation-delete' 'passbook_admin:invitation-test' %}">
|
||||||
<a href="{% url 'passbook_admin:invites' %}">{% trans 'Invites' %}</a>
|
<a href="{% url 'passbook_admin:invitations' %}">{% trans 'Invitations' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="#">{% trans 'Users' %}</a>
|
<a href="#">{% trans 'Users' %}</a>
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>{% trans "Invites" %}</h1>
|
<h1>{% trans "Invitations" %}</h1>
|
||||||
<a href="{% url 'passbook_admin:invite-create' %}" class="btn btn-primary">
|
<a href="{% url 'passbook_admin:invitation-create' %}" class="btn btn-primary">
|
||||||
{% trans 'Create...' %}
|
{% trans 'Create...' %}
|
||||||
</a>
|
</a>
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -23,13 +23,13 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for invite in object_list %}
|
{% for invitation in object_list %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ invite.name }}</td>
|
<td>{{ invitation.name }}</td>
|
||||||
<td>{{ invite.provider }}</td>
|
<td>{{ invitation.provider }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:invite-update' pk=invite.uuid %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:invitation-update' pk=invitation.uuid %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:invite-delete' pk=invite.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:invitation-delete' pk=invitation.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
"""passbook URL Configuration"""
|
"""passbook URL Configuration"""
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from passbook.admin.views import (applications, invites, overview, providers,
|
from passbook.admin.views import (applications, invitations, overview,
|
||||||
rules, sources)
|
providers, rules, sources)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', overview.AdministrationOverviewView.as_view(), name='overview'),
|
path('', overview.AdministrationOverviewView.as_view(), name='overview'),
|
||||||
|
@ -34,10 +34,12 @@ urlpatterns = [
|
||||||
providers.ProviderUpdateView.as_view(), name='provider-update'),
|
providers.ProviderUpdateView.as_view(), name='provider-update'),
|
||||||
path('providers/<int:pk>/delete/',
|
path('providers/<int:pk>/delete/',
|
||||||
providers.ProviderDeleteView.as_view(), name='provider-delete'),
|
providers.ProviderDeleteView.as_view(), name='provider-delete'),
|
||||||
# Invites
|
# Invitations
|
||||||
path('invites/', invites.InviteListView.as_view(), name='invites'),
|
path('invitations/', invitations.InviteListView.as_view(), name='invitations'),
|
||||||
path('invites/create/', invites.InviteCreateView.as_view(), name='invite-create'),
|
path('invitations/create/', invitations.InviteCreateView.as_view(), name='invitation-create'),
|
||||||
path('invites/<uuid:pk>/update/', invites.InviteUpdateView.as_view(), name='invite-update'),
|
path('invitations/<uuid:pk>/update/',
|
||||||
path('invites/<uuid:pk>/delete/', invites.InviteDeleteView.as_view(), name='invite-delete'),
|
invitations.InviteUpdateView.as_view(), name='invitation-update'),
|
||||||
|
path('invitations/<uuid:pk>/delete/',
|
||||||
|
invitations.InviteDeleteView.as_view(), name='invitation-delete'),
|
||||||
# path('api/v1/', include('passbook.admin.api.v1.urls'))
|
# path('api/v1/', include('passbook.admin.api.v1.urls'))
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,39 +5,39 @@ from django.utils.translation import ugettext as _
|
||||||
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
||||||
|
|
||||||
from passbook.admin.mixins import AdminRequiredMixin
|
from passbook.admin.mixins import AdminRequiredMixin
|
||||||
from passbook.core.forms.invites import InviteForm
|
from passbook.core.forms.invitations import InviteForm
|
||||||
from passbook.core.models import Invite
|
from passbook.core.models import Invite
|
||||||
|
|
||||||
|
|
||||||
class InviteListView(AdminRequiredMixin, ListView):
|
class InviteListView(AdminRequiredMixin, ListView):
|
||||||
"""Show list of all invites"""
|
"""Show list of all invitations"""
|
||||||
|
|
||||||
model = Invite
|
model = Invite
|
||||||
template_name = 'administration/invite/list.html'
|
template_name = 'administration/invitation/list.html'
|
||||||
|
|
||||||
|
|
||||||
class InviteCreateView(SuccessMessageMixin, AdminRequiredMixin, CreateView):
|
class InviteCreateView(SuccessMessageMixin, AdminRequiredMixin, CreateView):
|
||||||
"""Create new Invite"""
|
"""Create new Invite"""
|
||||||
|
|
||||||
template_name = 'generic/create.html'
|
template_name = 'generic/create.html'
|
||||||
success_url = reverse_lazy('passbook_admin:invites')
|
success_url = reverse_lazy('passbook_admin:invitations')
|
||||||
success_message = _('Successfully created Invite')
|
success_message = _('Successfully created Invite')
|
||||||
form_class = InviteForm
|
form_class = InviteForm
|
||||||
|
|
||||||
|
|
||||||
class InviteUpdateView(SuccessMessageMixin, AdminRequiredMixin, UpdateView):
|
class InviteUpdateView(SuccessMessageMixin, AdminRequiredMixin, UpdateView):
|
||||||
"""Update invite"""
|
"""Update invitation"""
|
||||||
|
|
||||||
model = Invite
|
model = Invite
|
||||||
template_name = 'generic/update.html'
|
template_name = 'generic/update.html'
|
||||||
success_url = reverse_lazy('passbook_admin:invites')
|
success_url = reverse_lazy('passbook_admin:invitations')
|
||||||
success_message = _('Successfully updated Invite')
|
success_message = _('Successfully updated Invite')
|
||||||
form_class = InviteForm
|
form_class = InviteForm
|
||||||
|
|
||||||
class InviteDeleteView(SuccessMessageMixin, AdminRequiredMixin, DeleteView):
|
class InviteDeleteView(SuccessMessageMixin, AdminRequiredMixin, DeleteView):
|
||||||
"""Delete invite"""
|
"""Delete invitation"""
|
||||||
|
|
||||||
model = Invite
|
model = Invite
|
||||||
template_name = 'generic/delete.html'
|
template_name = 'generic/delete.html'
|
||||||
success_url = reverse_lazy('passbook_admin:invites')
|
success_url = reverse_lazy('passbook_admin:invitations')
|
||||||
success_message = _('Successfully updated Invite')
|
success_message = _('Successfully updated Invite')
|
|
@ -22,6 +22,6 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='auditentry',
|
model_name='auditentry',
|
||||||
name='action',
|
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'), ('invite_used', 'invite_used')]),
|
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_used', 'invitation_used')]),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -24,8 +24,8 @@ class AuditEntry(UUIDModel):
|
||||||
ACTION_SUSPICIOUS_REQUEST = 'suspicious_request'
|
ACTION_SUSPICIOUS_REQUEST = 'suspicious_request'
|
||||||
ACTION_SIGN_UP = 'sign_up'
|
ACTION_SIGN_UP = 'sign_up'
|
||||||
ACTION_PASSWORD_RESET = 'password_reset'
|
ACTION_PASSWORD_RESET = 'password_reset'
|
||||||
ACTION_INVITE_CREATED = 'invite_created'
|
ACTION_INVITE_CREATED = 'invitation_created'
|
||||||
ACTION_INVITE_USED = 'invite_used'
|
ACTION_INVITE_USED = 'invitation_used'
|
||||||
ACTIONS = (
|
ACTIONS = (
|
||||||
(ACTION_LOGIN, ACTION_LOGIN),
|
(ACTION_LOGIN, ACTION_LOGIN),
|
||||||
(ACTION_LOGIN_FAILED, ACTION_LOGIN_FAILED),
|
(ACTION_LOGIN_FAILED, ACTION_LOGIN_FAILED),
|
||||||
|
|
|
@ -4,7 +4,8 @@ from django.contrib.auth.signals import (user_logged_in, user_logged_out,
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from passbook.audit.models import AuditEntry
|
from passbook.audit.models import AuditEntry
|
||||||
from passbook.core.signals import invite_created, invite_used, user_signed_up
|
from passbook.core.signals import (invitation_created, invitation_used,
|
||||||
|
user_signed_up)
|
||||||
|
|
||||||
|
|
||||||
@receiver(user_logged_in)
|
@receiver(user_logged_in)
|
||||||
|
@ -22,15 +23,15 @@ def on_user_signed_up(sender, request, user, **kwargs):
|
||||||
"""Log successfully signed up"""
|
"""Log successfully signed up"""
|
||||||
AuditEntry.create(AuditEntry.ACTION_SIGN_UP, request)
|
AuditEntry.create(AuditEntry.ACTION_SIGN_UP, request)
|
||||||
|
|
||||||
@receiver(invite_created)
|
@receiver(invitation_created)
|
||||||
def on_invite_created(sender, request, invite, **kwargs):
|
def on_invitation_created(sender, request, invitation, **kwargs):
|
||||||
"""Log Invite creation"""
|
"""Log Invite creation"""
|
||||||
AuditEntry.create(AuditEntry.ACTION_INVITE_CREATED, request, invite_uuid=invite.uuid)
|
AuditEntry.create(AuditEntry.ACTION_INVITE_CREATED, request, invitation_uuid=invitation.uuid)
|
||||||
|
|
||||||
@receiver(invite_used)
|
@receiver(invitation_used)
|
||||||
def on_invite_used(sender, request, invite, **kwargs):
|
def on_invitation_used(sender, request, invitation, **kwargs):
|
||||||
"""Log Invite usage"""
|
"""Log Invite usage"""
|
||||||
AuditEntry.create(AuditEntry.ACTION_INVITE_USED, request, invite_uuid=invite.uuid)
|
AuditEntry.create(AuditEntry.ACTION_INVITE_USED, request, invitation_uuid=invitation.uuid)
|
||||||
|
|
||||||
@receiver(user_login_failed)
|
@receiver(user_login_failed)
|
||||||
def on_user_login_failed(sender, request, user, **kwargs):
|
def on_user_login_failed(sender, request, user, **kwargs):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
"""passbook core invite form"""
|
"""passbook core invitation form"""
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Migration(migrations.Migration):
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Invite',
|
'verbose_name': 'Invite',
|
||||||
'verbose_name_plural': 'Invites',
|
'verbose_name_plural': 'Invitations',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -251,7 +251,7 @@ class DebugRule(Rule):
|
||||||
verbose_name_plural = _('Debug Rules')
|
verbose_name_plural = _('Debug Rules')
|
||||||
|
|
||||||
class Invite(UUIDModel):
|
class Invite(UUIDModel):
|
||||||
"""Single-use invite link"""
|
"""Single-use invitation link"""
|
||||||
|
|
||||||
created_by = models.ForeignKey('User', on_delete=models.CASCADE)
|
created_by = models.ForeignKey('User', on_delete=models.CASCADE)
|
||||||
expires = models.DateTimeField(default=None, blank=True, null=True)
|
expires = models.DateTimeField(default=None, blank=True, null=True)
|
||||||
|
@ -264,4 +264,4 @@ class Invite(UUIDModel):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
verbose_name = _('Invite')
|
verbose_name = _('Invite')
|
||||||
verbose_name_plural = _('Invites')
|
verbose_name_plural = _('Invitations')
|
||||||
|
|
|
@ -8,5 +8,5 @@ from django.core.signals import Signal
|
||||||
|
|
||||||
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
|
||||||
invite_created = Signal(providing_args=['request', 'invite'])
|
invitation_created = Signal(providing_args=['request', 'invitation'])
|
||||||
invite_used = Signal(providing_args=['request', 'invite', 'user'])
|
invitation_used = Signal(providing_args=['request', 'invitation', 'user'])
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 6.3 MiB |
|
@ -13,7 +13,7 @@ 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 Invite, User
|
||||||
from passbook.core.signals import invite_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
|
||||||
|
|
||||||
LOGGER = getLogger(__name__)
|
LOGGER = getLogger(__name__)
|
||||||
|
@ -113,13 +113,13 @@ class LogoutView(LoginRequiredMixin, View):
|
||||||
|
|
||||||
|
|
||||||
class SignUpView(UserPassesTestMixin, FormView):
|
class SignUpView(UserPassesTestMixin, FormView):
|
||||||
"""Sign up new user, optionally consume one-use invite link."""
|
"""Sign up new user, optionally consume one-use invitation link."""
|
||||||
|
|
||||||
template_name = 'login/form.html'
|
template_name = 'login/form.html'
|
||||||
form_class = SignUpForm
|
form_class = SignUpForm
|
||||||
success_url = '.'
|
success_url = '.'
|
||||||
# Invite insatnce, if invite link was used
|
# Invite insatnce, if invitation link was used
|
||||||
_invite = None
|
_invitation = None
|
||||||
# Instance of newly created user
|
# Instance of newly created user
|
||||||
_user = None
|
_user = None
|
||||||
|
|
||||||
|
@ -131,13 +131,13 @@ class SignUpView(UserPassesTestMixin, FormView):
|
||||||
return redirect(reverse('passbook_core:overview'))
|
return redirect(reverse('passbook_core:overview'))
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
"""Check if sign-up is enabled or invite link given"""
|
"""Check if sign-up is enabled or invitation link given"""
|
||||||
allowed = False
|
allowed = False
|
||||||
if 'invite' in request.GET:
|
if 'invitation' in request.GET:
|
||||||
invites = Invite.objects.filter(uuid=request.GET.get('invite'))
|
invitations = Invite.objects.filter(uuid=request.GET.get('invitation'))
|
||||||
allowed = invites.exists()
|
allowed = invitations.exists()
|
||||||
if allowed:
|
if allowed:
|
||||||
self._invite = invites.first()
|
self._invitation = invitations.first()
|
||||||
if CONFIG.y('passbook.sign_up.enabled'):
|
if CONFIG.y('passbook.sign_up.enabled'):
|
||||||
allowed = True
|
allowed = True
|
||||||
if not allowed:
|
if not allowed:
|
||||||
|
@ -155,21 +155,21 @@ class SignUpView(UserPassesTestMixin, FormView):
|
||||||
def form_valid(self, form: SignUpForm) -> HttpResponse:
|
def form_valid(self, form: SignUpForm) -> HttpResponse:
|
||||||
"""Create user"""
|
"""Create user"""
|
||||||
self._user = SignUpView.create_user(form.cleaned_data, self.request)
|
self._user = SignUpView.create_user(form.cleaned_data, self.request)
|
||||||
self.consume_invite()
|
self.consume_invitation()
|
||||||
messages.success(self.request, _("Successfully signed up!"))
|
messages.success(self.request, _("Successfully signed up!"))
|
||||||
LOGGER.debug("Successfully signed up %s",
|
LOGGER.debug("Successfully signed up %s",
|
||||||
form.cleaned_data.get('email'))
|
form.cleaned_data.get('email'))
|
||||||
return redirect(reverse('passbook_core:auth-login'))
|
return redirect(reverse('passbook_core:auth-login'))
|
||||||
|
|
||||||
def consume_invite(self):
|
def consume_invitation(self):
|
||||||
"""Consume invite if an invite was used"""
|
"""Consume invitation if an invitation was used"""
|
||||||
if self._invite:
|
if self._invitation:
|
||||||
invite_used.send(
|
invitation_used.send(
|
||||||
sender=self,
|
sender=self,
|
||||||
request=self.request,
|
request=self.request,
|
||||||
invite=self._invite,
|
invitation=self._invitation,
|
||||||
user=self._user)
|
user=self._user)
|
||||||
self._invite.delete()
|
self._invitation.delete()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_user(data: Dict, request: HttpRequest = None) -> User:
|
def create_user(data: Dict, request: HttpRequest = None) -> User:
|
||||||
|
|
|
@ -90,8 +90,8 @@ def login_process(request):
|
||||||
# # Only check if there is a connection from OAuth2 Application to product
|
# # Only check if there is a connection from OAuth2 Application to product
|
||||||
# product = remote.productextensionsaml2_set.first().product_set.first()
|
# product = remote.productextensionsaml2_set.first().product_set.first()
|
||||||
# relationship = UserAcquirableRelationship.objects.filter(user=request.user, model=product)
|
# relationship = UserAcquirableRelationship.objects.filter(user=request.user, model=product)
|
||||||
# # Product is invite_only = True and no relation with user exists
|
# # Product is invitation_only = True and no relation with user exists
|
||||||
# if product.invite_only and not relationship.exists():
|
# if product.invitation_only and not relationship.exists():
|
||||||
# access = False
|
# access = False
|
||||||
# Check if we should just autosubmit
|
# Check if we should just autosubmit
|
||||||
if remote.skip_authorization and access:
|
if remote.skip_authorization and access:
|
||||||
|
|
Reference in New Issue