Include third-party django-confirmation library.

Taken from http://code.google.com/p/django-confirmation/.

Code is under the BSD 3-clause license.

(imported from commit cfb5a511097fe14fba7f1bcea62dfa25cfb58622)
This commit is contained in:
Luke Faraone 2012-09-28 16:29:48 -04:00
parent 5556bdd0a1
commit b801b50c26
15 changed files with 323 additions and 0 deletions

View File

@ -0,0 +1,3 @@
=============================
Django Confirmation Changelog
=============================

12
confirmation/INSTALL.txt Normal file
View File

@ -0,0 +1,12 @@
To install django-confirmation, run the following command inside this
directory:
python setup.py install
You can also just copy the included ``confirmation`` directory somewhere
on your Python path, or symlink to it from somewhere on your Python path;
this is useful if you're working from a Subversion checkout.
This application requires Python 2.3 or later, and Django 1.0 or later.
You can obtain Python from http://www.python.org/ and Django from
http://www.djangoproject.com/.

28
confirmation/LICENSE.txt Normal file
View File

@ -0,0 +1,28 @@
Copyright (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the author nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

10
confirmation/README.txt Normal file
View File

@ -0,0 +1,10 @@
===================
Django Confirmation
===================
This is a generic object confirmation system for Django applications.
For installation instructions, see the file "INSTALL.txt" in this
directory; for instructions on how to use this application, and on
what it provides, see the file "overview.txt" in the "docs/"
directory.

24
confirmation/__init__.py Normal file
View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish, dis-
# tribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the fol-
# lowing conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
VERSION = (0, 9, 'pre')

13
confirmation/admin.py Normal file
View File

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
__revision__ = '$Id: admin.py 3 2008-11-18 07:33:52Z jarek.zgoda $'
from django.contrib import admin
from confirmation.models import Confirmation
admin.site.register(Confirmation)

View File

View File

@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
__revision__ = '$Id: cleanupconfirmation.py 5 2008-11-18 09:10:12Z jarek.zgoda $'
from django.core.management.base import NoArgsCommand
from confirmation.models import Confirmation
class Command(NoArgsCommand):
help = 'Delete expired confirmations from database'
def handle_noargs(self, **options):
Confirmation.objects.delete_expired_confirmations()

103
confirmation/models.py Normal file
View File

@ -0,0 +1,103 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
__revision__ = '$Id: models.py 28 2009-10-22 15:03:02Z jarek.zgoda $'
import os
import re
import datetime
from hashlib import sha1
from django.db import models
from django.core.urlresolvers import reverse
from django.core.mail import send_mail
from django.conf import settings
from django.template import loader, Context
from django.contrib.sites.models import Site
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.utils.translation import ugettext_lazy as _
from confirmation.util import get_status_field
try:
import mailer
send_mail = mailer.send_mail
except ImportError:
# no mailer app present, stick with default
pass
SHA1_RE = re.compile('^[a-f0-9]{40}$')
class ConfirmationManager(models.Manager):
def confirm(self, confirmation_key):
if SHA1_RE.search(confirmation_key):
try:
confirmation = self.get(confirmation_key=confirmation_key)
except self.model.DoesNotExist:
return False
if not confirmation.key_expired():
obj = confirmation.content_object
status_field = get_status_field(obj._meta.app_label, obj._meta.module_name)
setattr(obj, status_field, getattr(settings, 'STATUS_ACTIVE', 1))
obj.save()
return obj
return False
def send_confirmation(self, obj, email_address):
confirmation_key = sha1(str(os.urandom(12)) + str(email_address)).hexdigest()
current_site = Site.objects.get_current()
activate_url = u'http://%s%s' % (current_site.domain,
reverse('confirmation.views.confirm', kwargs={'confirmation_key': confirmation_key}))
context = Context({
'activate_url': activate_url,
'current_site': current_site,
'confirmation_key': confirmation_key,
'target': obj,
'days': getattr(settings, 'EMAIL_CONFIRMATION_DAYS', 10),
})
templates = [
'confirmation/%s_confirmation_email_subject.txt' % obj._meta.module_name,
'confirmation/confirmation_email_subject.txt',
]
template = loader.select_template(templates)
subject = template.render(context).strip().replace(u'\n', u' ') # no newlines, please
templates = [
'confirmation/%s_confirmation_email_body.txt' % obj._meta.module_name,
'confirmation/confirmation_email_body.txt',
]
template = loader.select_template(templates)
body = template.render(context)
send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, [email_address])
return self.create(content_object=obj, date_sent=datetime.datetime.now(), confirmation_key=confirmation_key)
def delete_expired_confirmations(self):
for confirmation in self.all():
if confirmation.key_expired():
confirmation.delete()
class Confirmation(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
date_sent = models.DateTimeField(_('sent'))
confirmation_key = models.CharField(_('activation key'), max_length=40)
objects = ConfirmationManager()
class Meta:
verbose_name = _('confirmation email')
verbose_name_plural = _('confirmation emails')
def __unicode__(self):
return _('confirmation email for %s') % self.content_object
def key_expired(self):
expiration_date = self.date_sent + datetime.timedelta(days=getattr(settings, 'EMAIL_CONFIRMATION_DAYS', 10))
return expiration_date <= datetime.datetime.now()
key_expired.boolean = True

12
confirmation/settings.py Normal file
View File

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
__revision__ = '$Id: settings.py 12 2008-11-23 19:38:52Z jarek.zgoda $'
EMAIL_CONFIRMATION_DAYS = 10
STATUS_ACTIVE = 1
STATUS_FIELDS = {
}

35
confirmation/setup.py Normal file
View File

@ -0,0 +1,35 @@
from setuptools import setup, find_packages
# Dynamically calculate the version based on confirmation.VERSION.
version_tuple = __import__('confirmation').VERSION
if version_tuple[2] is not None:
version = "%d.%d_%s" % version_tuple
else:
version = "%d.%d" % version_tuple[:2]
setup(
name = 'django-confirmation',
version = version,
description = 'Generic object confirmation for Django',
author = 'Jarek Zgoda',
author_email = 'jarek.zgoda@gmail.com',
url = 'http://code.google.com/p/django-confirmation/',
license = 'New BSD License',
packages = find_packages(),
classifiers = [
'Development Status :: 4 - Beta',
'Environment :: Web Environment',
'Framework :: Django',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Utilities',
],
zip_safe = False,
install_requires = [
'django>=1.0',
],
)

15
confirmation/urls.py Normal file
View File

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
__revision__ = '$Id: urls.py 3 2008-11-18 07:33:52Z jarek.zgoda $'
from django.conf.urls.defaults import *
from confirmation.views import confirm
urlpatterns = patterns('',
(r'^(?P<confirmation_key>\w+)/$', confirm),
)

12
confirmation/util.py Normal file
View File

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
__revision__ = '$Id: util.py 3 2008-11-18 07:33:52Z jarek.zgoda $'
from django.conf import settings
def get_status_field(app_label, model_name):
model = '%s.%s' % (app_label, model_name)
mapping = getattr(settings, 'STATUS_FIELDS', {})
return mapping.get(model, 'status')

39
confirmation/views.py Normal file
View File

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
__revision__ = '$Id: views.py 21 2008-12-05 09:21:03Z jarek.zgoda $'
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.conf import settings
from confirmation.models import Confirmation
def confirm(request, confirmation_key):
confirmation_key = confirmation_key.lower()
obj = Confirmation.objects.confirm(confirmation_key)
confirmed = True
if not obj:
# confirmation failed
confirmed = False
try:
# try to get the object we was supposed to confirm
obj = Confirmation.objects.get(confirmation_key=confirmation_key)
except Confirmation.DoesNotExist:
pass
ctx = {
'object': obj,
'confirmed': confirmed,
'days': getattr(settings, 'EMAIL_CONFIRMATION_DAYS', 10),
}
templates = [
'confirmation/confirm.html',
]
if obj:
# if we have an object, we can use specific template
templates.insert(0, 'confirmation/confirm_%s.html' % obj._meta.module_name)
return render_to_response(templates, ctx,
context_instance=RequestContext(request))