From 0bda603f1e573edbae5825d0e0380181fcef32c5 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Wed, 13 Mar 2024 09:11:28 +0100 Subject: [PATCH] first working version of URL traversal over folders via publication and view --- scopes/interfaces.py | 16 +++++++++++++--- scopes/server/app.py | 37 +++++++++++++++++++++++++++++++++++-- scopes/storage/folder.py | 6 +++++- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/scopes/interfaces.py b/scopes/interfaces.py index 8d1eef1..0fca68d 100644 --- a/scopes/interfaces.py +++ b/scopes/interfaces.py @@ -5,15 +5,18 @@ from zope.interface import Interface class ITraversable(Interface): + def get(key, default): + """Return the item addressed by `key`; return `default` if not found.""" + + +class IContainer(ITraversable): + def items(): """Return a sequence of key, value pairs of child objects.""" def keys(): """Return a sequence of keys of child objects.""" - def get(key, default): - """Return the item addressed by `key`; return `default` if not found.""" - def __getitem__(key): """Return the item addressed by `key`; rais KeyError if not found.""" @@ -22,3 +25,10 @@ class ITraversable(Interface): May modify `value` so that the attributes referencing this object and the value object (e.g. `parent´ and `name`) are stored correctly.""" + + +class IView(Interface): + + def __call__(): + """Render the view data as HTML or JSON.""" + diff --git a/scopes/server/app.py b/scopes/server/app.py index 1ed9223..b377199 100644 --- a/scopes/server/app.py +++ b/scopes/server/app.py @@ -1,10 +1,14 @@ # scopes.server.app +import json +from zope.interface import implementer from zope.publisher.base import DefaultPublication from zope.publisher.browser import BrowserRequest +from zope.publisher.interfaces import NotFound from zope.publisher.publish import publish from zope.traversing.publicationtraverse import PublicationTraverser +from scopes.interfaces import IContainer, ITraversable, IView from scopes.storage.folder import Root @@ -15,7 +19,7 @@ def zope_app_factory(config): appRoot = Root(storage, config) request = BrowserRequest(environ['wsgi.input'], environ) request.setPublication(Publication(appRoot)) - request = publish(request, True) + request = publish(request, False) response = request.response start_response(response.getStatusString(), response.getHeaders()) return response.consumeBodyIter() @@ -24,5 +28,34 @@ def zope_app_factory(config): class Publication(DefaultPublication): - pass + def traverseName(self, request, ob, name): + next = None + if ITraversable.providedBy(ob): + next = ob.get(name) + if next is None: + if name == 'index.html': + next = DefaultView(ob, request) + if next is None: + raise NotFound(ob, name, request) + return next + + def getDefaultTraversal(self, request, ob): + if IView.providedBy(ob): + return ob, () + return ob, ('index.html',) + + +@implementer(IView) +class DefaultView: + + def __init__(self, context, request): + self.context = context + self.request = request + + def __call__(self): + ob = self.context + result = dict(head=ob.head, data=ob.data) + if IContainer.providedBy(ob): + result['items'] = list(ob.keys()) + return json.dumps(result) diff --git a/scopes/storage/folder.py b/scopes/storage/folder.py index 961294a..c459ae8 100644 --- a/scopes/storage/folder.py +++ b/scopes/storage/folder.py @@ -1,9 +1,13 @@ # scopes.storage.folder +from zope.interface import implementer + +from scopes.interfaces import IContainer from scopes.storage.common import registerContainerClass from scopes.storage.tracking import Container, Track +@implementer(IContainer) class Folder(Track): """Needs docstring to be traversable.""" @@ -33,7 +37,7 @@ class Folder(Track): value.set('name', key) self.container.save(value) - def __call__(self, request=None): + def __str__(self): return 'folder: %s; keys: %s' % (self.name, list(self.keys()))