diff options
| -rw-r--r-- | repoze/bfg/router.py | 19 | ||||
| -rw-r--r-- | repoze/bfg/sampleapp/app.py | 34 | ||||
| -rw-r--r-- | repoze/bfg/sampleapp/browser.py | 31 | ||||
| -rw-r--r-- | repoze/bfg/sampleapp/configure.zcml | 21 | ||||
| -rw-r--r-- | repoze/bfg/sampleapp/models.py | 30 | ||||
| -rw-r--r-- | repoze/bfg/sampleapp/run.py | 15 | ||||
| -rw-r--r-- | repoze/bfg/sampleapp/www/blog.pt | 19 | ||||
| -rw-r--r-- | repoze/bfg/sampleapp/www/blog_entry.pt | 12 | ||||
| -rw-r--r-- | repoze/bfg/sampleapp/www/blog_view.pt | 7 | ||||
| -rw-r--r-- | repoze/bfg/sampleapp/www/contents.pt | 6 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_router.py | 24 |
11 files changed, 155 insertions, 63 deletions
diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py index a15ac0e62..efc7406b6 100644 --- a/repoze/bfg/router.py +++ b/repoze/bfg/router.py @@ -4,6 +4,7 @@ from zope.interface import directlyProvides from webob import Request from webob.exc import HTTPNotFound +from webob.exc import HTTPFound from repoze.bfg.interfaces import IPublishTraverserFactory from repoze.bfg.interfaces import IViewFactory @@ -24,13 +25,19 @@ class Router: path = environ.get('PATH_INFO', '/') traverser = getMultiAdapter((root, request), IPublishTraverserFactory) context, name, subpath = traverser(path) - request.subpath = subpath - app = queryMultiAdapter((context, request), IViewFactory, name=name, - default=_marker) - if app is _marker: - app = HTTPNotFound(request.url) + if (not name) and (not path.endswith('/')): + # if this is the default view of the context, and the URL + # doesn't end in a slash, redirect to the url + '/' (so we + # don't have to play base tag games) + app = HTTPFound(add_slash=True) else: - app = getMultiAdapter((app, request), IWSGIApplicationFactory) + request.subpath = subpath + app = queryMultiAdapter((context, request), IViewFactory, name=name, + default=_marker) + if app is _marker: + app = HTTPNotFound(request.url) + else: + app = getMultiAdapter((app, request), IWSGIApplicationFactory) return app(environ, start_response) def make_app(root_policy, package=None, filename='configure.zcml'): diff --git a/repoze/bfg/sampleapp/app.py b/repoze/bfg/sampleapp/app.py deleted file mode 100644 index 777feb5ca..000000000 --- a/repoze/bfg/sampleapp/app.py +++ /dev/null @@ -1,34 +0,0 @@ -from repoze.bfg.template import TemplateView - -from webob import Response - -class BlogDefaultView(TemplateView): - def getInfo(self): - return {'greeting':'Hello, I\'m the default view', - 'id':self.context.id} - -class BlogWooHooView(TemplateView): - def getInfo(self): - return {'greeting':'Woo hoo, I\'m another view' , - 'id':self.context.id} - -class DefaultView(object): - def __init__(self, context, request): - self.context = context - self.request = request - - def __call__(self): - return Response('Default page, context is %s' % self.context) - -if __name__ == '__main__': - from repoze.bfg import sampleapp - from repoze.bfg.sampleapp.models import BlogModel - from repoze.bfg.router import make_app - blog = BlogModel('myblog') - root = {'blog':blog} - def get_root(environ): - return root - app = make_app(get_root, sampleapp) - from paste import httpserver - httpserver.serve(app, host='0.0.0.0', port='5432') - diff --git a/repoze/bfg/sampleapp/browser.py b/repoze/bfg/sampleapp/browser.py new file mode 100644 index 000000000..5dc354736 --- /dev/null +++ b/repoze/bfg/sampleapp/browser.py @@ -0,0 +1,31 @@ +from webob import Response + +from repoze.bfg.template import TemplateView + +def datestring(dt): + return dt.strftime('%Y-%m-%dT%H:%M:%S') + +class BlogDefaultView(TemplateView): + def getInfo(self): + entrydata = [] + for name, entry in self.context.items(): + entrydata.append( + { + 'name':name, + 'title':entry.title, + 'author':entry.author, + 'created':datestring(entry.created), + } + ) + return {'name':self.context.__name__, 'entries':entrydata} + +class BlogEntryDefaultView(TemplateView): + def getInfo(self): + return { + 'name':self.context.__name__, + 'title':self.context.title, + 'body':self.context.body, + 'author':self.context.author, + 'created':datestring(self.context.created), + } + diff --git a/repoze/bfg/sampleapp/configure.zcml b/repoze/bfg/sampleapp/configure.zcml index cddefc172..0e58126a7 100644 --- a/repoze/bfg/sampleapp/configure.zcml +++ b/repoze/bfg/sampleapp/configure.zcml @@ -4,24 +4,27 @@ <include package="repoze.bfg" /> + <!-- the default view for a Blog --> <browser:page - for=".models.IBlogModel" - class=".app.BlogWooHooView" + for=".models.IBlog" + class=".browser.BlogDefaultView" + template="www/blog.pt" permission="repoze.view" - name="woohoo.html" - template="www/blog_view.pt" /> + <!-- the default view for a BlogEntry --> <browser:page - for=".models.IBlogModel" - class=".app.BlogDefaultView" + for=".models.IBlogEntry" + class=".browser.BlogEntryDefaultView" + template="www/blog_entry.pt" permission="repoze.view" - template="www/blog_view.pt" /> + <!-- the contents view for any mapping (shows dict members) --> <browser:page - for="*" - class=".app.DefaultView" + for=".models.IMapping" + template="www/contents.pt" + name="contents.html" permission="repoze.view" /> diff --git a/repoze/bfg/sampleapp/models.py b/repoze/bfg/sampleapp/models.py index 19ef03c8c..975d79142 100644 --- a/repoze/bfg/sampleapp/models.py +++ b/repoze/bfg/sampleapp/models.py @@ -1,12 +1,28 @@ from zope.interface import Interface -from zope.interface import Attribute from zope.interface import implements -class IBlogModel(Interface): - id = Attribute('id') +import datetime -class BlogModel(object): - implements(IBlogModel) - def __init__(self, id): - self.id = id +class IMapping(Interface): + pass +class IBlog(Interface): + pass + +class Blog(dict): + implements(IBlog, IMapping) + def __init__(self, name): + self.__name__ = name + dict.__init__(self) + +class IBlogEntry(Interface): + pass + +class BlogEntry(object): + implements(IBlogEntry) + def __init__(self, name, title, body, author): + self.__name__ = name + self.title = title + self.body = body + self.author = author + self.created = datetime.datetime.now() diff --git a/repoze/bfg/sampleapp/run.py b/repoze/bfg/sampleapp/run.py new file mode 100644 index 000000000..d0eb53a51 --- /dev/null +++ b/repoze/bfg/sampleapp/run.py @@ -0,0 +1,15 @@ +from repoze.bfg import sampleapp +from repoze.bfg.sampleapp.models import Blog +from repoze.bfg.sampleapp.models import BlogEntry +from repoze.bfg.router import make_app + +if __name__ == '__main__': + blog = Blog('Sample blog') + blog['sample'] = BlogEntry('sample', 'Sample Blog Entry', + '<p>This is a sample blog entry</p>', + 'chrism') + def get_root(environ): + return blog + app = make_app(get_root, sampleapp) + from paste import httpserver + httpserver.serve(app, host='0.0.0.0', port='5432') diff --git a/repoze/bfg/sampleapp/www/blog.pt b/repoze/bfg/sampleapp/www/blog.pt new file mode 100644 index 000000000..ffe8659df --- /dev/null +++ b/repoze/bfg/sampleapp/www/blog.pt @@ -0,0 +1,19 @@ +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:tal="http://xml.zope.org/namespaces/tal"> +<head></head> +<body tal:define="info view.getInfo()"> + <h1 tal:content="info.name">Blog Name</h1> + <table border="0"> + <thead> + <th>Title</th> + <th>Author</th> + <th>Created</th> + </thead> + <tr tal:repeat="entry info.entries"> + <td><a href="${entry.name}/">${entry.title}</a></td> + <td>${entry.author}</td> + <td>${entry.created}</td> + </tr> + </table> +</body> +</html> diff --git a/repoze/bfg/sampleapp/www/blog_entry.pt b/repoze/bfg/sampleapp/www/blog_entry.pt new file mode 100644 index 000000000..20e1b4409 --- /dev/null +++ b/repoze/bfg/sampleapp/www/blog_entry.pt @@ -0,0 +1,12 @@ +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:tal="http://xml.zope.org/namespaces/tal"> +<head></head> +<body> + <div tal:define="info view.getInfo()"> + <p><a href="..">Up</a></p> + <h1>${info.title}</h1> + <p>by ${info.author}</p> + <div tal:content="structure info.body"></div> + </div> +</body> +</html> diff --git a/repoze/bfg/sampleapp/www/blog_view.pt b/repoze/bfg/sampleapp/www/blog_view.pt deleted file mode 100644 index ceedf0cc1..000000000 --- a/repoze/bfg/sampleapp/www/blog_view.pt +++ /dev/null @@ -1,7 +0,0 @@ -<div xmlns="http://www.w3.org/1999/xhtml" - xmlns:tal="http://xml.zope.org/namespaces/tal"> - <div tal:define="info path: view/getInfo"> - <span tal:content="path: info/greeting"/> from - <span tal:content="path: info/id"/> - </div> -</div> diff --git a/repoze/bfg/sampleapp/www/contents.pt b/repoze/bfg/sampleapp/www/contents.pt new file mode 100644 index 000000000..eaae20ed5 --- /dev/null +++ b/repoze/bfg/sampleapp/www/contents.pt @@ -0,0 +1,6 @@ +<div xmlns="http://www.w3.org/1999/xhtml" + xmlns:tal="http://xml.zope.org/namespaces/tal"> + <div tal:repeat="name context"> + <a href="${name}/">${name}</a> + </div> +</div> diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py index bfa72fe41..25d3bfdcf 100644 --- a/repoze/bfg/tests/test_router.py +++ b/repoze/bfg/tests/test_router.py @@ -60,6 +60,30 @@ class RouterTests(unittest.TestCase, PlacelessSetup): self.assertEqual(status, '404 Not Found') self.failUnless('http://localhost:8080' in result[0], result) + def test_call_default_view_redirect(self): + rootpolicy = make_rootpolicy(None) + context = DummyContext() + traversalfactory = make_traversal_factory(context, '', []) + response = DummyResponse() + viewfactory = make_view_factory(response) + wsgifactory = make_wsgi_factory('200 OK', (), ['Hello world']) + environ = self._makeEnviron(PATH_INFO='/doesnt/end/in/slash') + self._registerTraverserFactory(traversalfactory, '', None, None) + self._registerViewFactory(viewfactory, '', None, None) + self._registerWSGIFactory(wsgifactory, '', None, None) + router = self._makeOne(rootpolicy) + start_response = DummyStartResponse() + result = router(environ, start_response) + headers = start_response.headers + self.assertEqual(len(headers), 3) + self.assertEqual( + headers[0], + ('content-type', 'text/html; charset=UTF-8')) + self.assertEqual( + headers[1], + ('location', 'http://localhost:8080/doesnt/end/in/slash/')) + self.assertEqual(start_response.status, '302 Found') + def test_call_view_registered_nonspecific_default_path(self): rootpolicy = make_rootpolicy(None) context = DummyContext() |
