Skip to content

Commit

Permalink
Merge 6960386 into 398442f
Browse files Browse the repository at this point in the history
  • Loading branch information
bee-keeper committed Mar 31, 2017
2 parents 398442f + 6960386 commit 54c1cd9
Show file tree
Hide file tree
Showing 19 changed files with 451 additions and 428 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
*.pyc
.tox/
dist/
.cache/
.coverage/
django_invitations.egg-info/
.gitchangelog.rc
Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
##Django-invitations - Generic invitations app
## Django-invitations - Generic invitations app

[![Build Status](https://travis-ci.org/bee-keeper/django-invitations.svg?branch=master)](https://travis-ci.org/bee-keeper/django-invitations)

[![Coverage Status](https://coveralls.io/repos/bee-keeper/django-invitations/badge.svg?branch=master&service=github)](https://coveralls.io/github/bee-keeper/django-invitations?branch=master)

###About
### About
Generic invitations solution with adaptable backend and support for django-allauth. All emails and messages are fully customisable.

Originally written as an invitations solution for the excellent [django-allauth](https://github.com/pennersr/django-allauth), this app has been refactored to remove the allauth dependency whilst retaining 100% backwards compatibility.
Expand All @@ -23,7 +23,7 @@ Allauth Invitation flow:
* The signup URL has the email prefilled and upon signing up the user is logged into the site


###Generic Installation
### Generic Installation

```
pip install django-invitations
Expand All @@ -35,7 +35,7 @@ pip install django-invitations
url(r'^invitations/', include('invitations.urls', namespace='invitations')),
```

###Allauth Integration
### Allauth Integration

As above but note that invitations must come after allauth in the INSTALLED_APPS

Expand All @@ -44,7 +44,7 @@ As above but note that invitations must come after allauth in the INSTALLED_APPS
ACCOUNT_ADAPTER = 'invitations.models.InvitationsAdapter'
```

###Sending Invites
### Sending Invites

```
# inviter argument is optional
Expand All @@ -55,12 +55,12 @@ invite.send_invitation(request)
To send invites via django admin, just add an invite and save.


###Bulk Invites
### Bulk Invites

Bulk invites are supported via JSON. Post a list of comma separated emails to the dedicated URL and Invitations will return a data object containing a list of valid and invalid invitations.


###Testing
### Testing

`python manage.py test` or `tox`

Expand Down Expand Up @@ -119,15 +119,15 @@ Bulk invites are supported via JSON. Post a list of comma separated emails to t

If set to `None` (the default), invitation email subjects will be prefixed with the name of the current Site in brackets (such as `[example.com]`). Set this to a string to for a custom email subject prefix, or an empty string for no prefix.

###Signals
### Signals

The following signals are emitted:

* `invite_url_sent`
* `invite_accepted`


###Management Commands
### Management Commands
Expired and accepted invites can be cleared as so:

`python manage.py clear_expired_invitations`
4 changes: 3 additions & 1 deletion invitations/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from django.contrib import admin

from .models import Invitation
from .forms import InvitationAdminAddForm, InvitationAdminChangeForm
from .utils import get_invitation_model

Invitation = get_invitation_model()


class InvitationAdmin(admin.ModelAdmin):
Expand Down
7 changes: 7 additions & 0 deletions invitations/app_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,12 @@ def EMAIL_SUBJECT_PREFIX(self):
"""
return self._setting("EMAIL_SUBJECT_PREFIX", None)

@property
def INVITATION_MODEL(self):
"""
Subject-line prefix to use for Invitation model setup
"""
return self._setting("INVITATION_MODEL", "invitations.Invitation")


app_settings = AppSettings('INVITATIONS_')
41 changes: 41 additions & 0 deletions invitations/base_invitation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from django.conf import settings
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _

from .managers import BaseInvitationManager


@python_2_unicode_compatible
class AbstractBaseInvitation(models.Model):
accepted = models.BooleanField(verbose_name=_('accepted'), default=False)
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, blank=True)

objects = BaseInvitationManager()

class Meta:
abstract = True

@classmethod
def create(cls, email, inviter=None, **kwargs):
raise NotImplementedError(
'You should implement the create method class'
)

def key_expired(self):
raise NotImplementedError(
'You should implement the key_expired method'
)

def send_invitation(self, request, **kwargs):
raise NotImplementedError(
'You should implement the send_invitation method'
)

def __str__(self):
raise NotImplementedError(
'You should implement the __str__ method'
)
4 changes: 3 additions & 1 deletion invitations/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import get_user_model

from .models import Invitation
from .adapters import get_invitations_adapter
from .exceptions import AlreadyInvited, AlreadyAccepted, UserRegisteredEmail
from .utils import get_invitation_model

Invitation = get_invitation_model()


class CleanEmailMixin(object):
Expand Down
4 changes: 3 additions & 1 deletion invitations/management/commands/clear_expired_invitations.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from django.core.management.base import BaseCommand
from .. .models import Invitation
from .. .utils import get_invitation_model

Invitation = get_invitation_model()


class Command(BaseCommand):
Expand Down
2 changes: 1 addition & 1 deletion invitations/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .app_settings import app_settings


class InvitationManager(models.Manager):
class BaseInvitationManager(models.Manager):

def all_expired(self):
return self.filter(self.expired_q())
Expand Down
34 changes: 12 additions & 22 deletions invitations/models.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,36 @@
import datetime

from django.conf import settings
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.template.context import RequestContext
from django.utils import timezone
from django.utils.crypto import get_random_string
from django.utils.encoding import python_2_unicode_compatible
from django.contrib.sites.models import Site
from django.conf import settings
from django.template.context import RequestContext
try:
from django.urls import reverse
except ImportError:
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _

from .managers import InvitationManager
from .app_settings import app_settings
from .adapters import get_invitations_adapter
from . import signals
from .adapters import get_invitations_adapter
from .app_settings import app_settings
from .base_invitation import AbstractBaseInvitation


@python_2_unicode_compatible
class Invitation(models.Model):

class Invitation(AbstractBaseInvitation):
email = models.EmailField(unique=True, verbose_name=_('e-mail address'),
max_length=app_settings.EMAIL_MAX_LENGTH)
accepted = models.BooleanField(verbose_name=_('accepted'), default=False)
created = models.DateTimeField(verbose_name=_('created'),
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,
blank=True, on_delete=models.CASCADE)

objects = InvitationManager()

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

def key_expired(self):
Expand Down
Loading

0 comments on commit 54c1cd9

Please sign in to comment.