Skip to content

Commit e1e2726

Browse files
committed
Fixed #6932 -- Added a template tag that gives a list of available flatpages for a given user. Thanks to Dmitri Fedortchenko for the suggestion, and to Mnewman, faldridge and Simon Meers for their work on the patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@13654 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent c00f35a commit e1e2726

File tree

11 files changed

+369
-10
lines changed

11 files changed

+369
-10
lines changed

django/contrib/flatpages/fixtures/sample_flatpages.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,22 @@
1717
{
1818
"pk": 2,
1919
"model": "flatpages.flatpage",
20+
"fields": {
21+
"registration_required": false,
22+
"title": "A Nested Flatpage",
23+
"url": "/location/flatpage/",
24+
"template_name": "",
25+
"sites": [
26+
1
27+
],
28+
"content": "Isn't it flat and deep!",
29+
"enable_comments": false
30+
}
31+
},
32+
33+
{
34+
"pk": 101,
35+
"model": "flatpages.flatpage",
2036
"fields": {
2137
"registration_required": true,
2238
"title": "Sekrit Flatpage",
@@ -28,5 +44,20 @@
2844
"content": "Isn't it sekrit!",
2945
"enable_comments": false
3046
}
47+
},
48+
{
49+
"pk": 102,
50+
"model": "flatpages.flatpage",
51+
"fields": {
52+
"registration_required": true,
53+
"title": "Sekrit Nested Flatpage",
54+
"url": "/location/sekrit/",
55+
"template_name": "",
56+
"sites": [
57+
1
58+
],
59+
"content": "Isn't it sekrit and deep!",
60+
"enable_comments": false
61+
}
3162
}
3263
]

django/contrib/flatpages/templatetags/__init__.py

Whitespace-only changes.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
from django import template
2+
from django.contrib.flatpages.models import FlatPage
3+
from django.utils.translation import ugettext as _
4+
from django.conf import settings
5+
6+
7+
register = template.Library()
8+
9+
10+
class FlatpageNode(template.Node):
11+
def __init__(self, context_name, starts_with=None, user=None):
12+
self.context_name = context_name
13+
if starts_with:
14+
self.starts_with = template.Variable(starts_with)
15+
else:
16+
self.starts_with = None
17+
if user:
18+
self.user = template.Variable(user)
19+
else:
20+
self.user = None
21+
22+
def render(self, context):
23+
flatpages = FlatPage.objects.filter(sites__id=settings.SITE_ID)
24+
# If a prefix was specified, add a filter
25+
if self.starts_with:
26+
flatpages = flatpages.filter(
27+
url__startswith=self.starts_with.resolve(context))
28+
29+
# If the provided user is not authenticated, or no user
30+
# was provided, filter the list to only public flatpages.
31+
if self.user:
32+
user = self.user.resolve(context)
33+
if not user.is_authenticated():
34+
flatpages = flatpages.filter(registration_required=False)
35+
else:
36+
flatpages = flatpages.filter(registration_required=False)
37+
38+
context[self.context_name] = flatpages
39+
return ''
40+
41+
42+
def get_flatpages(parser, token):
43+
"""
44+
Retrieves all flatpage objects available for the current site and
45+
visible to the specific user (or visible to all users if no user is
46+
specified). Populates the template context with them in a variable
47+
whose name is defined by the ``as`` clause.
48+
49+
An optional ``for`` clause can be used to control the user whose
50+
permissions are to be used in determining which flatpages are visible.
51+
52+
An optional argument, ``starts_with``, can be applied to limit the
53+
returned flatpages to those beginning with a particular base URL.
54+
This argument can be passed as a variable or a string, as it resolves
55+
from the template context.
56+
57+
Syntax::
58+
59+
{% get_flatpages ['url_starts_with'] [for user] as context_name %}
60+
61+
Example usage::
62+
63+
{% get_flatpages as flatpages %}
64+
{% get_flatpages for someuser as flatpages %}
65+
{% get_flatpages '/about/' as about_pages %}
66+
{% get_flatpages prefix as about_pages %}
67+
{% get_flatpages '/about/' for someuser as about_pages %}
68+
"""
69+
bits = token.split_contents()
70+
syntax_message = _("%(tag_name)s expects a syntax of %(tag_name)s "
71+
"['url_starts_with'] [for user] as context_name" %
72+
dict(tag_name=bits[0]))
73+
# Must have at 3-6 bits in the tag
74+
if len(bits) >= 3 and len(bits) <= 6:
75+
76+
# If there's an even number of bits, there's no prefix
77+
if len(bits) % 2 == 0:
78+
prefix = bits[1]
79+
else:
80+
prefix = None
81+
82+
# The very last bit must be the context name
83+
if bits[-2] != 'as':
84+
raise template.TemplateSyntaxError(syntax_message)
85+
context_name = bits[-1]
86+
87+
# If there are 5 or 6 bits, there is a user defined
88+
if len(bits) >= 5:
89+
if bits[-4] != 'for':
90+
raise template.TemplateSyntaxError(syntax_message)
91+
user = bits[-3]
92+
else:
93+
user = None
94+
95+
return FlatpageNode(context_name, starts_with=prefix, user=user)
96+
else:
97+
raise template.TemplateSyntaxError(syntax_message)
98+
99+
register.tag('get_flatpages', get_flatpages)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
from django.contrib.flatpages.tests.csrf import *
22
from django.contrib.flatpages.tests.middleware import *
3+
from django.contrib.flatpages.tests.templatetags import *
34
from django.contrib.flatpages.tests.views import *

django/contrib/flatpages/tests/csrf.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
from django.conf import settings
3+
from django.contrib.auth.models import User
34
from django.test import TestCase, Client
45

56
class FlatpageCSRFTests(TestCase):
@@ -42,6 +43,11 @@ def test_view_authenticated_flatpage(self):
4243
"A flatpage served through a view can require authentication"
4344
response = self.client.get('/flatpage_root/sekrit/')
4445
self.assertRedirects(response, '/accounts/login/?next=/flatpage_root/sekrit/')
46+
User.objects.create_user('testuser', '[email protected]', 's3krit')
47+
self.client.login(username='testuser',password='s3krit')
48+
response = self.client.get('/flatpage_root/sekrit/')
49+
self.assertEquals(response.status_code, 200)
50+
self.assertContains(response, "<p>Isn't it sekrit!</p>")
4551

4652
def test_fallback_flatpage(self):
4753
"A flatpage can be served by the fallback middlware"

django/contrib/flatpages/tests/middleware.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
from django.conf import settings
3+
from django.contrib.auth.models import User
34
from django.test import TestCase
45

56
class FlatpageMiddlewareTests(TestCase):
@@ -38,6 +39,11 @@ def test_view_authenticated_flatpage(self):
3839
"A flatpage served through a view can require authentication"
3940
response = self.client.get('/flatpage_root/sekrit/')
4041
self.assertRedirects(response, '/accounts/login/?next=/flatpage_root/sekrit/')
42+
User.objects.create_user('testuser', '[email protected]', 's3krit')
43+
self.client.login(username='testuser',password='s3krit')
44+
response = self.client.get('/flatpage_root/sekrit/')
45+
self.assertEquals(response.status_code, 200)
46+
self.assertContains(response, "<p>Isn't it sekrit!</p>")
4147

