cradmin_invite — A generalized invite workflow¶
The purpose of the django_cradmin.apps.cradmin_invite
app is to provide a
general purpose invite workflow.
Install¶
Add the following to INSTALLED_APPS
:
INSTALLED_APPS = (
# ...
'django_cradmin',
'django_cradmin.apps.cradmin_generic_token_with_metadata',
'django_cradmin.apps.cradmin_invite',
)
Set the DJANGO_CRADMIN_SITENAME
setting:
DJANGO_CRADMIN_SITENAME = 'Testsite'
Tutorial¶
In this tutorial we will create a workflow/process that can be used to
invite a user to become administrator for a Site. Our example assumes
you have a Django app named myapp
.
The Site model¶
Lets say we have the following model:
from django.db import models
from django.conf import settings
class Site(models.Model):
name = models.CharField(max_length=255)
admins = models.ManyToManyField(settings.AUTH_USER_MODEL)
Create the invite email¶
Create a subclass of django_cradmin.apps.cradmin_invite.invite_url.InviteUrl
:
from django_cradmin.apps.cradmin_invite.invite_url import InviteUrl
class SiteAdminInviteUrl(InviteUrl):
def get_appname(self):
return 'myapp'
def get_confirm_invite_url(self, generictoken):
# URL of the AcceptSiteAdminInviteView shown below
return reverse('siteadmin-invite-accept', kwargs={
'token': generictoken.token
})
And use it to send the invite email to test@example.com
:
from django.views.generic import View
from myapp.models import Site
class CreateInviteView(View):
def get(self, request):
# NOTE: You will most likely want to put this code in a post() method
# and use a form as input.
site = Site.objects.first() # Code to get at Site object
invite = SiteAdminInviteUrl(request=request, private=True, content_object=site)
invite.send_email('test@example.com')
Notice that we add the ID of the site as metadata. We need this to know which site to add the user accepting the invite to.
Create the view responsible for adding the user as admin¶
Create a subclass of django_cradmin.apps.cradmin_invite.baseviews.AbstractAcceptInviteView
:
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.conf import settings
from django_cradmin.apps.cradmin_invite.baseviews.accept import AbstractAcceptInviteView
from myapp.models import Site
class AcceptSiteAdminInviteView(AbstractAcceptInviteView):
description_template_name = 'myapp/invite_description.django.html'
def get_appname(self):
return 'myapp'
def invite_accepted(self, generictoken):
site = generictoken.content_object
site.admins.add(self.request.user)
messages.success(self.request, 'You are now admin on %(site)s' % {'site': site})
return HttpResponseRedirect(settings.LOGIN_URL)
Add to urls¶
Add the views to your url patterns:
urlpatterns = patterns(
# ...
url(r'^siteadmin/invite/create$',
CreateInviteView.as_view(),
name="siteadmin-invite-accept"),
url(r'^siteadmin/invite/accept/(?P<token>.+)$',
AcceptSiteAdminInviteView.as_view(),
name="siteadmin-invite-accept"),
# ...
)
Private vs public InviteUrl¶
See get_share_url()
and send_email()
.
The InviteUrl class¶
-
class
InviteUrl
(request, private, content_object, metadata=None, **kwargs)¶ Bases:
object
Sends an email with a link that the user clicks to accept an invite.
Example
from django_cradmin.apps.cradmin_invite.utils import InviteUrl class InviteUrl(InviteUrl): def get_appname(self): return 'myapp' def get_confirm_invite_url(self, generictoken): return reverse('myapp-confirm-invite', kwargs={ 'token': generictoken.token }) def myview(request): InviteUrl(request=request, private=True, content_object=someobject).send_email( 'test@example.com', 'test2@example.com') # ... or ... share_url = InviteUrl(request=request, private=False, content_object=someobject).get_share_url() # ... or ... InviteUrl(request=request, private=False, content_object=someobject).send_email( 'test@example.com', 'test2@example.com', 'test3@example.com')
Parameters: - request – A Django HttpRequest object.
- private – If this is
True
we send unique single-use invite URLs. - metadata – Metadata to accociate with the invite.
-
get_appname
()¶ Get the appname for
django_cradmin.apps.cradmin_generic_token_with_metadata.models.GenericTokenWithMetadata.app
.You must override this in subclasses.
-
get_confirm_invite_url
(generictoken)¶ Get the confirm invite view URL.
Must be implemented in subclasses.
Parameters: generictoken – A GenericTokenWithMetadata
object.
-
get_from_email
()¶ Get the email sender address.
Defaults to the
DJANGO_CRADMIN_INVITE_FROM_EMAIL
setting falling back on theDEFAULT_FROM_EMAIL
setting.
-
get_expiration_datetime
()¶ Get the value to use for the
expiration_datetime
attribute ofGenericTokenWithMetadata
.Defaults to the expiration_datetime provided via the constructor, and falls back to getting the configured expiration datetime for the app.
-
get_invite_email_class
()¶ Must return a subclass of
django_cradmin.apps.cradmin_email.emailutils.AbstractEmail
.Defaults to
InviteEmail
.
-
get_extra_invite_email_context_data
(generictoken)¶ Override this to provide extra context data for the
get_invite_email_class()
.Make sure you call
super
and extend the returned dict.
-
send_email
(*emails)¶ Generate a token and send an email containing an absolute invite URL for that token.
If this InviteUrl is private, we generate a new token each email recipient, and if it is public, we re-use the same token.
Private tokens are generated as single use tokens, and public tokens are unlimited use tokens.
Private tokens gets the email automatically added to the metadata if metadata is a dict or None.
Generate a token and return an absolute invite URL for that token.
If this InviteUrl is private, we generate a new token each time this is called, and if it is public, we re-use the same token.
Private tokens are generated as single use tokens, and public tokens are unlimited use tokens.
Email templates and how to override them¶
You can override the following templates:
- cradmin_invite/email/subject.django.txt
- Override this to set the email subject.
- cradmin_invite/email/message.django.txt
- Override this to change the email message.
All of the email templates get the following context variables:
DJANGO_CRADMIN_SITENAME
: The value of the setting with the same name.activate_url
: The URL that users should click to activate their account.
UI messages/labels and how to override them¶
You do not have to override the entire template to adjust
the text in the AbstractAcceptInviteView
UI.
We provide the following class methods for you to override:
get_pagetitle () |
Get the title of the page. |
get_description_template_name () |
The template used to render the description of the invite. |
get_accept_as_button_label () |
Get the label of the Accept as authenticated user button. |
get_register_account_button_label () |
Get the label of the Sign up button. |
get_login_as_different_user_button_label () |
Get the label of the Sign in as different user button. |
get_login_button_label () |
Get the label of the Sign in button. |
The token error template¶
When the token fails to validate because it has expired or because
the user does not copy the entire URL into their browser, we
respond with token_error_response()
.
You normally do not want to override this method, but instead
override token_error_template_name
or get_token_error_template_name()
.
Instead of creating a completely custom template, you can extend
cradmin_invite/accept/token_error.django.html
and just
override the invalid_token_message
and expired_token_message
blocks:
{% extend "cradmin_invite/accept/token_error.django.html" %}
{% load i18n %}
{% block invalid_token_message %}
{% trans "Invalid invite URL. Are you sure you copied the entire URL from the email?" %}
{% endblock invalid_token_message %}
{% block expired_token_message %}
{% trans "This invite link has expired." %}
{% endblock expired_token_message %}
The AbstractAcceptInviteView class¶
-
class
AbstractAcceptInviteView
(**kwargs)¶ Bases:
django.views.generic.base.TemplateView
,django_cradmin.javascriptregistry.viewmixin.StandaloneBaseViewMixin
Base class for views that accept invites from
InviteUrl
.You have to override:
Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things.
-
description_template_name
= 'cradmin_invite/accept/description.django.html'¶ Default value for
get_description_template_name()
.
-
token_error_template_name
= 'cradmin_invite/accept/token_error.django.html'¶ Default value for
get_token_error_template_name()
.
-
get_pagetitle
()¶ Get the title of the page.
Get the label of the Accept as authenticated user button.
Get the label of the Sign up button.
Get the label of the Sign in as different user button.
Get the label of the Sign in button.
-
get_description_template_name
()¶ The template used to render the description of the invite. The template context is the one returned by
get_context_data()
.Defaults to
description_template_name
.
-
get_token_error_template_name
()¶ The template used to render the view when the given token does not validate. If you just want to change the error messages, you can extend the
cradmin_invite/accept/token_error.django.html
template and override theinvalid_token_message
andexpired_token_message
blocks.Defaults to
token_error_template_name
.
-
dispatch
(request, *args, **kwargs)¶ Takes care of validating the token for both GET and POST requests.
If the token is valid, we set
self.generic_token
to theGenericTokenWithMetadata
.If the token is invalid, we respond with
token_error_response()
.
-
token_error_response
(token_does_not_exist=False, token_expired=False)¶ Generates the response when the token does not validate.
Unless you have some special needs, you will most likely want to just override
token_error_template_name
instead of this view.
-
add_next_argument_to_url
(url, next_url=None)¶ Adds
?next=<next_url>
to the givenurl
.Parameters: - url – The base url.
- next_url – The url to redirect to after whatever
url
does is successfully completed. Defaults to the absolute URI of the current request.
-
get_register_account_url
()¶ Get the URL to used to create a new user.
Should have some way of returning the user to this view after the user has been created.
Defaults to the
cradmin-register-account
view indjango_cradmin.apps.cradmin_register_account
.
-
get_login_url
()¶ Get the URL to used to login if not already authenticated.
Should have some way of returning the user to this view after login is complete.
Defaults to
settings.LOGIN_URL
.
-
get_login_as_different_user_url
()¶ Get the URL to used to login as a different user.
Should have some way of returning the user to this view after login is complete.
Defaults to the
cradmin-authenticate-logout
view indjango_cradmin.apps.cradmin_authenticate
with the next-argument set to thecradmin-authenticate-login
view in the same app, with the next argument of thecradmin-authenticate-login
view set to the current url.
-
post
(*args, **kwargs)¶ If the user is authenticated, we return
invite_accepted()
. If the user is not authenticated, we raisedjango.core.exceptions.PermissionDenied
.
-
get_appname
()¶ Get the name of the appname. Must match the appname returned by the
get_appname
method of yourInviteUrl
subclass.
-
invite_accepted
(token)¶ Called on POST when the invite has been accepted by the user.
At this point,
self.request.user
is the user accepting the invite.
-
Settings¶
- Required settings:
- DJANGO_CRADMIN_SITENAME
- The name of the site. You must set this setting unless you override the email subject and message templates as explained in Email templates and how to override them.
- Optional settings:
- DJANGO_CRADMIN_INVITE_FROM_EMAIL
- Defaults to the
DEFAULT_FROM_EMAIL
setting.