From 64c8458c90f0cdd24dc889fb58459e431661545e Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 10 Dec 2018 14:05:27 +0100 Subject: [PATCH] core: properly handle invites; audit: log invite creation and usage --- passbook/audit/models.py | 2 ++ passbook/audit/signals.py | 16 ++++++++++++++++ passbook/core/signals.py | 12 ++++++++++++ passbook/core/views/authentication.py | 23 ++++++++++++++++++++--- 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 passbook/core/signals.py diff --git a/passbook/audit/models.py b/passbook/audit/models.py index 918c65888..49fd372ae 100644 --- a/passbook/audit/models.py +++ b/passbook/audit/models.py @@ -24,6 +24,7 @@ class AuditEntry(UUIDModel): ACTION_SUSPICIOUS_REQUEST = 'suspicious_request' ACTION_SIGN_UP = 'sign_up' ACTION_PASSWORD_RESET = 'password_reset' + ACTION_INVITE_CREATED = 'invite_created' ACTION_INVITE_USED = 'invite_used' ACTIONS = ( (ACTION_LOGIN, ACTION_LOGIN), @@ -33,6 +34,7 @@ class AuditEntry(UUIDModel): (ACTION_SUSPICIOUS_REQUEST, ACTION_SUSPICIOUS_REQUEST), (ACTION_SIGN_UP, ACTION_SIGN_UP), (ACTION_PASSWORD_RESET, ACTION_PASSWORD_RESET), + (ACTION_INVITE_CREATED, ACTION_INVITE_CREATED), (ACTION_INVITE_USED, ACTION_INVITE_USED), ) diff --git a/passbook/audit/signals.py b/passbook/audit/signals.py index 5f31122be..8c623bb7a 100644 --- a/passbook/audit/signals.py +++ b/passbook/audit/signals.py @@ -4,6 +4,7 @@ from django.contrib.auth.signals import (user_logged_in, user_logged_out, from django.dispatch import receiver from passbook.audit.models import AuditEntry +from passbook.core.signals import invite_created, invite_used, user_signed_up @receiver(user_logged_in) @@ -16,6 +17,21 @@ def on_user_logged_out(sender, request, user, **kwargs): """Log successfully logout""" AuditEntry.create(AuditEntry.ACTION_LOGOUT, request) +@receiver(user_signed_up) +def on_user_signed_up(sender, request, user, **kwargs): + """Log successfully signed up""" + AuditEntry.create(AuditEntry.ACTION_SIGN_UP, request) + +@receiver(invite_created) +def on_invite_created(sender, request, invite, **kwargs): + """Log Invite creation""" + AuditEntry.create(AuditEntry.ACTION_INVITE_CREATED, request, invite_uuid=invite.uuid) + +@receiver(invite_used) +def on_invite_used(sender, request, invite, **kwargs): + """Log Invite usage""" + AuditEntry.create(AuditEntry.ACTION_INVITE_USED, request, invite_uuid=invite.uuid) + @receiver(user_login_failed) def on_user_login_failed(sender, request, user, **kwargs): """Log failed login attempt""" diff --git a/passbook/core/signals.py b/passbook/core/signals.py new file mode 100644 index 000000000..0f578e5b2 --- /dev/null +++ b/passbook/core/signals.py @@ -0,0 +1,12 @@ +"""passbook core signals""" + +from django.core.signals import Signal + +# from django.db.models.signals import post_save, pre_delete +# from django.dispatch import receiver +# from passbook.core.models import Invite, User + +user_signed_up = Signal(providing_args=['request', 'user']) +# TODO: Send this signal in admin interface +invite_created = Signal(providing_args=['request', 'invite']) +invite_used = Signal(providing_args=['request', 'invite', 'user']) diff --git a/passbook/core/views/authentication.py b/passbook/core/views/authentication.py index 3681bc89a..0b18c6fcb 100644 --- a/passbook/core/views/authentication.py +++ b/passbook/core/views/authentication.py @@ -13,6 +13,7 @@ from django.views.generic import FormView from passbook.core.forms.authentication import LoginForm, SignUpForm from passbook.core.models import Invite, User +from passbook.core.signals import invite_used, user_signed_up from passbook.lib.config import CONFIG LOGGER = getLogger(__name__) @@ -117,7 +118,10 @@ class SignUpView(UserPassesTestMixin, FormView): template_name = 'login/form.html' form_class = SignUpForm success_url = '.' + # Invite insatnce, if invite link was used _invite = None + # Instance of newly created user + _user = None # Allow only not authenticated users to login def test_func(self): @@ -150,14 +154,23 @@ class SignUpView(UserPassesTestMixin, FormView): def form_valid(self, form: SignUpForm) -> HttpResponse: """Create user""" - SignUpView.create_user(form.cleaned_data, self.request) - if self._invite: - self._invite.delete() + self._user = SignUpView.create_user(form.cleaned_data, self.request) + self.consume_invite() messages.success(self.request, _("Successfully signed up!")) LOGGER.debug("Successfully signed up %s", form.cleaned_data.get('email')) return redirect(reverse('passbook_core:auth-login')) + def consume_invite(self): + """Consume invite if an invite was used""" + if self._invite: + invite_used.send( + sender=self, + request=self.request, + invite=self._invite, + user=self._user) + self._invite.delete() + @staticmethod def create_user(data: Dict, request: HttpRequest = None) -> User: """Create user from data @@ -183,6 +196,10 @@ class SignUpView(UserPassesTestMixin, FormView): new_user.set_password(data.get('password')) new_user.save() # Send signal for other auth sources + user_signed_up.send( + sender=SignUpView, + user=new_user, + request=request) # try: # TODO: Create signal for signup # on_user_sign_up.send(