Django-inviteme is a reusable app that relies on its own code and doesn’t require any other extra app.
Installation
Installing Django-inviteme is as simple as checking out the source and adding it to your project or PYTHONPATH.
Use git, pip or easy_install to check out Django-inviteme from Github or get a release from PyPI:
- Use git to clone the repository, and then install the package (read more about git):
- git clone git://github.com/danirus/django-inviteme.git and
- python setup.py install
- Or use pip (read more about pip):
- Do pip install django-inviteme, or
- Edit your project’s requirements file and append either the Github URL or the package name django-inviteme, and then do pip install -r requirements.
- Or use easy_install (read more about easy_install):
- Do easy_install django-inviteme
Workflow described in 3 actions:
- Render the Contact Form page. Omit this at will by using the render-mail-form templatetag (see Templatetags) in your own templates.
- Check if there are form security errors. Django_ContactMe forms are protected with timestamp, security_hash and honeypot field, following the same approach as the built-in Django Comments Framework. In case of form security errors send a 400 code response and stop.
- Check whether there are other form errors (basically check if the email field is empty). In such a case render the Mail Form again, with the form errors and stop.
- Send signal inviteme.signals.confirmation_will_be_requested. If any receiver returns False, send a discarded response to the user and stop.
- Send a confirmation email to the user with a confirmation URL.
- Send signal inviteme.signals.confirmation_requested.
- Render a “confirmation has been sent to you by email” template.
- Check whether the token in the confirmation URL is correct. If it isn’t raise a 404 code response and stop.
- Create a ContactMail model instance with the email address secured in the URL.
- Send signal confirmation_received. If any receiver return False, send a discarded response to the user and stop.
- Send an email to settings.INVITEME_NOTIFY_TO addresses indicating that a new invitation request has been received.
- Render a “your invitation request has been received, thank you” template.
The Confirmation URL sent by email to the user has a secured token with the contact form data. To create the token Django-ContactMe uses the module signed.py authored by Simon Willison and provided in Django-OpenID.
django_openid.signed offers two high level functions:
A brief example:
>>> signed.dumps("hello")
'UydoZWxsbycKcDAKLg.QLtjWHYe7udYuZeQyLlafPqAx1E'
>>> signed.loads('UydoZWxsbycKcDAKLg.QLtjWHYe7udYuZeQyLlafPqAx1E')
'hello'
>>> signed.loads('UydoZWxsbycKcDAKLg.QLtjWHYe7udYuZeQyLlafPqAx1E-modified')
BadSignature: Signature failed: QLtjWHYe7udYuZeQyLlafPqAx1E-modified
There are two components in dump’s output UydoZWxsbycKcDAKLg.QLtjWHYe7udYuZeQyLlafPqAx1E, separatad by a ‘.’. The first component is a URLsafe base64 encoded pickle of the object passed to dumps(). The second component is a base64 encoded hmac/SHA1 hash of “$first_component.$secret”.
Calling signed.loads(s) checks the signature BEFORE unpickling the object -this protects against malformed pickle attacks. If the signature fails, a ValueError subclass is raised (actually a BadSignature).
The workflow mentions that django-inviteme sends 3 signals:
See Signals to know more.
You may want to extend django-inviteme by registering a receiver for any of this signals.
An example function receiver might check the datetime a user submitted a contact message and the datetime the confirmation URL has been clicked. If the difference between them is over 7 days the message could be discarded with a graceful “sorry, too old message” template.
Extending the demo site with the following code would do the job:
#----------------------------------------
# append the code below to demo/views.py:
from datetime import datetime, timedelta
from inviteme import signals
def check_submit_date_is_within_last_7days(sender, data, request, **kwargs):
plus7days = timedelta(days=7)
if data["submit_date"] + plus7days < datetime.now():
return False
signals.confirmation_received.connect(check_submit_date_is_within_last_7days)
#-----------------------------------------------------
# change get_instance_data in inviteme/forms.py to cheat a bit and
# make Django believe that the contact form was submitted 7 days ago:
def get_instance_data(self):
"""
Returns the dict of data to be used to create a contact message.
"""
from datetime import timedelta # ADD THIS
return dict(
email = self.cleaned_data["email"],
# submit_date = datetime.datetime.now(), # COMMENT THIS
submit_date = datetime.datetime.now() - timedelta(days=8), # ADD THIS
)
Try the demo site again and see that the inviteme/discarded.html template is rendered after clicking on the confirmation URL.