flexible export with selection based on parent concepts

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3604 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2009-10-26 18:19:27 +00:00
parent dddc43086d
commit c78bef8ec0
6 changed files with 207 additions and 63 deletions

23
external/README.txt vendored
View file

@ -177,6 +177,29 @@ corresponding extractor adapter.
viewName=u'mystuff.html')[ viewName=u'mystuff.html')[
annotations(creators=(u'john',))]... annotations(creators=(u'john',))]...
Extracting selected parts of the concept map
--------------------------------------------
>>> extractor = Extractor(loopsRoot, os.path.join(dataDirectory, 'export'))
>>> elements = list(extractor.extractForParents([concepts['customer']],
... includeSubconcepts=True, includeResources=True))
>>> len(elements)
10
>>> output = StringIO()
>>> writer.write(elements, output)
>>> print output.getvalue()
type(u'customer', u'Customer', options=u'', typeInterface=u'', viewName=u'')
concept(u'cust1', u'Customer 1', u'customer')
concept(u'cust2', u'Customer 2', u'customer')
concept(u'cust3', u'Customer 3', u'customer')
resource(u'd001.txt', u'Doc 001', u'textdocument', contentType='text/restructured')
resource(u'd003.txt', u'Doc 003', u'textdocument', contentType='text/restructured')
resource(u'd002.txt', u'Doc 002', u'textdocument', contentType='text/restructured')
resourceRelation(u'cust1', u'd001.txt', u'standard')
resourceRelation(u'cust1', u'd003.txt', u'standard')
resourceRelation(u'cust3', u'd002.txt', u'standard')
The Export/Import View The Export/Import View
====================== ======================

168
external/base.py vendored
View file

