Source

django-registration-plus / registration / backends / invitational / __init__.py

Full commit
from django.conf import settings

from registration import signals
from registration.forms import InvitationForm
from registration.forms import RegistrationInvitationalForm
from registration.models import EmailValidation
from registration.models import RegistrationInvitation
from registration.future import get_current_site


class InvitationBackend(object):
    """
    An invitation-registration backend which follows a simple workflow:
    
    1. A register user receives an ``RegistrationInvitation``
    
    2. The user invites a friend by entering her email.
    
    3. The friend accepts the invitation and comes to the registration view.
    
    4. User signs up, an active account is created.

    5. An ``EmailValidation`` is created. If the email is the same as in the 
    invitation the ``EmailValidation`` is immediately validated, 
    otherwise an email is sent to the user to validate it.

    6. User clicks validation link, email is validated.

    Using this backend requires that

    * ``registration`` be listed in the ``INSTALLED_APPS`` setting
      (since this backend makes use of models defined in this
      application).

    * The setting ``EMAIL_VALIDATION_DAYS`` be supplied, specifying
      (as an integer) the number of days from registration during
      which a user may validate their email (after that period
      expires, they will need to resend the validation email).

    * The creation of the templates
      ``registration/invitation_email_subject.txt``,
      ``registration/invitation_email.txt`` and optionally, 
      ``registration/invitation_email.html`` which will be used for
      the invitation email and templates 
      ``registration/activation_email_subject.txt``,
      ``registration/activation_email.txt`` and optionally, 
      ``registration/activation_email.html`` which will be used for
      the activation email. See the notes for this backends
      ``register`` method for details regarding these templates.

    Additionally, registration can be temporarily open (not requiring an 
    invitation code) by adding the setting ``REGISTRATION_OPEN`` and setting 
    it to ``True``. Omitting this setting, or setting it to ``False``, will
    be interpreted as meaning that registration is currently only available 
    with an invitation.

    Internally, this is accomplished via storing invitation data in an 
    instance of ``registration.models.RegistrationInvitation`` and validation 
    data in an instance of ``registration.models.EmailValidation``. See
    these models and their custom managers for full documentation of the
    fields and supported operations.
    
    """
    def invite(self, request, **kwargs):
        """
        Given a user and an email, send an invitation to the email if the 
        user has any invitations left to use.
        
        """
        user, email = request.user, kwargs['email']
        # TODO: check if user is actually logged in and not anonymous/guest?
        site = get_current_site(request)
        return RegistrationInvitation.objects.send_invitation(user, email, site)    
    
    def get_invitation_form_class(self, request):
        """
        Return the default form class used for user registration.
        
        """
        return InvitationForm
    
    def post_invitation_redirect(self, request, user):
        """
        Return the name of the URL to redirect to after successful
        registration invitation.
        
        """
        return ('registration_invitation_complete', (), {})
    
    def register(self, request, **kwargs):
        """
        Given a username, email address and password, register a new
        user account, which will initially be active immediately.
        
        If the registration is not open also require an invitation_key.
        
        Along with the new ``User`` object, a new
        ``registration.models.EmailValidation`` will be created,
        tied to that ``User``, containing the validation key which
        will be used to validate the email. 
        
        If invitation_key is supplied and the user email matches the 
        invitation email, the validation is done automatically without 
        sending the validation email. 
        
        If needed, the email will be sent to the supplied email address; this
        email should contain a validation link. The email will be
        rendered using three templates (subject, text and html version). See 
        the documentation for ``EmailValidation.send_activation_email()`` for
        information about these templates and the contexts provided to
        them.
        
        After the ``User`` and ``EmailValidation`` are created and an optional
        validation email is sent, the signal
        ``registration.signals.user_registered`` will be sent, with
        the new ``User`` as the keyword argument ``user`` and the
        class of this backend as the sender.
        
        """
        username, email, password, invitation_key = kwargs['username'],  \
                                                    kwargs['email'],  \
                                                    kwargs['password1'],  \
                                                    kwargs['invitation_key']
        site = get_current_site(request)
        new_user = EmailValidation.objects.create_user(username, email, 
                                                       password, site, 
                                                       invitation_key=invitation_key)
        for k in kwargs:
            if hasattr(new_user, k):
                setattr(new_user, k, kwargs[k])
        new_user.save()
        signals.user_registered.send(sender=self.__class__,
                                     user=new_user,
                                     request=request)
        signals.user_activated.send(sender=self.__class__,
                                     user=new_user,
                                     request=request)
        return new_user
    
    def validate(self, request, validation_key):
        """
        Given an an validation key, look up and validate the user
        account corresponding to that key (if possible).
        
        After successful validation, the signal
        ``registration.signals.user_activated`` will be sent, with the
        newly activated ``User`` as the keyword argument ``user`` and
        the class of this backend as the sender.
        
        """
        return EmailValidation.objects.validate_email(validation_key)
    
    def registration_allowed(self, request):
        """
        Indicate whether account registration is currently permitted,
        based on the value of the setting ``REGISTRATION_OPEN``. This
        is determined as follows:
        
        * If ``REGISTRATION_OPEN`` is not specified in settings, or is
          set to ``True``, registration is permitted.

        * If ``REGISTRATION_OPEN`` is both specified and set to
          ``False``, registration is not permitted.
        
        """
        if not getattr(settings, 'REGISTRATION_OPEN', False):
            try:
                invite = RegistrationInvitation.objects.get(invitation_key=request.GET.get("invitation_key"))
                return True
            except RegistrationInvitation.DoesNotExist:
                return False
        return True

    def get_form_class(self, request):
        """
        Return the default form class used for user registration.
        
        """
        return RegistrationInvitationalForm

    def post_registration_redirect(self, request, user):
        """
        Return the name of the URL to redirect to after successful
        user registration.
        
        """
        return ('registration_complete', (), {})

    def post_validation_redirect(self, request, user):
        """
        Return the name of the URL to redirect to after successful
        account validation.
        
        """
        return ('registration_validation_complete', (), {})