From 685ac858b0bb59651928c0d0223f065b778df610 Mon Sep 17 00:00:00 2001 From: helmutm Date: Sat, 17 Mar 2007 16:16:04 +0000 Subject: [PATCH] provide attributes and resources via XML-RPC git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1647 fd906abe-77d9-0310-91a1-e0d9ade77398 --- base.py | 1 - concept.py | 3 +++ interfaces.py | 21 ++++++++++++----- resource.py | 3 +++ xmlrpc/README.txt | 59 +++++++++++++++++++++++++++++++++++++++-------- xmlrpc/common.py | 27 ++++++++++++++++++++-- 6 files changed, 95 insertions(+), 19 deletions(-) diff --git a/base.py b/base.py index b261276..6256733 100644 --- a/base.py +++ b/base.py @@ -70,4 +70,3 @@ class Loops(Folder): prefix = loopsPrefix + '/' if uri.startswith(prefix): return traverse(self, uri[len(prefix):]) - diff --git a/concept.py b/concept.py index 9cd9daa..335161c 100644 --- a/concept.py +++ b/concept.py @@ -122,6 +122,9 @@ class Concept(Contained, Persistent): self.assignParent(concept, typePred) conceptType = property(getConceptType, setConceptType) + def getType(self): + return self.conceptType + def getLoopsRoot(self): return zapi.getParent(self).getLoopsRoot() diff --git a/interfaces.py b/interfaces.py index b16be0d..134f723 100644 --- a/interfaces.py +++ b/interfaces.py @@ -75,12 +75,12 @@ class IConcept(ILoopsObject, IPotentialTarget): required=True) description = schema.Text( - title=_(u'Description'), - description=_(u'A medium-length description describing the ' - 'content and the purpose of the object'), - default=u'', - missing_value=u'', - required=False) + title=_(u'Description'), + description=_(u'A medium-length description describing the ' + 'content and the purpose of the object'), + default=u'', + missing_value=u'', + required=False) conceptType = schema.Choice( title=_(u'Concept Type'), @@ -90,6 +90,10 @@ class IConcept(ILoopsObject, IPotentialTarget): source="loops.conceptTypeSource", required=False) + def getType(): + """ Return a concept that provides the object's type. + """ + def getChildren(predicates=None): """ Return a sequence of concepts related to self as child concepts, optionally restricted to the predicates given. @@ -223,6 +227,11 @@ class IBaseResource(ILoopsObject): source="loops.resourceTypeSource", required=False) + def getType(): + """ Return a concept that provides the object's type, i.e. the + resourceType attribute. + """ + data = schema.Bytes( title=_(u'Data'), description=_(u'Resource raw data'), diff --git a/resource.py b/resource.py index 5f699a3..fac4c9f 100644 --- a/resource.py +++ b/resource.py @@ -117,6 +117,9 @@ class Resource(Image, Contained): self.assignConcept(concept, typePred) resourceType = property(getResourceType, setResourceType) + def getType(self): + return self.resourceType + def _setData(self, data): dataFile = StringIO(data) # let File tear it into pieces super(Resource, self)._setData(dataFile) diff --git a/xmlrpc/README.txt b/xmlrpc/README.txt index 5415b3f..0318600 100755 --- a/xmlrpc/README.txt +++ b/xmlrpc/README.txt @@ -12,6 +12,7 @@ Let's do some basic set up >>> from zope import component, interface >>> from zope.publisher.browser import TestRequest >>> from loops.concept import Concept + >>> from loops.resource import Resource and setup a simple loops site with a concept manager and some concepts (with all the type machinery, what in real life is done via standard @@ -23,7 +24,8 @@ ZCML setup): >>> intIds = IntIdsStub() >>> component.provideUtility(intIds) - >>> from loops.type import ConceptType, TypeConcept + >>> from loops.type import LoopsType, ConceptType, TypeConcept + >>> component.provideAdapter(LoopsType) >>> component.provideAdapter(ConceptType) >>> component.provideAdapter(TypeConcept) @@ -31,28 +33,30 @@ ZCML setup): >>> loopsRoot = site['loops'] = Loops() >>> from loops.setup import SetupManager + >>> from loops.organize.setup import SetupManager as OrganizeSetupManager + >>> component.provideAdapter(OrganizeSetupManager, name='organize') >>> setup = SetupManager(loopsRoot) >>> concepts, resources, views = setup.setup() Let's look what setup has provided us with: >>> sorted(concepts) - [u'domain', u'file', u'hasType', u'note', u'predicate', u'query', + [u'domain', u'file', u'hasType', u'note', u'person', u'predicate', u'query', u'standard', u'textdocument', u'type'] Now let's add a few more concepts: >>> topic = concepts[u'topic'] = Concept(u'Topic') >>> intIds.register(topic) - 8 + 9 >>> zope = concepts[u'zope'] = Concept(u'Zope') >>> zope.conceptType = topic >>> intIds.register(zope) - 9 + 10 >>> zope3 = concepts[u'zope3'] = Concept(u'Zope 3') >>> zope3.conceptType = topic >>> intIds.register(zope3) - 10 + 11 Navigation typically starts at a start object, which by default ist the domain concept (if present, otherwise the top-level type concept): @@ -61,7 +65,8 @@ domain concept (if present, otherwise the top-level type concept): >>> xrf = LoopsMethods(loopsRoot, TestRequest()) >>> startObj = xrf.getStartObject() >>> sorted(startObj.keys()) - ['children', 'id', 'name', 'parents', 'title', 'type'] + ['children', 'description', 'id', 'name', 'options', 'parents', 'resources', + 'title', 'type', 'typeInterface', 'viewName'] >>> startObj['id'], startObj['name'], startObj['title'], startObj['type'] ('1', u'domain', u'Domain', '0') @@ -80,7 +85,7 @@ There are a few standard objects we can retrieve directly: In addition we can get a list of all types and all predicates available: >>> sorted(t['name'] for t in xrf.getConceptTypes()) - [u'domain', u'file', u'predicate', u'query', u'textdocument', u'type'] + [u'domain', u'file', u'person', u'predicate', u'query', u'textdocument', u'type'] >>> sorted(t['name'] for t in xrf.getPredicates()) [u'hasType', u'standard'] @@ -101,7 +106,7 @@ All methods that retrieve one object also returns its children and parents: >>> ch[0]['name'] u'hasType' >>> sorted(c['name'] for c in ch[0]['objects']) - [u'domain', u'file', u'predicate', u'query', u'textdocument', u'type'] + [u'domain', u'file', u'person', u'predicate', u'query', u'textdocument', u'type'] >>> pa = defaultPred['parents'] >>> len(pa) @@ -119,7 +124,7 @@ We can also retrieve children and parents explicitely: >>> ch[0]['name'] u'hasType' >>> sorted(c['name'] for c in ch[0]['objects']) - [u'domain', u'file', u'predicate', u'query', u'textdocument', u'type'] + [u'domain', u'file', u'person', u'predicate', u'query', u'textdocument', u'type'] >>> pa = xrf.getParents('6') >>> len(pa) @@ -129,6 +134,34 @@ We can also retrieve children and parents explicitely: >>> sorted(p['name'] for p in pa[0]['objects']) [u'predicate'] +Resources +--------- + + >>> from loops.resource import TextDocumentAdapter + >>> from loops.interfaces import IResource, ITextDocument + >>> component.provideAdapter(TextDocumentAdapter, (IResource,), ITextDocument) + + >>> zope3Id = xrf.getObjectByName('zope3')['id'] + >>> td01 = resources['td01'] = Resource(u'Doc1') + >>> td01.resourceType = concepts['textdocument'] + >>> zope3.assignResource(td01) + + >>> obj = xrf.getObjectById(zope3Id) + >>> obj['resources'][0]['objects'][0]['title'] + u'Doc1' + +Attributes +---------- + + >>> from loops.organize.party import Person + >>> from loops.organize.interfaces import IPerson + >>> component.provideAdapter(Person, provides=IPerson) + >>> p01 = concepts['p01'] = Concept(u'John Smith') + >>> p01.conceptType = concepts['person'] + + >>> john = xrf.getObjectByName('p01') + >>> #john + Updating the concept map ------------------------ @@ -142,7 +175,13 @@ Updating the concept map >>> topicId = xrf.getObjectByName('topic')['id'] >>> xrf.createConcept(topicId, u'zope2', u'Zope 2') - {'title': u'Zope 2', 'type': '8', 'id': '12', 'name': u'zope2'} + {'description': u'', 'title': u'Zope 2', 'type': '9', 'id': '15', + 'name': u'zope2'} + +Changing the attributes of a concept +------------------------------------ + +Not implemented yet. Fin de partie diff --git a/xmlrpc/common.py b/xmlrpc/common.py index f84d419..76ce7c5 100644 --- a/xmlrpc/common.py +++ b/xmlrpc/common.py @@ -31,6 +31,7 @@ from zope.traversing.api import getName from zope.security.proxy import removeSecurityProxy from zope.cachedescriptors.property import Lazy +from cybertools.typology.interfaces import IType from loops.concept import Concept from loops.util import getUidForObject, getObjectForUid, toUnicode @@ -90,11 +91,19 @@ class LoopsMethods(MethodPublisher): rels = obj.getParentRelations(preds or None, parent) return formatRelations(rels, useSecond=False) + def getResources(self, id, predicates=[], resource=''): + obj = getObjectForUid(id) + preds = [getObjectForUid(p) for p in predicates] + resource = resource and getObjectForUid(child) or None + rels = obj.getResourceRelations(preds or None, resource) + return formatRelations(rels) + def getObjectWithChildren(self, obj): mapping = objectAsDict(obj) mapping['children'] = formatRelations(obj.getChildRelations()) mapping['parents'] = formatRelations( obj.getParentRelations(), useSecond=False) + mapping['resources'] = formatRelations(obj.getResourceRelations()) return mapping def assignChild(self, objId, predicateId, childId): @@ -122,8 +131,22 @@ class LoopsMethods(MethodPublisher): def objectAsDict(obj): - mapping = {'id': getUidForObject(obj), 'name': getName(obj), 'title': obj.title, - 'type': getUidForObject(obj.conceptType)} + objType = IType(obj) + mapping = {'id': getUidForObject(obj), 'name': getName(obj), + 'title': obj.title, 'description': obj.description, + 'type': getUidForObject(objType.typeProvider)} + ti = objType.typeInterface + if ti is not None: + adapter = ti(obj) + for attr in (list(adapter._adapterAttributes) + list(ti)): + if attr not in ('__parent__', 'context', 'id', 'name', + 'title', 'description', 'type'): + value = getattr(adapter, attr) + # TODO: better selection and conversion + if value is None or type(value) in (str, unicode): + mapping[attr] = value or u'' + elif type(value) is list: + mapping[attr] = ' | '.join(value) return mapping def formatRelations(rels, useSecond=True):