From 96d0462b18473ccced41581a40f2455191553c3b Mon Sep 17 00:00:00 2001 From: helmutm Date: Tue, 9 Oct 2007 15:19:13 +0000 Subject: [PATCH] work in progress: classifier git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2106 fd906abe-77d9-0310-91a1-e0d9ade77398 --- README.txt | 19 +++++++++++++++++++ base.py | 12 ++++++++++++ classifier/base.py | 2 +- classifier/browser.py | 33 +++++++++++++++++++++++++++++++++ classifier/classifier_macros.pt | 11 +++++++++++ classifier/configure.zcml | 14 ++++++++++++-- classifier/testsetup.py | 2 -- concept.py | 20 ++++++++++++++++++++ integrator/browser.py | 8 ++++---- integrator/collection.py | 4 +++- interfaces.py | 12 ++++++++++-- resource.py | 21 +++++++++++++++++++-- view.py | 17 +++++++++++++++++ 13 files changed, 161 insertions(+), 14 deletions(-) create mode 100644 classifier/classifier_macros.pt diff --git a/README.txt b/README.txt index cc599ac..42f471c 100755 --- a/README.txt +++ b/README.txt @@ -768,6 +768,25 @@ target object's view here: 'http://127.0.0.1/loops/views/m1/m11/m111/.target23' +Collecting Information about Parents +==================================== + +Sometimes, e.g. when checking permissions, it is important to collect +informations about all parents of an object. + + >>> parents = m113.getAllParents() + >>> for p in parents: + ... print p.object.title + Zope + Menu + + >>> parents = resources['test_note'].getAllParents() + >>> for p in parents: + ... print p.object.title, len(p.relations) + Note 1 + Type 2 + + Import/Export ============= diff --git a/base.py b/base.py index febeb27..35aa69d 100644 --- a/base.py +++ b/base.py @@ -29,6 +29,7 @@ from zope.app.folder.interfaces import IFolder from zope.traversing.api import getPath, traverse from zope.interface import implements +from cybertools.util.jeep import Jeep from loops.interfaces import ILoops loopsPrefix = '.loops' @@ -58,6 +59,9 @@ class Loops(Folder): def getLoopsRoot(self): return self + def getAllParents(self, collectGrants=False): + return Jeep() + def getConceptManager(self): return self['concepts'] @@ -76,6 +80,14 @@ class Loops(Folder): return traverse(self, uri[len(prefix):]) +class ParentInfo(object): + + def __init__(self, obj, relations=None, grants=None): + self.object = obj + self.relations = relations or [] + self.grants = grants or [] + + # backward compatibility for old loops sites that got their Loops object # directly from loops/__init__.py import loops diff --git a/classifier/base.py b/classifier/base.py index f02db4e..27b4348 100644 --- a/classifier/base.py +++ b/classifier/base.py @@ -61,7 +61,7 @@ class Classifier(AdapterBase): for name in self.extractors.split(): extractor = component.getAdapter(adapted(resource), IExtractor, name=name) infoSet.update(extractor.extractInformationSet()) - analyzer = component.getAdapter(self, name=self.analyzer) + analyzer = component.getAdapter(self, IAnalyzer, name=self.analyzer) statements = analyzer.extractStatements(infoSet) defaultPredicate = self.context.getConceptManager().getDefaultPredicate() for statement in statements: diff --git a/classifier/browser.py b/classifier/browser.py index 23d3cae..6d32e9f 100644 --- a/classifier/browser.py +++ b/classifier/browser.py @@ -28,3 +28,36 @@ from zope.cachedescriptors.property import Lazy from loops.browser.concept import ConceptView from loops.common import adapted + + +class ClassifierView(ConceptView): + + macro_template = ViewPageTemplateFile('classifier_macros.pt') + + @property + def macro(self): + return self.macro_template.macros['render_classifier'] + + def update(self): + if 'update' in self.request.form: + cta = adapted(self.context) + if cta is not None: + for r in collectResources(self.context): + print '***', r.title + cta.process(r) + return True + + +def collectResources(concept, checkedConcepts=None, result=None): + if result is None: + result = [] + if checkedConcepts is None: + checkedConcepts = [] + for r in concept.getResources(): + if r not in result: + result.append(r) + for c in concept.getChildren(): + if c not in checkedConcepts: + checkedConcepts.append(c) + collectResources(c, checkedConcepts, result) + return result diff --git a/classifier/classifier_macros.pt b/classifier/classifier_macros.pt new file mode 100644 index 0000000..785957f --- /dev/null +++ b/classifier/classifier_macros.pt @@ -0,0 +1,11 @@ + + + + +
+ +
+ +
+ diff --git a/classifier/configure.zcml b/classifier/configure.zcml index 49e6742..bf5c528 100644 --- a/classifier/configure.zcml +++ b/classifier/configure.zcml @@ -30,15 +30,25 @@ - + + + + + diff --git a/classifier/testsetup.py b/classifier/testsetup.py index a932a82..a529bce 100644 --- a/classifier/testsetup.py +++ b/classifier/testsetup.py @@ -43,8 +43,6 @@ class TestSite(BaseTestSite): component.provideAdapter(OrganizeSetupManager, name='organize') concepts, resources, views = self.baseSetup() - #catalog = component.getUtility(ICatalog) - #catalog['loops_text'] = TextIndex('text', IIndexAttributes, True) # classifier and Co tType = concepts.getTypeConcept() tClassifier = addAndConfigureObject(concepts, Concept, 'classifier', diff --git a/concept.py b/concept.py index 0d41b79..7d89983 100644 --- a/concept.py +++ b/concept.py @@ -39,11 +39,14 @@ from cybertools.relation.registry import getRelations from cybertools.relation.registry import getRelationSingle, setRelationSingle from cybertools.relation.interfaces import IRelationRegistry, IRelatable from cybertools.typology.interfaces import IType, ITypeManager +from cybertools.util.jeep import Jeep +from loops.base import ParentInfo from loops.interfaces import IConcept, IConceptRelation, IConceptView from loops.interfaces import IConceptManager, IConceptManagerContained from loops.interfaces import ILoopsContained from loops.interfaces import IIndexAttributes +from loops import util from loops.view import TargetRelation @@ -132,6 +135,20 @@ class Concept(Contained, Persistent): def getConceptManager(self): return self.getLoopsRoot().getConceptManager() + def getAllParents(self, collectGrants=False, result=None): + if result is None: + result = Jeep() + for rel in self.getParentRelations(): + obj = rel.first + uid = util.getUidForObject(obj) + pi = result.get(uid) + if pi is None: + result[uid] = ParentInfo(obj, [rel]) + obj.getAllParents(collectGrants, result) + elif rel not in pi.relations: + pi.relations.append(rel) + return result + # concept relations def getClients(self, relationships=None): @@ -215,6 +232,9 @@ class ConceptManager(BTreeContainer): def getLoopsRoot(self): return zapi.getParent(self) + def getAllParents(self, collectGrants=False): + return Jeep() + def getTypePredicate(self): return self.get('hasType') diff --git a/integrator/browser.py b/integrator/browser.py index 626d694..1bbba07 100644 --- a/integrator/browser.py +++ b/integrator/browser.py @@ -28,6 +28,7 @@ from zope.cachedescriptors.property import Lazy from cybertools.typology.interfaces import IType from loops.browser.concept import ConceptView +from loops.common import adapted class ExternalCollectionView(ConceptView): @@ -40,9 +41,8 @@ class ExternalCollectionView(ConceptView): def update(self): if 'update' in self.request.form: - ti = IType(self.context).typeInterface - if ti is not None: - adapted = ti(self.context) - adapted.update() + cta = adapted(self.context) + if cta is not None: + cta.update() return True diff --git a/integrator/collection.py b/integrator/collection.py index f125a67..0adfd8f 100644 --- a/integrator/collection.py +++ b/integrator/collection.py @@ -156,4 +156,6 @@ class DirectoryCollectionProvider(object): base, ext = title.rsplit('.', 1) if ext.lower() in mimetypes.extensions.values(): title = base - return title.decode('UTF-8') + if not isinstance(title, unicode): + title = title.decode('UTF-8') + return title diff --git a/interfaces.py b/interfaces.py index 8c7fda9..388ee66 100644 --- a/interfaces.py +++ b/interfaces.py @@ -42,12 +42,20 @@ class ILoopsObject(Interface): """ Common top-level interface. """ + title = Attribute(u'A short line of information about an object to be ' + 'used e.g. for menu items or listing entries.') + def getLoopsRoot(): """ Return the loops root object. """ - title = Attribute(u'A short line of information about an object to be ' - 'used e.g. for menu items or listing entries.') + def getAllParents(collectGrants=False): + """ Return a sequence (or an ordered mapping / Jeep object) + with informations about all parents of the object. + + If ``collectGrants`` is set also collect grant information + (assigned/effective roles) together with the parents. + """ class IPotentialTarget(Interface): diff --git a/resource.py b/resource.py index 9b9bf87..fe17ba0 100644 --- a/resource.py +++ b/resource.py @@ -49,7 +49,11 @@ from cybertools.relation.interfaces import IRelatable from cybertools.storage.interfaces import IExternalStorage from cybertools.text.interfaces import ITextTransform from cybertools.typology.interfaces import IType, ITypeManager +from cybertools.util.jeep import Jeep +from loops.base import ParentInfo +from loops.common import ResourceAdapterBase, adapted +from loops.concept import ResourceRelation from loops.interfaces import IBaseResource, IResource from loops.interfaces import IFile, IExternalFile, INote from loops.interfaces import IDocument, ITextDocument, IDocumentSchema, IDocumentView @@ -58,8 +62,7 @@ from loops.interfaces import IResourceManager, IResourceManagerContained from loops.interfaces import ITypeConcept from loops.interfaces import ILoopsContained from loops.interfaces import IIndexAttributes -from loops.concept import ResourceRelation -from loops.common import ResourceAdapterBase, adapted +from loops import util from loops.versioning.util import getMaster from loops.view import TargetRelation @@ -76,6 +79,9 @@ class ResourceManager(BTreeContainer): def getViewManager(self): return self.getLoopsRoot().getViewManager() + def getAllParents(self, collectGrants=False): + return Jeep() + class Resource(Image, Contained): @@ -161,6 +167,17 @@ class Resource(Image, Contained): def getLoopsRoot(self): return zapi.getParent(self).getLoopsRoot() + def getAllParents(self, collectGrants=False): + result = Jeep() + for rel in self.getConceptRelations(): + obj = rel.first + uid = util.getUidForObject(obj) + pi = result.setdefault(uid, ParentInfo(obj)) + if rel not in pi.relations: + pi.relations.append(rel) + obj.getAllParents(collectGrants, result) + return result + # concept relations # note: we always use the master version for relations, see getMaster() diff --git a/view.py b/view.py index e49e116..88e2c4a 100644 --- a/view.py +++ b/view.py @@ -39,13 +39,16 @@ from persistent import Persistent from cybertools.relation import DyadicRelation from cybertools.relation.registry import getRelations from cybertools.relation.interfaces import IRelationRegistry, IRelatable +from cybertools.util.jeep import Jeep +from loops.base import ParentInfo from loops.interfaces import IView, INode from loops.interfaces import IViewManager, INodeContained from loops.interfaces import ILoopsContained from loops.interfaces import ITargetRelation from loops.interfaces import IConcept from loops.versioning.util import getVersion +from loops import util class View(object): @@ -103,6 +106,9 @@ class View(object): def getLoopsRoot(self): return zapi.getParent(self).getLoopsRoot() + def getAllParents(self, collectGrants=False): + return Jeep() + class Node(View, OrderedContainer): @@ -128,6 +134,14 @@ class Node(View, OrderedContainer): parent = zapi.getParent(parent) return None + def getAllParents(self, collectGrants=False): + result = Jeep() + parent = self.getParentNode() + while parent is not None: + result[util.getUidForObject(parent)] = ParentInfo(parent) + parent = parent.getParentNode() + return result + def getChildNodes(self, nodeTypes=None): for item in self.values(): if INode.providedBy(item) \ @@ -170,6 +184,9 @@ class ViewManager(OrderedContainer): def getViewManager(self): return self + def getAllParents(self, collectGrants=False): + return Jeep() + class TargetRelation(DyadicRelation): """ A relation between a view and its target.