4248
def test_fallback_flatpage(self):
4349
"A flatpage can be served by the fallback middlware"
@@ -54,3 +60,8 @@ def test_fallback_authenticated_flatpage(self):
5460
"A flatpage served by the middleware can require authentication"
5561
response = self.client.get('/sekrit/')
5662
self.assertRedirects(response, '/accounts/login/?next=/sekrit/')
63+
User.objects.create_user('testuser', '[email protected]', 's3krit')
64+
self.client.login(username='testuser',password='s3krit')
65+
response = self.client.get('/sekrit/')
66+
self.assertEquals(response.status_code, 200)
67+
self.assertContains(response, "<p>Isn't it sekrit!</p>")
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,10 @@
1-
<h1>{{ flatpage.title }}</h1>
2-
<p>{{ flatpage.content }}</p>
1+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
2+
"http://www.w3.org/TR/REC-html40/loose.dtd">
3+
<html>
4+
<head>
5+
<title>{{ flatpage.title }}</title>
6+
</head>
7+
<body>
8+
<p>{{ flatpage.content }}</p>
9+
</body>
10+
</html>
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import os
2+
from django.conf import settings
3+
from django.contrib.auth.models import AnonymousUser, User
4+
from django.template import Template, Context, TemplateSyntaxError
5+
from django.test import TestCase
6+
7+
class FlatpageTemplateTagTests(TestCase):
8+
fixtures = ['sample_flatpages']
9+
urls = 'django.contrib.flatpages.tests.urls'
10+
11+
def setUp(self):
12+
self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES
13+
flatpage_middleware_class = 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'
14+
if flatpage_middleware_class not in settings.MIDDLEWARE_CLASSES:
15+
settings.MIDDLEWARE_CLASSES += (flatpage_middleware_class,)
16+
self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
17+
settings.TEMPLATE_DIRS = (
18+
os.path.join(
19+
os.path.dirname(__file__),
20+
'templates'
21+
),
22+
)
23+
self.me = User.objects.create_user('testuser', '[email protected]', 's3krit')
24+
25+
def tearDown(self):
26+
settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES
27+
settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
28+
29+
def test_get_flatpages_tag(self):
30+
"The flatpage template tag retrives unregistered prefixed flatpages by default"
31+
out = Template(
32+
"{% load flatpages %}"
33+
"{% get_flatpages as flatpages %}"
34+
"{% for page in flatpages %}"
35+
"{{ page.title }},"
36+
"{% endfor %}"
37+
).render(Context())
38+
self.assertEquals(out, "A Flatpage,A Nested Flatpage,")
39+
40+
def test_get_flatpages_tag_for_anon_user(self):
41+
"The flatpage template tag retrives unregistered flatpages for an anonymous user"
42+
out = Template(
43+
"{% load flatpages %}"
44+
"{% get_flatpages for anonuser as flatpages %}"
45+
"{% for page in flatpages %}"
46+
"{{ page.title }},"
47+
"{% endfor %}"
48+
).render(Context({
49+
'anonuser': AnonymousUser()
50+
}))
51+
self.assertEquals(out, "A Flatpage,A Nested Flatpage,")
52+
53+
def test_get_flatpages_tag_for_user(self):
54+
"The flatpage template tag retrives all flatpages for an authenticated user"
55+
out = Template(
56+
"{% load flatpages %}"
57+
"{% get_flatpages for me as flatpages %}"
58+
"{% for page in flatpages %}"
59+
"{{ page.title }},"
60+
"{% endfor %}"
61+
).render(Context({
62+
'me': self.me
63+
}))
64+
self.assertEquals(out, "A Flatpage,A Nested Flatpage,Sekrit Nested Flatpage,Sekrit Flatpage,")
65+
66+
def test_get_flatpages_with_prefix(self):
67+
"The flatpage template tag retrives unregistered prefixed flatpages by default"
68+
out = Template(
69+
"{% load flatpages %}"
70+
"{% get_flatpages '/location/' as location_flatpages %}"
71+
"{% for page in location_flatpages %}"
72+
"{{ page.title }},"
73+
"{% endfor %}"
74+
).render(Context())
75+
self.assertEquals(out, "A Nested Flatpage,")
76+
77+
def test_get_flatpages_with_prefix_for_anon_user(self):
78+
"The flatpage template tag retrives unregistered prefixed flatpages for an anonymous user"
79+
out = Template(
80+
"{% load flatpages %}"
81+
"{% get_flatpages '/location/' for anonuser as location_flatpages %}"
82+
"{% for page in location_flatpages %}"
83+
"{{ page.title }},"
84+
"{% endfor %}"
85+
).render(Context({
86+
'anonuser': AnonymousUser()
87+
}))
88+
self.assertEquals(out, "A Nested Flatpage,")
89+
90+
def test_get_flatpages_with_prefix_for_user(self):
91+
"The flatpage template tag retrive prefixed flatpages for an authenticated user"
92+
out = Template(
93+
"{% load flatpages %}"
94+
"{% get_flatpages '/location/' for me as location_flatpages %}"
95+
"{% for page in location_flatpages %}"
96+
"{{ page.title }},"
97+
"{% endfor %}"
98+
).render(Context({
99+
'me': self.me
100+
}))
101+
self.assertEquals(out, "A Nested Flatpage,Sekrit Nested Flatpage,")
102+
103+
def test_get_flatpages_with_variable_prefix(self):
104+
"The prefix for the flatpage template tag can be a template variable"
105+
out = Template(
106+
"{% load flatpages %}"
107+
"{% get_flatpages location_prefix as location_flatpages %}"
108+
"{% for page in location_flatpages %}"
109+
"{{ page.title }},"
110+
"{% endfor %}"
111+
).render(Context({
112+
'location_prefix': '/location/'
113+
}))
114+
self.assertEquals(out, "A Nested Flatpage,")
115+
116+
def test_parsing_errors(self):
117+
"There are various ways that the flatpages template tag won't parse"
118+
render = lambda t: Template(t).render(Context())
119+
120+
self.assertRaises(TemplateSyntaxError, render,
121+
"{% load flatpages %}{% get_flatpages %}")
122+
self.assertRaises(TemplateSyntaxError, render,
123+
"{% load flatpages %}{% get_flatpages as %}")
124+
self.assertRaises(TemplateSyntaxError, render,
125+
"{% load flatpages %}{% get_flatpages cheesecake flatpages %}")
126+
self.assertRaises(TemplateSyntaxError, render,
127+
"{% load flatpages %}{% get_flatpages as flatpages asdf%}")
128+
self.assertRaises(TemplateSyntaxError, render,
129+
"{% load flatpages %}{% get_flatpages cheesecake user as flatpages %}")
130+
self.assertRaises(TemplateSyntaxError, render,
131+
"{% load flatpages %}{% get_flatpages for user as flatpages asdf%}")
132+
self.assertRaises(TemplateSyntaxError, render,
133+
"{% load flatpages %}{% get_flatpages prefix for user as flatpages asdf%}")
134+

django/contrib/flatpages/tests/views.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
from django.conf import settings
3+
from django.contrib.auth.models import User
34
from django.test import TestCase
45

56
class FlatpageViewTests(TestCase):
@@ -38,6 +39,11 @@ def test_view_authenticated_flatpage(self):
3839
"A flatpage served through a view can require authentication"
3940
response = self.client.get('/flatpage_root/sekrit/')
4041
self.assertRedirects(response, '/accounts/login/?next=/flatpage_root/sekrit/')
42+
User.objects.create_user('testuser', '[email protected]', 's3krit')
43+
self.client.login(username='testuser',password='s3krit')
44+
response = self.client.get('/flatpage_root/sekrit/')
45+
self.assertEquals(response.status_code, 200)
46+
self.assertContains(response, "<p>Isn't it sekrit!</p>")
4147

4248
def test_fallback_flatpage(self):
4349
"A fallback flatpage won't be served if the middleware is disabled"

0 commit comments

Comments
 (0)