Skip to content

Commit 3e14142

Browse files
author
Resolver Systems Ltd
committed
T3214 Wrote basic tutorial server without content. By Giles & Hansel
1 parent 78693d1 commit 3e14142

9 files changed

Lines changed: 203 additions & 16 deletions

File tree

server/renderer/__init__.py

Whitespace-only changes.

server/renderer/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.db import models
2+
3+
# Create your models here.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2+
<html>
3+
<head>
4+
5+
<link rel="stylesheet" href="/static/anywhere/styles/common_base.css" type="text/css" media="screen" charset="utf-8" />
6+
<link rel="stylesheet" href="/static/anywhere/styles/tutorial.css" type="text/css" media="screen" charset="utf-8" />
7+
<link rel="stylesheet" href="/static/pygments/style.css" type="text/css" media="screen" charset="utf-8" />
8+
9+
<script type="text/javascript">
10+
parent.setHash({{ pagenum }});
11+
12+
var _gaq = _gaq || [];
13+
_gaq.push(['_setAccount', 'UA-18014859-6']);
14+
_gaq.push(['_trackPageview']);
15+
16+
(function() {
17+
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
18+
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
19+
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
20+
})();
21+
22+
</script>
23+
24+
<title>{{ title }}</title>
25+
26+
</head>
27+
28+
<body>
29+
{% autoescape off %}
30+
<h3>{{ title }}</h3>
31+
32+
{{ body }}
33+
{% endautoescape %}
34+
</body>
35+
</html>
36+
37+
38+
39+

server/renderer/tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from server.renderer.tests.test_views import *
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Copyright (c) 2011 Resolver Systems Ltd.
2+
# All Rights Reserved
3+
#
4+
5+
6+
from django.core.urlresolvers import reverse
7+
from django.http import Http404, HttpResponse, HttpResponsePermanentRedirect
8+
9+
from mock import Mock, patch
10+
import os
11+
12+
from resolver_test import ResolverViewTestCase
13+
14+
from server.renderer.views import render_view
15+
16+
17+
class RenderViewTest(ResolverViewTestCase):
18+
19+
@patch("server.renderer.views.os.path.exists")
20+
def test_render_view_404s_for_nonexistent_file(self, mock_exists):
21+
mock_exists.return_value = False
22+
23+
with self.assertRaises(Http404):
24+
render_view(self.request, '9')
25+
26+
27+
def test_render_view_404s_for_existing_file_outside_of_content_directory(self):
28+
29+
with self.assertRaises(Http404):
30+
render_view(self.request, '../../README')
31+
32+
33+
@patch("server.renderer.views.os.path.exists")
34+
@patch("server.renderer.views.publish_parts")
35+
@patch("server.renderer.views.render_to_response")
36+
def test_render_view_renders_rst_sensibly(self, mock_render, mock_publish_parts, mock_exists):
37+
mock_exists.return_value = True
38+
mock_open = Mock()
39+
read_results = "The rest contents"
40+
mock_open.return_value.__enter__ = Mock()
41+
mock_open.return_value.__enter__.return_value.read.return_value = read_results
42+
mock_open.return_value.__exit__ = Mock()
43+
44+
mock_publish_parts.return_value = {
45+
"title": "I am a dashing -- title",
46+
"body": "<div>I am a processed rest body with double --s</div>"
47+
}
48+
49+
50+
orig_open = open
51+
__builtins__['open'] = mock_open
52+
try:
53+
response = render_view(self.request, "foo")
54+
finally:
55+
__builtins__['open'] = orig_open
56+
57+
contents_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'content'))
58+
self.assertCalledOnce(mock_open, os.path.join(contents_dir, 'foo.txt'), "r")
59+
self.assertCalledOnce(mock_publish_parts, source=read_results, writer_name="html4css1")
60+
61+
self.assert_render_template_was(mock_render, "tutorial_base.html")
62+
self.assertRenderedWith(mock_render, "title", "I am a dashing &mdash; title")
63+
self.assertRenderedWith(mock_render, "body", "<div>I am a processed rest body with double &mdash;s</div>")
64+
65+
66+
def test_render_view_handles_root_request_sensibly(self):
67+
self.request.META['QUERY_STRING'] = ''
68+
69+
response = render_view(self.request, '')
70+
71+
self.assertIsInstance(response, HttpResponsePermanentRedirect)
72+
self.assertEquals(
73+
response['Location'],
74+
reverse('render_view', args=['index'])
75+
)
76+
77+
78+
79+
80+
81+