@ -40,6 +40,7 @@ from loops.common import adapted
from loops.external.interfaces import ILoader, IExtractor, ISubExtractor from loops.external.interfaces import ILoader, IExtractor, ISubExtractor
from loops.external.element import elementTypes from loops.external.element import elementTypes
from loops.interfaces import IConceptSchema, IResourceSchema from loops.interfaces import IConceptSchema, IResourceSchema
from loops.layout.base import LayoutNode
from loops.resource import Document, MediaAsset from loops.resource import Document, MediaAsset
from loops.setup import SetupManager from loops.setup import SetupManager
@ -109,79 +110,38 @@ class Extractor(Base):
yield element yield element
def extractConcepts(self): def extractConcepts(self):
conceptElement = elementTypes['concept']
typeConcept = self.typeConcept
for name, obj in self.concepts.items(): for name, obj in self.concepts.items():
if obj.conceptType is None: if obj.conceptType != self.typeConcept:
raise ValueError('Concept type is None for %s.' % getName(obj)) yield self.getConceptElement(name, obj)
if obj.conceptType != typeConcept:
data = self.getObjectData(obj)
tp = getName(obj.conceptType)
element = conceptElement(name, obj.title, tp, **data)
self.provideSubElements(obj, element)
yield element
def extractConceptsForType(self, typeName):
conceptElement = elementTypes['concept']
typeObject = self.concepts[typeName]
for obj in typeObject.getChildren([self.typePredicate]):
data = self.getObjectData(obj)
tp = getName(obj.conceptType)
element = conceptElement(name, obj.title, tp, **data)
#self.provideSubElements(obj, element)
yield element
def extractResources(self): def extractResources(self):
elementClass = elementTypes['resource']
for name, obj in self.resources.items(): for name, obj in self.resources.items():
data = self.getObjectData(obj, IResourceSchema) yield self.getResourceElement(name, obj)
tp = getName(obj.resourceType)
if isinstance(obj, Document): # backward compatibility
tp = 'textdocument'
element = elementClass(name, obj.title, tp, **data)
element.processExport(self)
self.provideSubElements(obj, element)
yield element
def extractChildren(self): def extractChildren(self):
childElement = elementTypes['child']
typePredicate = self.typePredicate
for c in self.concepts.values(): for c in self.concepts.values():
for r in c.getChildRelations(): for r in self.getChildRelations(c):
if r.predicate != typePredicate: yield r
args = [getName(r.first), getName(r.second), getName(r.predicate)]
if r.order != 0 or r.relevance != 1.0:
args.append(r.order)
if r.relevance != 1.0:
args.append(r.relevance)
yield childElement(*args)
def extractResourceRelations(self): def extractResourceRelations(self):
elementClass = elementTypes['resourceRelation']
typePredicate = self.typePredicate
for c in self.concepts.values(): for c in self.concepts.values():
for r in c.getResourceRelations(): for r in self.getResourceRelations(c):
if r.predicate != typePredicate: yield r
args = [getName(r.first), getName(r.second), getName(r.predicate)]
if r.order != 0 or r.relevance != 1.0:
args.append(r.order)
if r.relevance != 1.0:
args.append(r.relevance)
yield elementClass(*args)
def extractNodes(self, parent=None, path=''): def extractNodes(self, parent=None, path=''):
if parent is None: if parent is None:
parent = self.views parent = self.views
elementClass = elementTypes['node']
for name, obj in parent.items(): for name, obj in parent.items():
data = {} data = {}
for attr in ('description', 'body', 'viewName'): for attr in ('description', 'body', 'viewName', 'pageName'):
value = getattr(obj, attr) value = getattr(obj, attr, None)
if value: if value:
data[attr] = value data[attr] = value
target = obj.target target = obj.target
if target is not None: if target is not None:
data['target'] = '/'.join((getName(getParent(target)), getName(target))) data['target'] = '/'.join((getName(getParent(target)), getName(target)))
elementClass = (isinstance(obj, LayoutNode) and elementTypes['layoutNode']
or elementTypes['node'])
elem = elementClass(name, obj.title, path, obj.nodeType, **data) elem = elementClass(name, obj.title, path, obj.nodeType, **data)
self.provideSubElements(obj, elem) self.provideSubElements(obj, elem)
yield elem yield elem
@ -190,8 +150,106 @@ class Extractor(Base):
#self.provideSubElements(obj, elem) #self.provideSubElements(obj, elem)
yield elem yield elem
def extractForParents(self, parents, predicates=None,
includeSubconcepts=False, includeResources=False):
checked = set()
children = set()
resources = set()
for p in parents:
yield self.getConceptElement(getName(p), p)
for elem in self._extractForParents(parents, predicates,
includeSubconcepts, includeResources,
checked, children, resources):
yield elem
allConcepts = checked.union(children)
for c in allConcepts:
for r in c.getChildRelations(predicates):
if r.predicate != self.typePredicate and r.second in children:
yield self.getChildElement(r)
for c in allConcepts:
for r in c.getResourceRelations(predicates):
if r.predicate != self.typePredicate and r.second in resources:
yield self.getResourceRelationElement(r)
def _extractForParents(self, parents, predicates,
includeSubconcepts, includeResources,
checked, children, resources):
for p in parents:
if p in checked:
continue
checked.add(p)
ch = p.getChildren(predicates)
for obj in ch:
if obj not in children:
children.add(obj)
yield self.getConceptElement(getName(obj), obj)
if includeSubconcepts:
for elem in self._extractForParents(ch, predicates,
includeSubconcepts, includeResources,
checked, children, resources):
yield elem
if includeResources:
for obj in p.getResources(predicates):
if obj not in resources:
resources.add(obj)
yield self.getResourceElement(getName(obj), obj)
# helper methods # helper methods
def getConceptElement(self, name, obj):
if obj.conceptType is None:
raise ValueError('Concept type is None for %s.' % getName(obj))
data = self.getObjectData(obj)
type = obj.conceptType
if type == self.typeConcept:
element = elementTypes['type'](getName(obj), obj.title, **data)
else:
tp = getName(type)
element = elementTypes['concept'](name, obj.title, tp, **data)
self.provideSubElements(obj, element)
return element
def getResourceElement(self, name, obj):
data = self.getObjectData(obj, IResourceSchema)
tp = getName(obj.resourceType)
if isinstance(obj, Document): # backward compatibility
tp = 'textdocument'
element = elementTypes['resource'](name, obj.title, tp, **data)
element.processExport(self)
self.provideSubElements(obj, element)
return element
def provideSubElements(self, obj, element):
for name, extractor in component.getAdapters((obj,), ISubExtractor):
for sub in extractor.extract():
element.add(sub)
def getChildRelations(self, c, predicates=None):
for r in c.getChildRelations(predicates):
if r.predicate != self.typePredicate:
yield self.getChildElement(r)
def getChildElement(self, r):
args = [getName(r.first), getName(r.second), getName(r.predicate)]
if r.order != 0 or r.relevance != 1.0:
args.append(r.order)
if r.relevance != 1.0:
args.append(r.relevance)
return elementTypes['child'](*args)
def getResourceRelations(self, c, predicates=None):
for r in c.getResourceRelations(predicates):
if r.predicate != self.typePredicate:
yield self.getResourceRelationElement(r)
def getResourceRelationElement(self, r):
args = [getName(r.first), getName(r.second), getName(r.predicate)]
if r.order != 0 or r.relevance != 1.0:
args.append(r.order)
if r.relevance != 1.0:
args.append(r.relevance)
return elementTypes['resourceRelation'](*args)
def getObjectData(self, obj, defaultInterface=IConceptSchema): def getObjectData(self, obj, defaultInterface=IConceptSchema):
aObj = adapted(obj) aObj = adapted(obj)
schemaFactory = component.getAdapter(aObj, ISchemaFactory) schemaFactory = component.getAdapter(aObj, ISchemaFactory)
@ -210,9 +268,3 @@ class Extractor(Base):
if not data['description']: if not data['description']:
del data['description'] del data['description']
return data return data
def provideSubElements(self, obj, element):
for name, extractor in component.getAdapters((obj,), ISubExtractor):
for sub in extractor.extract():
element.add(sub)

