diff --git a/scopes/interfaces.py b/scopes/interfaces.py index 82cad03..e146293 100644 --- a/scopes/interfaces.py +++ b/scopes/interfaces.py @@ -24,6 +24,15 @@ class IContainer(ITraversable): and the value object (e.g. `parent´ and `name`) are stored correctly.""" +class IReference(Interface): + + def getTarget(): + """Return item referenced by this object.""" + + def setTarget(target): + """Store reference to target item.""" + + class IView(Interface): def __call__(): diff --git a/scopes/server/app.py b/scopes/server/app.py index d9bc634..fb35a69 100644 --- a/scopes/server/app.py +++ b/scopes/server/app.py @@ -7,6 +7,7 @@ from zope.publisher.publish import publish from scopes.interfaces import ITraversable, IView from scopes.server.browser import getView +import scopes.storage.concept from scopes.storage.folder import Root diff --git a/scopes/server/browser.py b/scopes/server/browser.py index 4cd432a..902c8a9 100644 --- a/scopes/server/browser.py +++ b/scopes/server/browser.py @@ -2,7 +2,7 @@ import json from zope.interface import implementer -from scopes.interfaces import IContainer, IView +from scopes.interfaces import IContainer, IReference, IView views = {} # registry for all views: {name: {prefix: viewClass, ...}, ...} @@ -38,10 +38,24 @@ class DefaultView: self.context = context self.request = request - def __call__(self): + def prepareResult(self): ob = self.context - result = dict(head=ob.head, data=ob.data) + result = ob.asDict() if IContainer.providedBy(ob): result['items'] = [v.asDict() for v in ob.values()] - return json.dumps(result) + 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()] + return result + + def renderJson(self, result): + self.request.response.setHeader('Content-type', 'application/json; charset=utf-8') + return json.dumps(result).encode('UTF-8') + + def __call__(self): + result = self.prepareResult() + return self.renderJson(result) diff --git a/scopes/storage/concept.py b/scopes/storage/concept.py index ba0764a..595ede5 100644 --- a/scopes/storage/concept.py +++ b/scopes/storage/concept.py @@ -3,6 +3,7 @@ """Core classes for concept map structure.""" from zope.interface import implementer +from scopes.interfaces import IContainer from scopes.storage.common import registerContainerClass, registry from scopes.storage.tracking import Container, Track @@ -17,6 +18,10 @@ class Concept(Track): def children(self, predicate=None): return self.container.queryRels(first=self, predicate=predicate) + def values(self): + return (t.getSecond() for t in self.children(Rels.defaultPredicate)) + + class Concepts(Container): @@ -77,18 +82,30 @@ class Rels(Container): # types stuff +@implementer(IContainer) class Type(Concept): headFields = ['name', 'tprefix'] prefix = 'type' + def values(self): + cont = self.container.storage.getContainer(self.tprefix) + return cont.query() + def get(self, key, default=None): cont = self.container.storage.getContainer(self.tprefix) return cont.queryLast(name=key) or default - def values(self): + def __getitem__(self, key): + value = self.get(key) + if value is None: + raise KeyError(key) + return value + + def __setitem__(self, key, value): cont = self.container.storage.getContainer(self.tprefix) - return cont.query() + value.name = key + cont.save(value) @registerContainerClass @@ -100,7 +117,7 @@ class Types(Concepts): def storeType(storage, cls, name): - types = storage.create(Types) + types = storage.getContainer('type') types.save(Type(name, cls.prefix)) def setupCoreTypes(storage): diff --git a/scopes/storage/folder.py b/scopes/storage/folder.py index 5057372..1a05e61 100644 --- a/scopes/storage/folder.py +++ b/scopes/storage/folder.py @@ -2,12 +2,12 @@ from zope.interface import implementer -from scopes.interfaces import IContainer +from scopes.interfaces import IContainer, IReference from scopes.storage.common import registerContainerClass from scopes.storage.tracking import Container, Track -@implementer(IContainer) +@implementer(IContainer, IReference) class Folder(Track): headFields = ['parent', 'name', 'ref'] @@ -29,7 +29,7 @@ class Folder(Track): return value def __getitem__(self, key): - value = self.container.queryLast(parent=self.rid, name=key) + value = self.get(key) if value is None: raise KeyError(key) return value @@ -39,6 +39,15 @@ class Folder(Track): value.set('name', key) self.container.save(value) + def getTarget(self): + if self.ref == '': + return None + return self.container.storage.getItem(self.ref) + + def setTarget(self, target): + self.ref = target.uid + self.container.save(self) + def __str__(self): return '%s: %s; keys: %s' % (self.__class__.__name__, self.name, list(self.keys()))