py-scopes/scopes/web/browser.py
2025-04-20 16:42:13 +02:00

69 lines
2.1 KiB
Python

# scopes.web.browser
import json
import logging
from zope.interface import implementer
from scopes.interfaces import IContainer, IReference, IView
logger = logging.getLogger('web.browser')
views = {} # registry for all views: {name: {prefix: viewClass, ...}, ...}
def register(name, *contextTypes):
"""Use as decorator: `@register(name, class_or_prefix, ...).
No class (or `None` or `''`) means default view for all classes."""
def doRegister(factory):
implementer(IView)(factory)
nameEntry = views.setdefault(name, {})
cts = contextTypes or ['']
for ct in cts:
if not isinstance(ct, str):
ct = ct.prefix
nameEntry[ct] = factory
return factory
return doRegister
def getView(request, ob, name):
nameEntry = views.get(name)
if nameEntry is None:
return None
factory = nameEntry.get(ob.prefix)
if factory is None:
factory = nameEntry.get('')
if factory is None:
return None
logger.debug('getView: %s %s', ob, request['PATH_INFO'])
return factory(ob, request)
@register('index.html')
@register('index.json')
class DefaultView:
def __init__(self, context, request):
self.context = context
self.request = request
def __call__(self):
result = self.prepareResult()
return self.render(result)
def prepareResult(self):
ob = self.context
result = ob.asDict()
if IContainer.providedBy(ob):
result['items'] = [v.asDict() for v in ob.values()]
if IReference.providedBy(ob):
target = ob.getTarget()
if target:
result['target'] = target.asDict()
if IContainer.providedBy(target):
result['target']['items'] = [v.asDict() for v in target.values()]
prc = self.request.principal
if prc is not None:
result['principal'] = prc.asDict()
return result
def render(self, result):
self.request.response.setHeader('Content-type', 'application/json; charset=utf-8')
return json.dumps(result).encode('UTF-8')