Skip to content

Commit

Permalink
Merge pull request #22 from bee-keeper/devel
Browse files Browse the repository at this point in the history
Added inviter to invitation
  • Loading branch information
bee-keeper committed Nov 26, 2015
2 parents d38f621 + e6aacec commit 5dd2263
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 10 deletions.
93 changes: 89 additions & 4 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,70 @@ Changelog
%%version%% (unreleased)
------------------------

- Added inviter to invitation. [bee_keeper]

- Merge pull request #21 from bee-keeper/devel. [bee-keeper]

Support for django1.9

- Testing for django1.9 and python 3.5. [bee_keeper]

- Merge pull request #20 from bee-keeper/devel. [bee-keeper]

Added json endpoint for invites

- Added json endpoint for invites. [bee_keeper]

- Merge pull request #19 from bee-keeper/devel. [bee-keeper]

Made accept trailing slash optional

- Made trailing slash optional and added flake8 to CI. [bee_keeper]

Bumped to version 1.3

- Update models.py. [bee-keeper]

- Roadmap. [bee_keeper]

1.2 (2015-08-29)
----------------

- Test coverage done, ready for 1.2 release. [bee_keeper]

- Dropping support for python 3.2. [bee_keeper]

- site_name passed to tpl rather than current_site obj
- Dropping support for python 3.2. [bee_keeper]

- Accepted signal sender is now invitations view
- Signal test coverage, tweaking tox. [bee_keeper]

- Signal test coverage [bee_keeper]
- Coverage. [bee-keeper]

- Tox+travis. [bee-keeper]

- Tox. [bee-keeper]

- Tox+travis. [bee-keeper]

- Testing tox+travis. [bee-keeper]

- Testing tox+travis. [bee-keeper]

- Tox file. [bee_keeper]

- Py3 fix. [bee_keeper]

- Test for signup redirect. [bee_keeper]

- More Tests and bug fixes. [bee-keeper]
- Update README.md. [bee-keeper]

- Py 3.2. [bee_keeper]

- Py 3.2. [bee-keeper]

- Print. [bee-keeper]

- Tests and bug fixes. [bee-keeper]

1.1 (2015-08-05)
----------------
Expand All @@ -42,8 +93,14 @@ Changelog

- Changing travis supported versions. [bee_keeper]

- Travis. [bee_keeper]

- Travis. [bee_keeper]

- Remove 2.6 from testing. [bee_keeper]

- Requirements and changelog. [bee_keeper]

- Test settings. [bee_keeper]

- Requirements.txt. [bee_keeper]
Expand All @@ -62,6 +119,18 @@ Changelog

- Update views.py. [bee-keeper]

- Teavis. [bee_keeper]

- Travis. [bee_keeper]

- Travis. [bee_keeper]

- Travis. [bee_keeper]

- Travis. [bee_keeper]

- Travis. [bee_keeper]

- App settings. [bee_keeper]

- Merge pull request #6 from simonv3/master. [bee-keeper]
Expand Down Expand Up @@ -96,12 +165,26 @@ Changelog

- Py3.2 format. [bee_keeper]

- .travis.yml. [bee_keeper]

- .travis.yml. [bee_keeper]

- .travis.yml. [bee_keeper]

- .travs.yml. [bee_keeper]

- .travis.yml. [bee_keeper]

- .travis.yml. [bee_keeper]

- Test settings and more test coverage. [bee_keeper]

- Tests and refactoring. [bee_keeper]

- New style migrations. [bee_keeper]

- 1.7 style migrations. [bee_keeper]

0.12 (2014-11-30)
-----------------

Expand Down Expand Up @@ -129,6 +212,8 @@ Changelog

- Template path. [bee_keeper]

- Template path. [bee_keeper]

- Name changes. [bee_keeper]


5 changes: 5 additions & 0 deletions invitations/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ class AlreadyInvited(Exception):
class AlreadyAccepted(Exception):
"""User has already accepted an invitation"""
pass


class UserRegisteredEmail(Exception):
"""This email is already registered by a site user """
pass
9 changes: 7 additions & 2 deletions invitations/forms.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import get_user_model

from allauth.account.adapter import get_adapter

from .models import Invitation
from .exceptions import AlreadyInvited, AlreadyAccepted
from .exceptions import AlreadyInvited, AlreadyAccepted, UserRegisteredEmail


class CleanEmailMixin(object):
Expand All @@ -16,6 +17,8 @@ def validate_invitation(self, email):
elif Invitation.objects.filter(
email__iexact=email, accepted=True):
raise AlreadyAccepted
elif get_user_model().objects.filter(email__iexact=email):
raise UserRegisteredEmail
else:
return True