30
external/browser.py vendored
View file

@ -30,7 +30,7 @@ from zope.app import zapi
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from zope.security.proxy import removeSecurityProxy from zope.security.proxy import removeSecurityProxy
from zope.traversing.api import getPath from zope.traversing.api import getName, getPath
from loops.external.base import Loader, Extractor from loops.external.base import Loader, Extractor
from loops.external.interfaces import IReader, IWriter from loops.external.interfaces import IReader, IWriter
@ -73,6 +73,10 @@ class ExportImport(object):
def export(self): def export(self):
f = StringIO() f = StringIO()
extractor = Extractor(self.context, self.resourceExportDirectory) extractor = Extractor(self.context, self.resourceExportDirectory)
parentIds = self.request.form.get('parents')
if parentIds:
elements = self.extractForParents(extractor, parentIds)
else:
elements = extractor.extract() elements = extractor.extract()
writer = component.getUtility(IWriter) writer = component.getUtility(IWriter)
writer.write(elements, f) writer.write(elements, f)
@ -81,6 +85,30 @@ class ExportImport(object):
self.setDownloadHeader(self.request, text) self.setDownloadHeader(self.request, text)
return text return text
def extractForParents(self, extractor, parentIds):
form = self.request.form
parentIds = [id for id in parentIds.splitlines() if id]
parents = [self.conceptManager.get(id) for id in parentIds]
parents = [p for p in parents if p is not None]
predicateIds = form.get('predicates')
predicates = (predicateIds and [self.conceptManager[id]
for id in parentIds] or None)
includeSubconcepts = form.get('include_subconcepts')
includeResources = form.get('include_resources')
return extractor.extractForParents(parents, predicates,
includeSubconcepts, includeResources)
@Lazy
def conceptManager(self):
return self.context.getConceptManager()
@Lazy
def predicates(self):
ptype = self.conceptManager['predicate']
hasType = self.conceptManager['hasType']
return [dict(name=getName(p), title=p.title)
for p in ptype.getChildren([hasType])]
def upload(self): def upload(self):
data = self.request.get('field.data', None) data = self.request.get('field.data', None)
resourceImportDirectory = (self.request.get('resourceImportDirectory', None) resourceImportDirectory = (self.request.get('resourceImportDirectory', None)

13
external/element.py vendored
View file

@ -37,6 +37,8 @@ from loops.common import adapted
from loops.interfaces import IConceptSchema from loops.interfaces import IConceptSchema
from loops.external.interfaces import IElement from loops.external.interfaces import IElement
from loops.i18n.common import I18NValue from loops.i18n.common import I18NValue
from loops.layout.base import LayoutNode
from loops.view import Node
class Element(dict): class Element(dict):
@ -192,6 +194,7 @@ class NodeElement(Element):
elementType = 'node' elementType = 'node'
posArgs = ('name', 'title', 'path', 'type') posArgs = ('name', 'title', 'path', 'type')
factory = Node
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
for idx, arg in enumerate(args): for idx, arg in enumerate(args):
@ -205,13 +208,20 @@ class NodeElement(Element):
#target = self.pop('target', None) #target = self.pop('target', None)
kw = dict((k, v) for k, v in self.items() kw = dict((k, v) for k, v in self.items()
if k not in self.posArgs) if k not in self.posArgs)
node = loader.addNode(self['name'], self['title'], cont, type, **kw) node = loader.addNode(self['name'], self['title'], cont, type,
factory=self.factory, **kw)
#if target is not None: #if target is not None:
# targetObject = traverse(loader.context, target, None) # targetObject = traverse(loader.context, target, None)
# node.target = targetObject # node.target = targetObject
#self.object = node #self.object = node
class LayoutNodeElement(NodeElement):
elementType = 'layoutNode'
factory = LayoutNode
# element registry # element registry
elementTypes = dict( elementTypes = dict(
@ -221,6 +231,7 @@ elementTypes = dict(
resource=ResourceElement, resource=ResourceElement,
resourceRelation=ResourceRelationElement, resourceRelation=ResourceRelationElement,
node=NodeElement, node=NodeElement,
layoutNode=LayoutNodeElement,
I18NValue=I18NValue, I18NValue=I18NValue,
) )

View file

@ -24,6 +24,36 @@
<div>&nbsp;</div> <div>&nbsp;</div>
<h4>Export Site</h4> <h4>Export Site</h4>
<div>&nbsp;</div> <div>&nbsp;</div>
<div class="row">
<table>
<tr>
<td>
<label for="parents">Parent concepts</label><br />
<textarea name="parents" id="parents"
rows="8" class="pretty"></textarea>
</td>
<td>
<label for="predicates">Predicates</label><br />
<select multiple name="predicates" id="predicates"
size="9">
<option tal:repeat="pred view/predicates"
tal:attributes="value pred/name"
tal:content="pred/title">subobject</option></select>
</td><td>&nbsp;</td>
<td>
<br />
<input type="checkbox" name="include_subconcepts"
id="include_subconcepts" />
<label for="include_subconcepts">Include Subconcepts</label>
<br />
<input type="checkbox" name="include_resources"
id="include_resources" />
<label for="include_resources">Include Resources</label>
</td>
</tr>
</table>
</div>
<div>&nbsp;</div>
<div class="row"> <div class="row">
<div class="controls"> <div class="controls">
<input type="submit" name="loops.export" value="Export" /> <input type="submit" name="loops.export" value="Export" />

View file

@ -197,7 +197,7 @@ class SetupManager(object):
(resourceName, conceptName, getName(predicate))) (resourceName, conceptName, getName(predicate)))
def addNode(self, name, title, container=None, nodeType='page', def addNode(self, name, title, container=None, nodeType='page',
description=u'', body=u'', target=None, **kw): description=u'', body=u'', target=None, factory=Node, **kw):
if container is None: if container is None:
container = self.views container = self.views
nodeType = 'menu' nodeType = 'menu'
@ -209,7 +209,7 @@ class SetupManager(object):
self.log("Wrong node type for '%s': '%s' instead of '%s'." % self.log("Wrong node type for '%s': '%s' instead of '%s'." %
(name, n.nodeType, nodeType)) (name, n.nodeType, nodeType))
else: else:
n = addAndConfigureObject(container, Node, name, title=title, n = addAndConfigureObject(container, factory, name, title=title,
description=description, body=body, description=description, body=body,
nodeType=nodeType, **kw) nodeType=nodeType, **kw)
self.log("Node '%s' ('%s') created." % (name, title)) self.log("Node '%s' ('%s') created." % (name, title))