Merge lp:~thumper/wikkid/script-name into lp:wikkid

Proposed by Tim Penhey
Status: Merged
Approved by: Tim Penhey
Approved revision: 85
Merged at revision: 70
Proposed branch: lp:~thumper/wikkid/script-name
Merge into: lp:wikkid
Diff against target: 622 lines (+193/-80)
15 files modified
bin/wikkid-serve (+5/-1)
setup.py (+2/-1)
wikkid/app.py (+35/-19)
wikkid/context.py (+13/-4)
wikkid/skin/default/base.html (+4/-4)
wikkid/tests/factory.py (+2/-2)
wikkid/tests/test_app.py (+40/-12)
wikkid/tests/views/test_breadcrumbs.py (+13/-0)
wikkid/tests/views/test_root.py (+33/-2)
wikkid/tests/views/test_urls.py (+22/-17)
wikkid/view/base.py (+13/-9)
wikkid/view/directory.py (+5/-5)
wikkid/view/edit.py (+1/-1)
wikkid/view/root.py (+2/-0)
wikkid/view/urls.py (+3/-3)
To merge this branch: bzr merge lp:~thumper/wikkid/script-name
Reviewer Review Type Date Requested Status
Tim Penhey Approve
Review via email: mp+106141@code.launchpad.net

Description of the change

Allow wikkid-serve to specify a script-name. This is the assumed to be the start of any request for a wikkid served page. If not, a 404 is returned.

Styling and links are updated to use the script-name.

To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :

I approve :-)

review: Approve
lp:~thumper/wikkid/script-name updated
86. By Tim Penhey

Have the views use their own canonical_url function that uses the request object.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bin/wikkid-serve'
--- bin/wikkid-serve 2011-03-09 21:34:46 +0000
+++ bin/wikkid-serve 2012-05-17 11:13:18 +0000
@@ -58,12 +58,16 @@
58 '--default-format', type='string', default=DEFAULT_FORMAT,58 '--default-format', type='string', default=DEFAULT_FORMAT,
59 help=("Specify the default wiki format to use. Defaults to %r"59 help=("Specify the default wiki format to use. Defaults to %r"
60 % DEFAULT_FORMAT))60 % DEFAULT_FORMAT))
61 parser.add_option(
62 '--script-name',
63 help=('The SCRIPT_NAME for the environment. This is the prefix for the URLs'))
61 options, args = parser.parse_args(sys.argv[1:])64 options, args = parser.parse_args(sys.argv[1:])
6265
63 execution_context = ExecutionContext(66 execution_context = ExecutionContext(
64 host=options.host,67 host=options.host,
65 port=options.port,68 port=options.port,
66 default_format=options.default_format)69 default_format=options.default_format,
70 script_name=options.script_name)
6771
68 if len(args) == 0:72 if len(args) == 0:
69 print "No branch location specified.\n"73 print "No branch location specified.\n"
7074
=== modified file 'setup.py'
--- setup.py 2011-06-29 09:21:55 +0000
+++ setup.py 2012-05-17 11:13:18 +0000
@@ -31,7 +31,8 @@
31 'zope.interface',31 'zope.interface',
32 ],32 ],
33 test_requires=[33 test_requires=[
34 'beautifulsoup',34 'bs4',
35 'bzrlib.tests',
35 'testtools',36 'testtools',
36 ],37 ],
37 test_suite='wikkid.tests',38 test_suite='wikkid.tests',
3839
=== modified file 'wikkid/app.py'
--- wikkid/app.py 2010-11-22 00:00:31 +0000
+++ wikkid/app.py 2012-05-17 11:13:18 +0000
@@ -11,6 +11,7 @@
11import mimetypes11import mimetypes
12import os.path12import os.path
13import urllib13import urllib
14from wsgiref.util import shift_path_info
1415
15from bzrlib import urlutils16from bzrlib import urlutils
16from webob import Request, Response17from webob import Request, Response
@@ -59,35 +60,50 @@
59 self.skin = Skin(skin_name)60 self.skin = Skin(skin_name)
60 self.logger = logging.getLogger('wikkid')61 self.logger = logging.getLogger('wikkid')
6162
62 def __call__(self, environ, start_response):63 def process_call(self, environ):
63 """The WSGI bit."""64 """The actual implementation of dealing with the call."""
65 # TODO: reject requests that aren't GET or POST
64 request = Request(environ)66 request = Request(environ)
65
66 # TODO: reject requests that aren't GET or POST
67 path = urllib.unquote(request.path)67 path = urllib.unquote(request.path)
68 script_name = self.execution_context.script_name
69 if not path.startswith(script_name + '/'):
70 return HTTPNotFound()
71
72 shifted_prefix = ''
73 while shifted_prefix != script_name:
74 shifted = shift_path_info(environ)
75 shifted_prefix = '{0}/{1}'.format(shifted_prefix, shifted)
76 # Now we are just interested in the path_info having ignored the
77 # script name.
78 path = urllib.unquote(request.path_info)
79
68 if path == '/favicon.ico':80 if path == '/favicon.ico':
69 if self.skin.favicon is not None:81 if self.skin.favicon is not None:
70 response = serve_file(self.skin.favicon)82 return serve_file(self.skin.favicon)
71 else:83 else:
72 response = HTTPNotFound()84 return HTTPNotFound()
73 elif path.startswith('/static/'):85
86 if path.startswith('/static/'):
74 if self.skin.static_dir is not None:87 if self.skin.static_dir is not None:
75 static_dir = self.skin.static_dir.rstrip(os.sep) + os.sep88 static_dir = self.skin.static_dir.rstrip(os.sep) + os.sep
76 static_file = os.path.abspath(89 static_file = os.path.abspath(
77 urlutils.joinpath(static_dir, path[8:]))90 urlutils.joinpath(static_dir, path[8:]))
78 if static_file.startswith(static_dir):91 if static_file.startswith(static_dir):
79 response = serve_file(static_file)92 return serve_file(static_file)
80 else:93 else:
81 response = HTTPNotFound()94 return HTTPNotFound()
82 else:95 else:
83 response = HTTPNotFound()96 return HTTPNotFound()
84 else:97
85 resource_path, action = parse_url(path)98 resource_path, action = parse_url(path)
86 model = self.resource_factory.get_resource_at_path(resource_path)99 model = self.resource_factory.get_resource_at_path(resource_path)
87 try:100 try:
88 view = get_view(model, action, request, self.execution_context)101 view = get_view(model, action, request, self.execution_context)
89 response = view.render(self.skin)102 return view.render(self.skin)
90 except HTTPException, e:103 except HTTPException, e:
91 response = e104 return e
92105
106 def __call__(self, environ, start_response):
107 """The WSGI bit."""
108 response = self.process_call(environ)
93 return response(environ, start_response)109 return response(environ, start_response)
94110
=== modified file 'wikkid/context.py'
--- wikkid/context.py 2010-11-22 00:00:31 +0000
+++ wikkid/context.py 2012-05-17 11:13:18 +0000
@@ -1,6 +1,6 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2#2#
3# Copyright (C) 2010 Wikkid Developers.3# Copyright (C) 2010-2012 Wikkid Developers.
4#4#
5# This software is licensed under the GNU Affero General Public License5# This software is licensed under the GNU Affero General Public License
6# version 3 (see the file LICENSE).6# version 3 (see the file LICENSE).
@@ -13,9 +13,13 @@
1313
1414
15class ExecutionContext(object):15class ExecutionContext(object):
16 """Store run-time execution context data."""16 """Store run-time execution context data.
1717
18 def __init__(self, host=None, port=None, default_format=None):18 This is the Encapsulate Context pattern.
19 """
20
21 def __init__(self, host=None, port=None, default_format=None,
22 script_name=None):
19 """Create an execution context for the application.23 """Create an execution context for the application.
2024
21 :param host: The hostname that content is being served from.25 :param host: The hostname that content is being served from.
@@ -32,3 +36,8 @@
32 self.host = host36 self.host = host
33 self.port = port37 self.port = port
34 self.default_format = default_format38 self.default_format = default_format
39 # TODO: make sure the script_name if set starts with a slash and
40 # doesn't finish with one.
41 if script_name is None:
42 script_name = ''
43 self.script_name = script_name
3544
=== modified file 'wikkid/skin/default/base.html'
--- wikkid/skin/default/base.html 2010-07-13 12:49:52 +0000
+++ wikkid/skin/default/base.html 2012-05-17 11:13:18 +0000
@@ -5,14 +5,14 @@
5 <title>{% block title %}{% endblock %} - Wikkid</title>5 <title>{% block title %}{% endblock %} - Wikkid</title>
66
7 <link type="text/css" rel="stylesheet" media="screen, print"7 <link type="text/css" rel="stylesheet" media="screen, print"
8 href="/static/default.css" />8 href="{{ request.script_name }}/static/default.css" />
9 <link rel="shortcut icon" href="/favicon.ico" />9 <link rel="shortcut icon" href="{{ request.script_name }}/favicon.ico" />
10 {% endblock %}10 {% endblock %}
11</head>11</head>
12<body>12<body>
13<div id="container">13<div id="container">
14 <div id="header">14 <div id="header">
15 <div class="wikkidlogo"><a href="/"><strong>Wikkid Wiki</strong></a></div>15 <div class="wikkidlogo"><a href="{{ request.script_name }}/"><strong>Wikkid Wiki</strong></a></div>
16 <div id="logged">16 <div id="logged">
17 {% if view.user %}17 {% if view.user %}
1818
@@ -44,7 +44,7 @@
44 </div>44 </div>
45 {% block footer %}{% endblock %}45 {% block footer %}{% endblock %}
46 <div id="footer">46 <div id="footer">
47 &copy; 201047 &copy; 2010-2012
48 <a href="https://launchpad.net/~wikkid">Wikkid Hackers</a>,48 <a href="https://launchpad.net/~wikkid">Wikkid Hackers</a>,
49 All rights reserved.49 All rights reserved.
50 </div>50 </div>
5151
=== modified file 'wikkid/tests/factory.py'
--- wikkid/tests/factory.py 2010-06-15 09:05:29 +0000
+++ wikkid/tests/factory.py 2012-05-17 11:13:18 +0000
@@ -26,7 +26,7 @@
26class ViewTestCase(FactoryTestCase):26class ViewTestCase(FactoryTestCase):
27 """A factory test case that can create views."""27 """A factory test case that can create views."""
2828
29 def get_view(self, factory, path, name=None):29 def get_view(self, factory, path, name=None, base_url=None):
30 info = factory.get_resource_at_path(path)30 info = factory.get_resource_at_path(path)
31 request = Request.blank(path)31 request = Request.blank(path, base_url=base_url)
32 return get_view(info, name, request)32 return get_view(info, name, request)
3333
=== modified file 'wikkid/tests/test_app.py'
--- wikkid/tests/test_app.py 2011-04-23 08:18:58 +0000
+++ wikkid/tests/test_app.py 2012-05-17 11:13:18 +0000
@@ -11,25 +11,28 @@
11from webob.request import environ_from_url11from webob.request import environ_from_url
1212
13from wikkid.app import WikkidApp13from wikkid.app import WikkidApp
14from wikkid.context import ExecutionContext
14from wikkid.filestore.volatile import FileStore15from wikkid.filestore.volatile import FileStore
15from wikkid.tests import TestCase16from wikkid.tests import TestCase
1617
1718
18class TestApp(TestCase):19class TestApp(TestCase):
1920
21 def assert_not_found(self, status, headers):
22 self.assertEqual("404 Not Found", status)
23
24 def assert_ok(self, status, headers):
25 self.assertEqual("200 OK", status)
26
20 def test_traverse_above_static_not_possible_with_relative_path(self):27 def test_traverse_above_static_not_possible_with_relative_path(self):
21 """28 """
22 Traversal above the static folder, by forging a malicious request with29 Traversal above the static folder, by forging a malicious request with
23 a relative path for example, is not possible.30 a relative path for example, is not possible.
24 """31 """
25 environ = environ_from_url("/static/../page.html")32 environ = environ_from_url("/static/../page.html")
26
27 def start_response(status, headers):
28 self.assertEqual("404 Not Found", status)
29
30 filestore = FileStore()33 filestore = FileStore()
31 app = WikkidApp(filestore)34 app = WikkidApp(filestore)
32 app(environ, start_response)35 app(environ, self.assert_not_found)
3336
34 def test_traverse_above_static_not_possible_with_absolute_path(self):37 def test_traverse_above_static_not_possible_with_absolute_path(self):
35 """38 """
@@ -38,10 +41,35 @@
38 """41 """
39 this_file = os.path.abspath(__file__)42 this_file = os.path.abspath(__file__)
40 environ = environ_from_url("/static/" + this_file)43 environ = environ_from_url("/static/" + this_file)
4144 filestore = FileStore()
42 def start_response(status, headers):45 app = WikkidApp(filestore)
43 self.assertEqual("404 Not Found", status)46 app(environ, self.assert_not_found)
4447
45 filestore = FileStore()48 def test_getting_static_style_css_works(self):
46 app = WikkidApp(filestore)49
47 app(environ, start_response)50 environ = environ_from_url("/static/default.css")
51 filestore = FileStore()
52 app = WikkidApp(filestore)
53 app(environ, self.assert_ok)
54
55 def test_getting_static_style_css_works_with_script_name(self):
56
57 environ = environ_from_url("/test/static/default.css")
58 filestore = FileStore()
59 context = ExecutionContext(script_name="/test")
60 app = WikkidApp(filestore, execution_context=context)
61 app(environ, self.assert_ok)
62
63 def test_getting_static_style_css_works_with_script_name_multiple_segments(self):
64 environ = environ_from_url("/p/project-name/wiki/static/default.css")
65 filestore = FileStore()
66 context = ExecutionContext(script_name="/p/project-name/wiki")
67 app = WikkidApp(filestore, execution_context=context)
68 app(environ, self.assert_ok)
69
70 def test_getting_anything_outside_script_name_fails(self):
71 environ = environ_from_url("/foo/bar")
72 filestore = FileStore()
73 context = ExecutionContext(script_name="/test")
74 app = WikkidApp(filestore, execution_context=context)
75 app(environ, self.assert_not_found)
4876
=== modified file 'wikkid/tests/views/test_breadcrumbs.py'
--- wikkid/tests/views/test_breadcrumbs.py 2010-06-15 09:05:29 +0000
+++ wikkid/tests/views/test_breadcrumbs.py 2012-05-17 11:13:18 +0000
@@ -107,3 +107,16 @@
107 ('wiki root', '/+listing'),107 ('wiki root', '/+listing'),
108 ('SomePage', '/SomePage/+listing'),108 ('SomePage', '/SomePage/+listing'),
109 ('SubPage', '/SomePage/SubPage')])109 ('SubPage', '/SomePage/SubPage')])
110
111 def test_directory_breadcrumbs_nested_with_script_name(self):
112 # For each directory after the root, a listing crumb is added.
113 # Names are not wiki expanded.
114 factory = self.make_factory([
115 ('SomePage/SubPage/Nested.txt', 'some text')])
116 view = self.get_view(factory, '/SomePage/SubPage', 'listing', '/p/wiki')
117 self.assertBreadcrumbs(
118 view,
119 [('Home', '/p/wiki/Home'),
120 ('wiki root', '/p/wiki/+listing'),
121 ('SomePage', '/p/wiki/SomePage/+listing'),
122 ('SubPage', '/p/wiki/SomePage/SubPage')])
110123
=== modified file 'wikkid/tests/views/test_root.py'
--- wikkid/tests/views/test_root.py 2010-06-17 10:45:52 +0000
+++ wikkid/tests/views/test_root.py 2012-05-17 11:13:18 +0000
@@ -6,16 +6,19 @@
66
7"""Test views for the root object."""7"""Test views for the root object."""
88
9from bs4 import BeautifulSoup
10from testtools.matchers import Equals
9from webob.exc import HTTPSeeOther11from webob.exc import HTTPSeeOther
1012
13from wikkid.skin.loader import Skin
11from wikkid.tests.factory import ViewTestCase14from wikkid.tests.factory import ViewTestCase
1215
1316
14class TestRootViews(ViewTestCase):17class TestRootViews(ViewTestCase):
15 """Test the views on the root object."""18 """Test the views on the root object."""
1619
17 def test_last_modified_by(self):20 def test_root_redirects(self):
18 """Test that the last committer is displayed properly"""21 """Going to / redirects to the Home page."""
19 factory = self.make_factory()22 factory = self.make_factory()
20 view = self.get_view(factory, '/')23 view = self.get_view(factory, '/')
21 error = self.assertRaises(24 error = self.assertRaises(
@@ -23,3 +26,31 @@
23 view.render,26 view.render,
24 None)27 None)
25 self.assertEqual('/Home', error.headers['Location'])28 self.assertEqual('/Home', error.headers['Location'])
29
30 def test_root_redirects_with_script_name(self):
31 """Redirection works and respects the script name"""
32 factory = self.make_factory()
33 view = self.get_view(factory, '/', base_url='/p/test')
34 error = self.assertRaises(
35 HTTPSeeOther,
36 view.render,
37 None)
38 self.assertEqual('/p/test/Home', error.headers['Location'])
39
40 def test_home_rendering(self):
41 """Render the home page and test the elements."""
42 factory = self.make_factory()
43 view = self.get_view(factory, '/Home')
44 content = view.render(Skin('default'))
45 soup = BeautifulSoup(content.text)
46 [style] = soup.find_all('link', {'rel':'stylesheet'})
47 self.assertThat(style['href'], Equals('/static/default.css'))
48
49 def test_home_rendering_with_script_name(self):
50 """Render the home page and test the elements."""
51 factory = self.make_factory()
52 view = self.get_view(factory, '/Home', base_url='/p/test')
53 content = view.render(Skin('default'))
54 soup = BeautifulSoup(content.text)
55 [style] = soup.find_all('link', {'rel':'stylesheet'})
56 self.assertThat(style['href'], Equals('/p/test/static/default.css'))
2657
=== modified file 'wikkid/tests/views/test_urls.py'
--- wikkid/tests/views/test_urls.py 2010-06-16 10:29:35 +0000
+++ wikkid/tests/views/test_urls.py 2012-05-17 11:13:18 +0000
@@ -6,6 +6,9 @@
66
7"""Tests the edit views."""7"""Tests the edit views."""
88
9from testtools.matchers import Equals
10from webob import Request
11
9from wikkid.tests import TestCase12from wikkid.tests import TestCase
10from wikkid.tests.factory import FactoryTestCase13from wikkid.tests.factory import FactoryTestCase
11from wikkid.view.urls import canonical_url, parse_url14from wikkid.view.urls import canonical_url, parse_url
@@ -14,84 +17,86 @@
14class TestCanonicalUrl(FactoryTestCase):17class TestCanonicalUrl(FactoryTestCase):
15 """Test the wikkid.view.base.canonical_url."""18 """Test the wikkid.view.base.canonical_url."""
1619
20 def assertUrl(self, resource, url, view_name=None, base_url=None):
21 request = Request.blank('/', base_url=base_url)
22 self.assertThat(canonical_url(resource, request, view_name),
23 Equals(url))
24
17 def test_root(self):25 def test_root(self):
18 factory = self.make_factory()26 factory = self.make_factory()
19 root = factory.get_resource_at_path('/')27 root = factory.get_resource_at_path('/')
20 self.assertEqual('/', canonical_url(root))28 self.assertUrl(root, '/')
2129
22 def test_root_listing(self):30 def test_root_listing(self):
23 factory = self.make_factory()31 factory = self.make_factory()
24 root = factory.get_resource_at_path('/')32 root = factory.get_resource_at_path('/')
25 self.assertEqual('/+listing', canonical_url(root, 'listing'))33 self.assertUrl(root, '/+listing', view_name='listing')
2634
27 def test_default(self):35 def test_default(self):
28 factory = self.make_factory([36 factory = self.make_factory([
29 ('Home.txt', 'Some content'),37 ('Home.txt', 'Some content'),
30 ])38 ])
31 root = factory.get_resource_at_path('/')39 root = factory.get_resource_at_path('/')
32 self.assertEqual('/Home', canonical_url(root.default_resource))40 self.assertUrl(root.default_resource, '/Home')
3341
34 def test_default_view(self):42 def test_default_view(self):
35 factory = self.make_factory([43 factory = self.make_factory([
36 ('Home.txt', 'Some content'),44 ('Home.txt', 'Some content'),
37 ])45 ])
38 root = factory.get_resource_at_path('/')46 root = factory.get_resource_at_path('/')
39 self.assertEqual(47 self.assertUrl(root.default_resource, '/Home/+edit', view_name='edit')
40 '/Home/+edit',
41 canonical_url(root.default_resource, 'edit'))
4248
43 def test_wiki_page(self):49 def test_wiki_page(self):
44 factory = self.make_factory([50 factory = self.make_factory([
45 ('SomeDir/SomePage.txt', 'Some content'),51 ('SomeDir/SomePage.txt', 'Some content'),
46 ])52 ])
47 page = factory.get_resource_at_path('/SomeDir/SomePage')53 page = factory.get_resource_at_path('/SomeDir/SomePage')
48 self.assertEqual('/SomeDir/SomePage', canonical_url(page))54 self.assertUrl(page, '/SomeDir/SomePage')
4955
50 def test_wiki_page_view(self):56 def test_wiki_page_view(self):
51 factory = self.make_factory([57 factory = self.make_factory([
52 ('SomeDir/SomePage.txt', 'Some content'),58 ('SomeDir/SomePage.txt', 'Some content'),
53 ])59 ])
54 page = factory.get_resource_at_path('/SomeDir/SomePage')60 page = factory.get_resource_at_path('/SomeDir/SomePage')
55 self.assertEqual(61 self.assertUrl(page, '/SomeDir/SomePage/+edit', view_name='edit')
56 '/SomeDir/SomePage/+edit', canonical_url(page, 'edit'))
5762
58 def test_wiki_page_full_url(self):63 def test_wiki_page_full_url(self):
59 factory = self.make_factory([64 factory = self.make_factory([
60 ('SomeDir.txt', 'Some content'),65 ('SomeDir.txt', 'Some content'),
61 ])66 ])
62 page = factory.get_resource_at_path('/SomeDir.txt')67 page = factory.get_resource_at_path('/SomeDir.txt')
63 self.assertEqual('/SomeDir', canonical_url(page))68 self.assertUrl(page, '/SomeDir')
6469
65 def test_wiki_page_full_url_with_view(self):70 def test_wiki_page_full_url_with_view(self):
66 factory = self.make_factory([71 factory = self.make_factory([
67 ('SomeDir.txt', 'Some content'),72 ('SomeDir.txt', 'Some content'),
68 ])73 ])
69 page = factory.get_resource_at_path('/SomeDir.txt')74 page = factory.get_resource_at_path('/SomeDir.txt')
70 self.assertEqual('/SomeDir/+edit', canonical_url(page, 'edit'))75 self.assertUrl(page, '/SomeDir/+edit', view_name='edit')
7176
72 def test_other_file(self):77 def test_other_file(self):
73 factory = self.make_factory([78 factory = self.make_factory([
74 ('simple.py', '#!/usr/bin/python'),79 ('simple.py', '#!/usr/bin/python'),
75 ])80 ])
76 page = factory.get_resource_at_path('/simple.py')81 page = factory.get_resource_at_path('/simple.py')
77 self.assertEqual('/simple.py', canonical_url(page))82 self.assertUrl(page, '/simple.py')
7883
79 def test_other_file_view(self):84 def test_other_file_view(self):
80 factory = self.make_factory([85 factory = self.make_factory([
81 ('simple.py', '#!/usr/bin/python'),86 ('simple.py', '#!/usr/bin/python'),
82 ])87 ])
83 page = factory.get_resource_at_path('/simple.py')88 page = factory.get_resource_at_path('/simple.py')
84 self.assertEqual('/simple.py/+edit', canonical_url(page, 'edit'))89 self.assertUrl(page, '/simple.py/+edit', view_name='edit')
8590
86 def test_missing(self):91 def test_missing(self):
87 factory = self.make_factory()92 factory = self.make_factory()
88 root = factory.get_resource_at_path('/MissingPage')93 missing = factory.get_resource_at_path('/MissingPage')
89 self.assertEqual('/MissingPage', canonical_url(root))94 self.assertUrl(missing, '/MissingPage')
9095
91 def test_missing_view(self):96 def test_missing_view(self):
92 factory = self.make_factory()97 factory = self.make_factory()
93 root = factory.get_resource_at_path('/MissingPage')98 missing = factory.get_resource_at_path('/MissingPage')
94 self.assertEqual('/MissingPage/+edit', canonical_url(root, 'edit'))99 self.assertUrl(missing, '/MissingPage/+edit', view_name='edit')
95100
96101
97class TestParseUrl(TestCase):102class TestParseUrl(TestCase):
98103
=== modified file 'wikkid/view/base.py'
--- wikkid/view/base.py 2010-11-22 09:23:40 +0000
+++ wikkid/view/base.py 2012-05-17 11:13:18 +0000
@@ -29,8 +29,8 @@
29class Breadcrumb(object):29class Breadcrumb(object):
30 """Breadcrumbs exist to give the user quick links up the path chain."""30 """Breadcrumbs exist to give the user quick links up the path chain."""
3131
32 def __init__(self, context, view=None, title=None):32 def __init__(self, context, request, view=None, title=None):
33 self.path = canonical_url(context, view)33 self.path = canonical_url(context, request, view)
34 if title is None:34 if title is None:
35 self.title = title_for_filename(context.base_name)35 self.title = title_for_filename(context.base_name)
36 else:36 else:
@@ -54,14 +54,14 @@
54 self.logger = logging.getLogger('wikkid')54 self.logger = logging.getLogger('wikkid')
5555
56 def _create_breadcrumbs(self):56 def _create_breadcrumbs(self):
57 crumbs = [Breadcrumb(self.context)]57 crumbs = [Breadcrumb(self.context, self.request)]
58 current = self.context.parent58 current = self.context.parent
59 while not IRootResource.providedBy(current):59 while not IRootResource.providedBy(current):
60 crumbs.append(Breadcrumb(current))60 crumbs.append(Breadcrumb(current, self.request))
61 current = current.parent61 current = current.parent
62 # And add in the default page if the context isn't the default.62 # And add in the default page if the context isn't the default.
63 if not IDefaultPage.providedBy(self.context):63 if not IDefaultPage.providedBy(self.context):
64 crumbs.append(Breadcrumb(current.default_resource))64 crumbs.append(Breadcrumb(current.default_resource, self.request))
65 return reversed(crumbs)65 return reversed(crumbs)
6666
67 def initialize(self):67 def initialize(self):
@@ -89,6 +89,9 @@
89 def before_render(self):89 def before_render(self):
90 """A hook to do things before rendering."""90 """A hook to do things before rendering."""
9191
92 def canonical_url(self, context, view=None):
93 return canonical_url(context, self.request, view)
94
92 def template_args(self):95 def template_args(self):
93 """Needs to be implemented in the derived classes.96 """Needs to be implemented in the derived classes.
9497
@@ -99,7 +102,7 @@
99 'user': self.user,102 'user': self.user,
100 'context': self.context,103 'context': self.context,
101 'request': self.request,104 'request': self.request,
102 'canonical_url': canonical_url,105 'canonical_url': self.canonical_url,
103 }106 }
104107
105 def _render(self, skin):108 def _render(self, skin):
@@ -139,12 +142,13 @@
139 view = None142 view = None
140 while not IRootResource.providedBy(current):143 while not IRootResource.providedBy(current):
141 crumbs.append(Breadcrumb(144 crumbs.append(Breadcrumb(
142 current, view, title=current.base_name))145 current, self.request, view, title=current.base_name))
143 current = current.parent146 current = current.parent
144 # Add listings to subsequent urls.147 # Add listings to subsequent urls.
145 view = 'listing'148 view = 'listing'
146 # Add in the root dir.149 # Add in the root dir.
147 crumbs.append(Breadcrumb(current, 'listing', title='wiki root'))150 crumbs.append(Breadcrumb(current, self.request, 'listing',
151 title='wiki root'))
148 # And add in the default page.152 # And add in the default page.
149 crumbs.append(Breadcrumb(current.default_resource))153 crumbs.append(Breadcrumb(current.default_resource, self.request))
150 return reversed(crumbs)154 return reversed(crumbs)
151155
=== modified file 'wikkid/view/directory.py'
--- wikkid/view/directory.py 2010-06-23 10:57:14 +0000
+++ wikkid/view/directory.py 2012-05-17 11:13:18 +0000
@@ -14,9 +14,9 @@
14class ListingItem(object):14class ListingItem(object):
15 """An item to be shown in the directory listing."""15 """An item to be shown in the directory listing."""
1616
17 def __init__(self, context, view, css_class, name=None):17 def __init__(self, context, request, view, css_class, name=None):
18 self.context = context18 self.context = context
19 self.url = canonical_url(self.context, view)19 self.url = canonical_url(self.context, request, view)
20 if name is None:20 if name is None:
21 name = context.base_name21 name = context.base_name
22 self.name = name22 self.name = name
@@ -53,11 +53,11 @@
53 if self.context.path != '/':53 if self.context.path != '/':
54 parent = self.context.parent54 parent = self.context.parent
55 items.append(55 items.append(
56 ListingItem(parent, 'listing', 'up', name='..'))56 ListingItem(parent, self.request, 'listing', 'up', name='..'))
57 for item in sorted(directories, key=sort_key):57 for item in sorted(directories, key=sort_key):
58 items.append(ListingItem(item, 'listing', 'directory'))58 items.append(ListingItem(item, self.request, 'listing', 'directory'))
59 for item in sorted(files, key=sort_key):59 for item in sorted(files, key=sort_key):
60 items.append(ListingItem(item, None, 'file'))60 items.append(ListingItem(item, self.request, None, 'file'))
61 self.items = items61 self.items = items
6262
63 @property63 @property
6464
=== modified file 'wikkid/view/edit.py'
--- wikkid/view/edit.py 2010-06-17 10:45:52 +0000
+++ wikkid/view/edit.py 2012-05-17 11:13:18 +0000
@@ -24,7 +24,7 @@
24 @property24 @property
25 def save_url(self):25 def save_url(self):
26 """The link for the cancel button."""26 """The link for the cancel button."""
27 return canonical_url(self.context, 'save')27 return canonical_url(self.context, self.request, 'save')
2828
29 @property29 @property
30 def cancel_url(self):30 def cancel_url(self):
3131
=== modified file 'wikkid/view/root.py'
--- wikkid/view/root.py 2010-06-17 10:45:52 +0000
+++ wikkid/view/root.py 2012-05-17 11:13:18 +0000
@@ -23,4 +23,6 @@
23 """Redirect to Home (or the default page)."""23 """Redirect to Home (or the default page)."""
24 default_resource = self.context.default_resource24 default_resource = self.context.default_resource
25 preferred = default_resource.preferred_path25 preferred = default_resource.preferred_path
26 if self.request.script_name:
27 preferred = self.request.script_name + preferred
26 raise HTTPSeeOther(location=preferred)28 raise HTTPSeeOther(location=preferred)
2729
=== modified file 'wikkid/view/urls.py'
--- wikkid/view/urls.py 2010-06-16 10:29:35 +0000
+++ wikkid/view/urls.py 2012-05-17 11:13:18 +0000
@@ -24,12 +24,12 @@
24 return (path, None)24 return (path, None)
2525
2626
27def canonical_url(context, view=None):27def canonical_url(context, request, view=None):
28 """The one true URL for the context object."""28 """The one true URL for the context object."""
29 path = context.preferred_path29 path = context.preferred_path
30 if view is None:30 if view is None:
31 return path31 return '{0}{1}'.format(request.script_name, path)
32 else:32 else:
33 if path == '/':33 if path == '/':
34 path = ''34 path = ''
35 return '{0}/+{1}'.format(path, view)35 return '{0}{1}/+{2}'.format(request.script_name, path, view)

Subscribers

People subscribed via source and target branches