mirror of
https://github.com/Hopiu/django-tos.git
synced 2026-03-16 20:10:24 +00:00
Merge branch 'master' of github.com:revsys/django-tos
This commit is contained in:
commit
557d4d5984
16 changed files with 215 additions and 112 deletions
33
.coveragerc
Normal file
33
.coveragerc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
[report]
|
||||
# Regexes for lines to exclude from consideration
|
||||
exclude_lines =
|
||||
# Have to re-enable the standard pragma
|
||||
pragma: no cover
|
||||
|
||||
# Don't complain about missing debug-only code:
|
||||
def __repr__
|
||||
if self\.debug
|
||||
def __unicode__
|
||||
def __repr__
|
||||
if settings.DEBUG
|
||||
raise NotImplementedError
|
||||
from django\.
|
||||
|
||||
# Don't complain if tests don't hit defensive assertion code:
|
||||
raise AssertionError
|
||||
raise NotImplementedError
|
||||
|
||||
# Don't complain if non-runnable code isn't run:
|
||||
if 0:
|
||||
if __name__ == .__main__.:
|
||||
|
||||
[run]
|
||||
omit =
|
||||
*tests*
|
||||
*migrations*
|
||||
*management*
|
||||
*urls*
|
||||
*site-packages*
|
||||
*src*
|
||||
*manage*
|
||||
*settings*
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,2 +1,2 @@
|
|||
*.pyc
|
||||
templates/
|
||||
.coverage
|
||||
|
|
|
|||
13
.travis.yml
13
.travis.yml
|
|
@ -3,19 +3,20 @@ python:
|
|||
- "2.6"
|
||||
- "2.7"
|
||||
- "3.4"
|
||||
|
||||
install:
|
||||
- pip install .
|
||||
- pip install coverage
|
||||
- pip install $DJANGO
|
||||
script:
|
||||
- django-admin.py test tos --settings=tos.tests.test_settings
|
||||
- coverage run runtests.py
|
||||
- coverage report -m
|
||||
env:
|
||||
- DJANGO="Django==1.4.12"
|
||||
- DJANGO="Django==1.5"
|
||||
- DJANGO="Django==1.5.7"
|
||||
- DJANGO="Django==1.6.4"
|
||||
- DJANGO="Django==1.7.11"
|
||||
|
||||
- DJANGO="Django==1.8.11"
|
||||
- DJANGO="Django==1.9.4"
|
||||
matrix:
|
||||
exclude:
|
||||
# Python 2.6 support has been dropped in Django 1.7
|
||||
|
|
@ -23,3 +24,7 @@ matrix:
|
|||
env: DJANGO="Django==1.7.11"
|
||||
- python: "3.4"
|
||||
env: DJANGO="Django==1.4.12"
|
||||
- python: "2.6"
|
||||
env: DJANGO="Django==1.8.11"
|
||||
- python: "2.6"
|
||||
env: DJANGO="Django==1.9.4"
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
Django>=1.4
|
||||
coverage
|
||||
|
|
|
|||
53
runtests.py
Executable file
53
runtests.py
Executable file
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
|
||||
import django
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management import execute_from_command_line
|
||||
|
||||
|
||||
if not settings.configured:
|
||||
settings.configure(
|
||||
DATABASES={
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
}
|
||||
},
|
||||
INSTALLED_APPS=[
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.sites',
|
||||
'tos',
|
||||
'tos.tests'
|
||||
],
|
||||
MIDDLEWARE_CLASSES=[
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
],
|
||||
ROOT_URLCONF='tos.tests.test_urls',
|
||||
LOGIN_URL='/login/',
|
||||
SITE_ID='1'
|
||||
)
|
||||
|
||||
|
||||
import logging
|
||||
logging.basicConfig(
|
||||
level = logging.DEBUG,
|
||||
format = '%(asctime)s %(levelname)s %(message)s',
|
||||
)
|
||||
logging.disable(logging.CRITICAL)
|
||||
|
||||
|
||||
def runtests():
|
||||
argv = sys.argv[:1] + ['test', 'tos']
|
||||
execute_from_command_line(argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
runtests()
|
||||
39
tos/compat.py
Normal file
39
tos/compat.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import django
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def get_fk_user_model():
|
||||
if django.VERSION >= (1, 5):
|
||||
return settings.AUTH_USER_MODEL
|
||||
from django.contrib.auth.models import User
|
||||
return User
|
||||
|
||||
|
||||
def get_runtime_user_model():
|
||||
if django.VERSION >= (1, 5):
|
||||
from django.contrib.auth import get_user_model
|
||||
return get_user_model()
|
||||
from django.contrib.auth.models import User
|
||||
return User
|
||||
|
||||
|
||||
def get_request_site():
|
||||
if django.VERSION >= (1, 9):
|
||||
from django.contrib.sites.requests import RequestSite
|
||||
else:
|
||||
from django.contrib.sites.models import RequestSite
|
||||
return RequestSite
|
||||
|
||||
|
||||
def get_library():
|
||||
if django.VERSION >= (1, 9):
|
||||
from django.template.library import Library
|
||||
else:
|
||||
from django.template.base import Library
|
||||
return Library
|
||||
|
||||
|
||||
if django.VERSION < (1, 5):
|
||||
from django.templatetags.future import url
|
||||
else:
|
||||
from django.template.defaulttags import url
|
||||
|
|
@ -2,14 +2,7 @@ from django.core.exceptions import ValidationError
|
|||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
# Django 1.4 compatability
|
||||
try:
|
||||
from django.contrib.auth import get_user_model
|
||||
USER_MODEL = get_user_model()
|
||||
except ImportError:
|
||||
from django.contrib.auth.models import User
|
||||
USER_MODEL = User
|
||||
|
||||
from tos.compat import get_fk_user_model
|
||||
|
||||
class NoActiveTermsOfService(ValidationError):
|
||||
pass
|
||||
|
|
@ -65,7 +58,8 @@ class TermsOfService(BaseModel):
|
|||
else:
|
||||
if not TermsOfService.objects\
|
||||
.exclude(id=self.id)\
|
||||
.filter(active=True):
|
||||
.filter(active=True)\
|
||||
.exists():
|
||||
raise NoActiveTermsOfService(
|
||||
u'One of the terms of service must be marked active'
|
||||
)
|
||||
|
|
@ -75,7 +69,7 @@ class TermsOfService(BaseModel):
|
|||
|
||||
class UserAgreement(BaseModel):
|
||||
terms_of_service = models.ForeignKey(TermsOfService, related_name='terms')
|
||||
user = models.ForeignKey(USER_MODEL, related_name='user_agreement')
|
||||
user = models.ForeignKey(get_fk_user_model(), related_name='user_agreement')
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s agreed to TOS: %s' % (self.user.username,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% load url from future %}
|
||||
{% load url from compat %}
|
||||
{% if note %}
|
||||
<h2>{{ note }}</note>
|
||||
{% else %}
|
||||
|
|
|
|||
0
tos/templatetags/__init__.py
Normal file
0
tos/templatetags/__init__.py
Normal file
10
tos/templatetags/compat.py
Normal file
10
tos/templatetags/compat.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
from tos.compat import url as tos_url, get_library
|
||||
|
||||
|
||||
Library = get_library()
|
||||
register = Library()
|
||||
|
||||
|
||||
@register.tag
|
||||
def url(parser, token):
|
||||
return tos_url(parser, token)
|
||||
|
|
@ -1,2 +1,5 @@
|
|||
from tos.tests.test_models import *
|
||||
from tos.tests.test_views import *
|
||||
import django
|
||||
|
||||
if django.VERSION < (1, 6):
|
||||
from tos.tests.test_models import *
|
||||
from tos.tests.test_views import *
|
||||
|
|
|
|||
1
tos/tests/templates/registration/login.html
Normal file
1
tos/tests/templates/registration/login.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
Dummy login template.
|
||||
|
|
@ -1,24 +1,25 @@
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.test import TestCase
|
||||
|
||||
from tos.compat import get_runtime_user_model
|
||||
from tos.models import (
|
||||
NoActiveTermsOfService,
|
||||
TermsOfService,
|
||||
UserAgreement,
|
||||
has_user_agreed_latest_tos,
|
||||
USER_MODEL
|
||||
)
|
||||
|
||||
|
||||
class TestModels(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.user1 = USER_MODEL.objects.create_user('user1',
|
||||
self.user1 = get_runtime_user_model().objects.create_user('user1',
|
||||
'user1@example.com',
|
||||
'user1pass')
|
||||
self.user2 = USER_MODEL.objects.create_user('user2',
|
||||
self.user2 = get_runtime_user_model().objects.create_user('user2',
|
||||
'user2@example.com',
|
||||
'user2pass')
|
||||
self.user3 = USER_MODEL.objects.create_user('user3',
|
||||
self.user3 = get_runtime_user_model().objects.create_user('user3',
|
||||
'user3@example.com',
|
||||
'user3pass')
|
||||
|
||||
|
|
@ -48,10 +49,6 @@ class TestModels(TestCase):
|
|||
# latest is active though
|
||||
self.assertTrue(latest.active)
|
||||
|
||||
def test_terms_of_service_manager(self):
|
||||
|
||||
self.assertEquals(TermsOfService.objects.get_current_tos(), self.tos1)
|
||||
|
||||
def test_validation_error_all_set_false(self):
|
||||
"""
|
||||
If you try and set all to false the model will throw a ValidationError
|
||||
|
|
@ -92,3 +89,18 @@ class TestModels(TestCase):
|
|||
self.assertTrue(has_user_agreed_latest_tos(self.user1))
|
||||
self.assertFalse(has_user_agreed_latest_tos(self.user2))
|
||||
self.assertTrue(has_user_agreed_latest_tos(self.user3))
|
||||
|
||||
|
||||
class TestManager(TestCase):
|
||||
def test_terms_of_service_manager(self):
|
||||
|
||||
tos1 = TermsOfService.objects.create(
|
||||
content="first edition of the terms of service",
|
||||
active=True
|
||||
)
|
||||
|
||||
self.assertEquals(TermsOfService.objects.get_current_tos(), tos1)
|
||||
|
||||
def test_terms_of_service_manager_raises_error(self):
|
||||
|
||||
self.assertRaises(NoActiveTermsOfService, TermsOfService.objects.get_current_tos)
|
||||
|
|
|
|||
|
|
@ -1,64 +0,0 @@
|
|||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
SITE_ID = 1
|
||||
SECRET_KEY = 'foobarbaz'
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': 'mydatabase'
|
||||
}
|
||||
}
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
)
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.core.context_processors.debug',
|
||||
'django.core.context_processors.i18n',
|
||||
'django.core.context_processors.media',
|
||||
'django.core.context_processors.static',
|
||||
'django.core.context_processors.tz',
|
||||
'django.core.context_processors.request',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
)
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.sites',
|
||||
'tos',
|
||||
)
|
||||
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
'django.template.loaders.eggs.Loader',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'tos.tests.test_urls'
|
||||
|
||||
LOGIN_URL = '/login/'
|
||||
|
||||
import logging
|
||||
logging.basicConfig(
|
||||
level = logging.DEBUG,
|
||||
format = '%(asctime)s %(levelname)s %(message)s',
|
||||
)
|
||||
|
||||
|
||||
# Django 1.7 compatibility:
|
||||
import django
|
||||
if hasattr(django, 'setup'):
|
||||
django.setup()
|
||||
|
||||
if django.VERSION > (1, 6):
|
||||
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
|
||||
|
|
@ -2,20 +2,15 @@ from django.conf import settings
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase
|
||||
|
||||
# Django 1.4 compatability
|
||||
try:
|
||||
from django.contrib.auth import get_user_model
|
||||
except ImportError:
|
||||
from django.contrib.auth.models import User
|
||||
get_user_model = lambda: User
|
||||
from tos.compat import get_runtime_user_model
|
||||
from tos.models import TermsOfService, UserAgreement, has_user_agreed_latest_tos
|
||||
|
||||
from tos.models import TermsOfService, UserAgreement, has_user_agreed_latest_tos, USER_MODEL as USER
|
||||
|
||||
class TestViews(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.user1 = USER.objects.create_user('user1', 'user1@example.com', 'user1pass')
|
||||
self.user2 = USER.objects.create_user('user2', 'user2@example.com', 'user2pass')
|
||||
self.user1 = get_runtime_user_model().objects.create_user('user1', 'user1@example.com', 'user1pass')
|
||||
self.user2 = get_runtime_user_model().objects.create_user('user2', 'user2@example.com', 'user2pass')
|
||||
|
||||
self.tos1 = TermsOfService.objects.create(
|
||||
content="first edition of the terms of service",
|
||||
|
|
@ -53,6 +48,34 @@ class TestViews(TestCase):
|
|||
|
||||
self.assertFalse(has_user_agreed_latest_tos(self.user2))
|
||||
|
||||
def test_do_not_need_agreement(self):
|
||||
""" user2 tries to login and has already agreed"""
|
||||
|
||||
self.assertTrue(has_user_agreed_latest_tos(self.user1))
|
||||
|
||||
response = self.client.post(self.login_url, dict(username='user1',
|
||||
password='user1pass'))
|
||||
self.assertEqual(302, response.status_code)
|
||||
|
||||
def test_redirect_security(self):
|
||||
""" redirect to outside url not allowed, should redirect to login url"""
|
||||
|
||||
response = self.client.post(self.login_url, dict(username='user1',
|
||||
password='user1pass', next='http://example.com'))
|
||||
self.assertEqual(302, response.status_code)
|
||||
self.assertIn(settings.LOGIN_REDIRECT_URL, response._headers['location'][1])
|
||||
|
||||
def test_need_to_log_in(self):
|
||||
""" GET to login url shows login tempalte."""
|
||||
|
||||
response = self.client.get(self.login_url)
|
||||
self.assertContains(response, "Dummy login template.")
|
||||
|
||||
def test_root_tos_view(self):
|
||||
|
||||
response = self.client.get('/tos/')
|
||||
self.assertIn(b'first edition of the terms of service', response.content)
|
||||
|
||||
def test_reject_agreement(self):
|
||||
|
||||
self.assertFalse(has_user_agreed_latest_tos(self.user2))
|
||||
|
|
|
|||
19
tos/views.py
19
tos/views.py
|
|
@ -5,7 +5,7 @@ from django.contrib import messages
|
|||
from django.contrib.auth import login as auth_login
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
from django.contrib.sites.models import Site, RequestSite
|
||||
from django.contrib.sites.models import Site
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
|
|
@ -13,16 +13,9 @@ from django.views.decorators.cache import never_cache
|
|||
from django.views.decorators.csrf import csrf_protect
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from tos.compat import get_runtime_user_model, get_request_site
|
||||
from tos.models import has_user_agreed_latest_tos, TermsOfService, UserAgreement
|
||||
|
||||
# Django 1.4 compatability
|
||||
try:
|
||||
from django.contrib.auth import get_user_model
|
||||
USER_MODEL = get_user_model()
|
||||
except ImportError:
|
||||
from django.contrib.auth.models import User
|
||||
USER_MODEL = User
|
||||
|
||||
|
||||
class TosView(TemplateView):
|
||||
template_name = "tos/tos.html"
|
||||
|
|
@ -54,11 +47,11 @@ def _redirect_to(redirect_to):
|
|||
def check_tos(request, template_name='tos/tos_check.html',
|
||||
redirect_field_name=REDIRECT_FIELD_NAME,):
|
||||
|
||||
redirect_to = _redirect_to(request.REQUEST.get(redirect_field_name, ''))
|
||||
redirect_to = _redirect_to(request.POST.get(redirect_field_name, request.GET.get(redirect_field_name, '')))
|
||||
tos = TermsOfService.objects.get_current_tos()
|
||||
if request.method == "POST":
|
||||
if request.POST.get("accept", "") == "accept":
|
||||
user = USER_MODEL.objects.get(pk=request.session['tos_user'])
|
||||
user = get_runtime_user_model().objects.get(pk=request.session['tos_user'])
|
||||
user.backend = request.session['tos_backend']
|
||||
|
||||
# Save the user agreement to the new TOS
|
||||
|
|
@ -90,7 +83,7 @@ def login(request, template_name='registration/login.html',
|
|||
authentication_form=AuthenticationForm):
|
||||
"""Displays the login form and handles the login action."""
|
||||
|
||||
redirect_to = request.REQUEST.get(redirect_field_name, '')
|
||||
redirect_to = request.POST.get(redirect_field_name, request.GET.get(redirect_field_name, ''))
|
||||
|
||||
if request.method == "POST":
|
||||
form = authentication_form(data=request.POST)
|
||||
|
|
@ -135,7 +128,7 @@ def login(request, template_name='registration/login.html',
|
|||
if Site._meta.installed:
|
||||
current_site = Site.objects.get_current()
|
||||
else:
|
||||
current_site = RequestSite(request)
|
||||
current_site = get_request_site()(request)
|
||||
|
||||
return render_to_response(template_name, {
|
||||
'form': form,
|
||||
|
|
|
|||
Loading…
Reference in a new issue