Skip to content

Commit

Permalink
Merge pull request #49 from copperleaftech/accept-invite-after-signup
Browse files Browse the repository at this point in the history
Add option to accept invite after signup for allauth
  • Loading branch information
bee-keeper committed Oct 19, 2016
2 parents f188c41 + 5f7e3a7 commit 765147a
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 14 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ Bulk invites are supported via JSON. Post a list of comma separated emails to t

Boolean. If confirmations can be accepted via a `GET` request.

* `INVITATIONS_ACCEPT_INVITE_AFTER_SIGNUP` (default=`False`)

Boolean. If `True`, invitations will be accepted after users finish signup.
If `False`, invitations will be accepted right after the invitation link is clicked.
Note that this only works with Allauth for now, which means `ACCOUNT_ADAPTER` has to be
`'invitations.models.InvitationsAdapter'`.

* `INVITATIONS_GONE_ON_ACCEPT_ERROR` (default=`True`)

Boolean. If `True`, return an HTTP 410 GONE response if the invitation key
Expand Down
5 changes: 5 additions & 0 deletions invitations/app_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ def CONFIRM_INVITE_ON_GET(self):
""" Simple get request confirms invite """
return self._setting('CONFIRM_INVITE_ON_GET', True)

@property
def ACCEPT_INVITE_AFTER_SIGNUP(self):
""" Accept the invitation after the user finished signup. """
return self._setting('ACCEPT_INVITE_AFTER_SIGNUP', False)

@property
def GONE_ON_ACCEPT_ERROR(self):
"""
Expand Down
4 changes: 4 additions & 0 deletions invitations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def __str__(self):
if hasattr(settings, 'ACCOUNT_ADAPTER'):
if settings.ACCOUNT_ADAPTER == 'invitations.models.InvitationsAdapter':
from allauth.account.adapter import DefaultAccountAdapter
from allauth.account.signals import user_signed_up

class InvitationsAdapter(DefaultAccountAdapter):

Expand All @@ -96,3 +97,6 @@ def is_open_for_signup(self, request):
else:
# Site is open to signup
return True

def get_user_signed_up_signal(self):
return user_signed_up
32 changes: 32 additions & 0 deletions invitations/tests/allauth/test_allauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,38 @@ def test_accept_invite_allauth(self, method):
email='email@example.com')
self.assertTrue(allauth_email_obj.verified)

@parameterized.expand([
('get'),
('post'),
])
@override_settings(
INVITATIONS_ACCEPT_INVITE_AFTER_SIGNUP=True,
)
def test_accept_invite_accepted_invitation_after_signup(self, method):
client_with_method = getattr(self.client, method)
resp = client_with_method(
reverse('invitations:accept-invite',
kwargs={'key': self.invitation.key}), follow=True)
self.assertEqual(resp.status_code, 200)

invite = Invitation.objects.get(email='email@example.com')
self.assertEqual(invite.inviter, self.user)
self.assertFalse(invite.accepted)
self.assertEqual(
resp.request['PATH_INFO'], reverse('account_signup'))
form = resp.context_data['form']
self.assertEqual('email@example.com', form.fields['email'].initial)

resp = self.client.post(
reverse('account_signup'),
{'email': 'email@example.com',
'username': 'username',
'password1': 'password',
'password2': 'password'
})
invite = Invitation.objects.get(email='email@example.com')
self.assertTrue(invite.accepted)

def test_fetch_adapter(self):
self.assertIsInstance(self.adapter, InvitationsAdapter)

Expand Down
47 changes: 33 additions & 14 deletions invitations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@

from .forms import InviteForm, CleanEmailMixin
from .models import Invitation
from . import signals
from .exceptions import AlreadyInvited, AlreadyAccepted, UserRegisteredEmail
from .app_settings import app_settings
from .adapters import get_invitations_adapter
from .signals import invite_accepted


class SendInvite(LoginRequiredMixin, FormView):
Expand Down Expand Up @@ -138,22 +138,16 @@ def post(self, *args, **kwargs):
# Redirect to sign-up since they might be able to register anyway.
return redirect(app_settings.SIGNUP_REDIRECT)

# The invitation is valid! Accept it and let them finish the sign-up.
invitation.accepted = True
invitation.save()
# The invitation is valid.
# Mark it as accepted now if ACCEPT_INVITE_AFTER_SIGNUP is False.
if not app_settings.ACCEPT_INVITE_AFTER_SIGNUP:
accept_invitation(invitation=invitation,
request=self.request,
signal_sender=self.__class__)

get_invitations_adapter().stash_verified_email(
self.request, invitation.email)

signals.invite_accepted.send(sender=self.__class__,
request=self.request,
email=invitation.email)

get_invitations_adapter().add_message(
self.request,
messages.SUCCESS,
'invitations/messages/invite_accepted.txt',
{'email': invitation.email})

return redirect(app_settings.SIGNUP_REDIRECT)

def get_object(self, queryset=None):
Expand All @@ -166,3 +160,28 @@ def get_object(self, queryset=None):

def get_queryset(self):
return Invitation.objects.all()


def accept_invitation(invitation, request, signal_sender):
invitation.accepted = True
invitation.save()

invite_accepted.send(sender=signal_sender, email=invitation.email)

get_invitations_adapter().add_message(
request,
messages.SUCCESS,
'invitations/messages/invite_accepted.txt',
{'email': invitation.email})


def accept_invite_after_signup(sender, request, user, **kwargs):
invitation = Invitation.objects.filter(email=user.email).first()
if invitation:
accept_invitation(invitation=invitation,
request=request,
signal_sender=Invitation)

if app_settings.ACCEPT_INVITE_AFTER_SIGNUP:
signed_up_signal = get_invitations_adapter().get_user_signed_up_signal()
signed_up_signal.connect(accept_invite_after_signup)

0 comments on commit 765147a

Please sign in to comment.