server/renderer/urls.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright (c) 2011 Resolver Systems Ltd.
2+
# All Rights Reserved
3+
#
4+
5+
from django.conf.urls.defaults import *
6+
from django.conf import settings
7+
8+
from anywhere.tutorial.views import render_tutorial_page, tutorial_root
9+
10+
11+
urlpatterns = patterns('',
12+
13+
url(
14+
'^tutorial/$',
15+
tutorial_root,
16+
name="tutorial_root"
17+
),
18+
19+
url(
20+
'^tutorial/(\d+)/$',
21+
render_tutorial_page,
22+
name="tutorial_page"
23+
),
24+
)

server/renderer/views.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright (c) 2011 Resolver Systems Ltd.
2+
# All Rights Reserved
3+
#
4+
5+
from docutils.core import publish_parts
6+
import os
7+
8+
from django.core.urlresolvers import reverse
9+
from django.http import Http404
10+
from django.shortcuts import render_to_response
11+
from django.views.generic.simple import redirect_to
12+
13+
14+
CONTENT_DIR = os.path.abspath(
15+
os.path.join(
16+
os.path.dirname(
17+
os.path.abspath(__file__)
18+
),
19+
'..', '..',
20+
"content",
21+
)
22+
)
23+
24+
25+
26+
def render_view(request, path):
27+
if path == '':
28+
return redirect_to(request, reverse("render_view", args=['index']))
29+
30+
filename = os.path.abspath(os.path.join(CONTENT_DIR, path + '.txt'))
31+
if not os.path.exists(filename) or not filename.startswith(CONTENT_DIR):
32+
raise Http404()
33+
34+
with open(filename, "r") as f:
35+
contents = f.read()
36+
37+
parts = publish_parts(source=contents, writer_name="html4css1")
38+
return render_to_response(
39+
"tutorial_base.html",
40+
{
41+
"title": __tidy_html(parts["title"]),
42+
"body": __tidy_html(parts["body"]),
43+
}
44+
)
45+
46+
47+
48+
def __tidy_html(html):
49+
return html.replace("--", "&mdash;")
50+
51+

server/settings.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,7 @@
116116
'django.contrib.sites',
117117
'django.contrib.messages',
118118
'django.contrib.staticfiles',
119-
# Uncomment the next line to enable the admin:
120-
# 'django.contrib.admin',
121-
# Uncomment the next line to enable admin documentation:
122-
# 'django.contrib.admindocs',
119+
'server.renderer'
123120
)
124121

125122
# A sample logging configuration. The only tangible logging

server/urls.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
11
from django.conf.urls.defaults import patterns, include, url
22

3-
# Uncomment the next two lines to enable the admin:
4-
# from django.contrib import admin
5-
# admin.autodiscover()
3+
from server.renderer.views import render_view
64

7-
urlpatterns = patterns('',
8-
# Examples:
9-
# url(r'^$', 'server.views.home', name='home'),
10-
# url(r'^server/', include('server.foo.urls')),
11-
12-
# Uncomment the admin/doc line below to enable admin documentation:
13-
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
145

15-
# Uncomment the next line to enable the admin:
16-
# url(r'^admin/', include(admin.site.urls)),
6+
urlpatterns = patterns('',
7+
url(r'^(.*)$', render_view, name='render_view')
178
)

0 commit comments

Comments
 (0)