Expand All @@ -28,14 +31,16 @@ def clean_email(self):
" invited."),
"already_accepted": _("This e-mail address has already"
" accepted an invite."),
"email_in_use": _("An active user is using this e-mail address"),
}
try:
self.validate_invitation(email)
except(AlreadyInvited):
raise forms.ValidationError(errors["already_invited"])
except(AlreadyAccepted):
raise forms.ValidationError(errors["already_accepted"])

except(UserRegisteredEmail):
raise forms.ValidationError(errors["email_in_use"])
return email


Expand Down
26 changes: 26 additions & 0 deletions invitations/migrations/0002_auto_20151126_0426.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
from django.conf import settings


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('invitations', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='invitation',
name='inviter',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True),
),
migrations.AlterField(
model_name='invitation',
name='email',
field=models.EmailField(unique=True, max_length=254, verbose_name='e-mail address'),
),
]
8 changes: 6 additions & 2 deletions invitations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.utils.encoding import python_2_unicode_compatible
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.conf import settings

from allauth.account.adapter import DefaultAccountAdapter
from allauth.account.adapter import get_adapter
Expand All @@ -25,15 +26,17 @@ class Invitation(models.Model):
default=timezone.now)
key = models.CharField(verbose_name=_('key'), max_length=64, unique=True)
sent = models.DateTimeField(verbose_name=_('sent'), null=True)
inviter = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)

objects = InvitationManager()

@classmethod
def create(cls, email):
def create(cls, email, user=None):
key = get_random_string(64).lower()
instance = cls._default_manager.create(
email=email,
key=key)
key=key,
inviter=user)
return instance

def key_expired(self):
Expand All @@ -54,6 +57,7 @@ def send_invitation(self, request, **kwargs):
'site_name': current_site.name,
'email': self.email,
'key': self.key,
'inviter': self.inviter,
}

email_template = 'invitations/email/email_invite'
Expand Down
20 changes: 18 additions & 2 deletions invitations/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,15 @@ def setUp(cls):
cls.user = get_user_model().objects.create_user(
username='flibble',
password='password')
cls.existing_user = get_user_model().objects.create_user(
username='flobble',
password='password',
email='flobble@example.com')
cls.invitation = Invitation.create('invited@example.com')

@classmethod
def tearDownClass(cls):
cls.user.delete()
get_user_model().objects.all().delete()
Invitation.objects.all().delete()

def test_auth(self):
Expand All @@ -104,6 +108,7 @@ def test_auth(self):
@parameterized.expand([
('invalid@example', 'Enter a valid email address'),
('invited@example.com', 'This e-mail address has already been'),
('flobble@example.com', 'An active user is')
])
def test_invalid_form_submissions(self, email, error):
self.client.login(username='flibble', password='password')
Expand Down Expand Up @@ -137,10 +142,14 @@ class InvitationsAcceptViewTests(TestCase):

@classmethod
def setUpClass(cls):
cls.invitation = Invitation.create('email@example.com')
cls.user = get_user_model().objects.create_user(
username='flibble',
password='password')
cls.invitation = Invitation.create('email@example.com', user=cls.user)

@classmethod
def tearDownClass(cls):
get_user_model().objects.all().delete()
Invitation.objects.all().delete()

@override_settings(
Expand Down Expand Up @@ -176,6 +185,7 @@ def test_accept_invite(self, method):
kwargs={'key': self.invitation.key}), follow=True)
invite = Invitation.objects.get(email='email@example.com')
self.assertTrue(invite.accepted)
self.assertEqual(invite.inviter, self.user)
self.assertEqual(resp.request['PATH_INFO'], reverse('account_signup'))

form = resp.context_data['form']
Expand Down Expand Up @@ -267,15 +277,21 @@ def setUp(cls):
pending_invite.sent = timezone.now() - datetime.timedelta(
days=app_settings.INVITATION_EXPIRY - 1)
pending_invite.save()
cls.existing_user = get_user_model().objects.create_user(
username='flobble',
password='password',
email='flobble@example.com')

@classmethod
def tearDownClass(cls):
get_user_model().objects.all().delete()
Invitation.objects.all().delete()

@parameterized.expand([
('bogger@something.com', True, None),
('already@accepted.com', False, 'has already accepted an invite'),
('pending@example.com', False, 'has already been invited'),
('flobble@example.com', False, 'active user is using this'),
])
def test_form(self, email, form_validity, errors):
form = InviteForm(data={'email': email})
Expand Down

0 comments on commit 5dd2263

Please sign in to comment.