diff --git a/configure.zcml b/configure.zcml index 34517f0..08d315a 100644 --- a/configure.zcml +++ b/configure.zcml @@ -371,5 +371,6 @@ + diff --git a/search/README.txt b/search/README.txt index a29ee86..9eaa82c 100755 --- a/search/README.txt +++ b/search/README.txt @@ -103,7 +103,7 @@ a controller attribute for the search view. >>> searchView.submitReplacing('1.results', '1.search.form', pageView) 'return submitReplacing("1.results", "1.search.form", - "http://127.0.0.1/loops/views/page/.target19/@@searchresults.html")' + "http://127.0.0.1/loops/views/page/.target9/@@searchresults.html")' Basic (text/title) search ------------------------- @@ -198,7 +198,7 @@ of the concepts' titles: >>> request = TestRequest(form=form) >>> view = Search(page, request) >>> view.listConcepts() - "[['Zope (Topic)', '23']]" + "[['Zope (Topic)', '11']]" TODO - more to come... diff --git a/xmlrpc/README.txt b/xmlrpc/README.txt new file mode 100755 index 0000000..d60bc0e --- /dev/null +++ b/xmlrpc/README.txt @@ -0,0 +1,102 @@ +=============================================================== +loops.xmlrpc +=============================================================== + + ($Id$) + +Let's do some basic set up + + >>> from zope.app.testing.setup import placefulSetUp, placefulTearDown + >>> site = placefulSetUp(True) + + >>> from zope import component, interface + >>> from zope.publisher.browser import TestRequest + +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 +ZCML setup): + + >>> from cybertools.relation.registry import DummyRelationRegistry + >>> component.provideUtility(DummyRelationRegistry()) + >>> from cybertools.relation.tests import IntIdsStub + >>> component.provideUtility(IntIdsStub()) + + >>> from loops.type import ConceptType, TypeConcept + >>> component.provideAdapter(ConceptType) + >>> component.provideAdapter(TypeConcept) + + >>> from loops import Loops + >>> loopsRoot = site['loops'] = Loops() + + >>> from loops.setup import SetupManager + >>> setup = SetupManager(loopsRoot) + >>> concepts, resources, views = setup.setup() + +Let's look what setup has provided us with: + + >>> list(concepts) + [u'file', u'hasType', u'image', u'predicate', u'standard', u'textdocument', u'type'] + +Navigation typically starts at a start object, which by default ist the +top-level type concept: + + >>> from loops.xmlrpc.common import LoopsMethods + >>> xrf = LoopsMethods(loopsRoot, TestRequest()) + >>> xrf.getStartObject() + {'title': u'Type', 'type': '0', 'id': '0', 'name': u'type'} + +If we provide a concept named "domain" this will be used as starting point: + + >>> from loops.concept import Concept + >>> domain = concepts[u'domain'] = Concept(u'Domain') + >>> domain.conceptType = concepts.getTypeConcept() + >>> xrf.getStartObject() + {'title': u'Domain', 'type': '0', 'id': '7', 'name': u'domain'} + +There are a few standard objects we can retrieve directly: + + >>> xrf.getDefaultPredicate() + {'title': u'subobject', 'type': '4', 'id': '6', 'name': u'standard'} + >>> xrf.getTypePredicate() + {'title': u'has Type', 'type': '4', 'id': '5', 'name': u'hasType'} + >>> xrf.getTypeConcept() + {'title': u'Type', 'type': '0', 'id': '0', 'name': u'type'} + +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'image', u'predicate', u'textdocument', u'type'] + >>> sorted(t['name'] for t in xrf.getPredicates()) + [u'hasType', u'standard'] + +We can also retrieve a certain object by its id or its name: + + >>> xrf.getObjectById('2') + {'title': u'Image', 'type': '0', 'id': '2', 'name': u'image'} + >>> xrf.getObjectByName(u'textdocument') + {'title': u'Text Document', 'type': '0', 'id': '3', 'name': u'textdocument'} + +Now we are ready to deal with children and parents... + + >>> ch = xrf.getChildren('0') + >>> len(ch) + 1 + >>> ch[0]['name'] + u'hasType' + >>> sorted(c['name'] for c in ch[0]['objects']) + [u'domain', u'file', u'image', u'predicate', u'textdocument', u'type'] + + >>> pa = xrf.getParents('5') + >>> len(pa) + 1 + >>> pa[0]['name'] + u'hasType' + >>> sorted(p['name'] for p in pa[0]['objects']) + u'predicate' + + +Fin de partie +============= + + >>> placefulTearDown() + diff --git a/xmlrpc/__init__.py b/xmlrpc/__init__.py new file mode 100644 index 0000000..4bc90fb --- /dev/null +++ b/xmlrpc/__init__.py @@ -0,0 +1,4 @@ +""" +$Id$ +""" + diff --git a/xmlrpc/common.py b/xmlrpc/common.py new file mode 100644 index 0000000..56ec685 --- /dev/null +++ b/xmlrpc/common.py @@ -0,0 +1,108 @@ +# +# Copyright (c) 2005 Helmut Merz helmutm@cy55.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +Tournament and Assessment views. + +$Id$ +""" + +from zope.interface import implements +from zope.app.publisher.xmlrpc import XMLRPCView +from zope.app.publisher.xmlrpc import MethodPublisher +from zope.app.traversing.api import getName +from zope.security.proxy import removeSecurityProxy +from zope.cachedescriptors.property import Lazy + +from loops.util import getUidForObject, getObjectForUid + +class LoopsMethods(MethodPublisher): + """ XML-RPC methods for the loops root object. + """ + + def __init__(self, context, request): + self.context = removeSecurityProxy(context) + self.request = request + + @Lazy + def concepts(self): + return self.context.getConceptManager() + + def getStartObject(self): + so = self.concepts.get('domain', self.concepts.getTypeConcept()) + return objectAsDict(so) + + def getObjectById(self, id): + return objectAsDict(getObjectForUid(id)) + + def getObjectByName(self, name): + return objectAsDict(self.concepts[name]) + + def getDefaultPredicate(self): + return objectAsDict(self.concepts.getDefaultPredicate()) + + def getTypePredicate(self): + return objectAsDict(self.concepts.getTypePredicate()) + + def getTypeConcept(self): + return objectAsDict(self.concepts.getTypeConcept()) + + def getConceptTypes(self): + tc = self.concepts.getTypeConcept() + types = tc.getChildren((self.concepts.getTypePredicate(),)) + return [objectAsDict(t) for t in types] + + def getPredicates(self): + pt = self.concepts.getDefaultPredicate().conceptType + types = pt.getChildren((self.concepts.getTypePredicate(),)) + return [objectAsDict(t) for t in types] + + def getChildren(self, id, predicates=[], child=''): + obj = getObjectForUid(id) + preds = [getObjectForUid(p) for p in predicates] + child = child and getObjectForUid(child) or None + rels = obj.getChildRelations(preds, child) + return formatRelations(rels) + + def getParents(self, id, predicates=[], parent=''): + obj = getObjectForUid(id) + preds = [getObjectForUid(p) for p in predicates] + parent = parent and getObjectForUid(parent) or None + rels = obj.getParentRelations(preds, parent) + return formatRelations(rels, useSecond=False) + + +def objectAsDict(obj): + mapping = {'id': getUidForObject(obj), 'name': getName(obj), 'title': obj.title, + 'type': getUidForObject(obj.conceptType)} + return mapping + +def formatRelations(rels, useSecond=True): + predIds = {} + result = [] + for rel in rels: + pred = rel.predicate + predId = getUidForObject(pred) + if not predId in predIds: + predIds[predId] = len(result) + result.append({'id': predId, 'name': getName(pred), + 'title': pred.title, 'objects': []}) + result[predIds[predId]]['objects'].append( + objectAsDict(useSecond and rel.second or rel.first)) + return result + diff --git a/xmlrpc/configure.zcml b/xmlrpc/configure.zcml new file mode 100644 index 0000000..02fb696 --- /dev/null +++ b/xmlrpc/configure.zcml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/xmlrpc/tests.py b/xmlrpc/tests.py new file mode 100755 index 0000000..159d2ef --- /dev/null +++ b/xmlrpc/tests.py @@ -0,0 +1,22 @@ +# $Id$ + +import unittest, doctest +from zope.testing.doctestunit import DocFileSuite + + +class Test(unittest.TestCase): + "Basic tests for the loops.xmlrpc package." + + def testBasics(self): + pass + + +def test_suite(): + flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS + return unittest.TestSuite(( + unittest.makeSuite(Test), + DocFileSuite('README.txt', optionflags=flags), + )) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite')