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')[
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
======================

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.element import elementTypes
from loops.interfaces import IConceptSchema, IResourceSchema
from loops.layout.base import LayoutNode
from loops.resource import Document, MediaAsset
from loops.setup import SetupManager
@ -109,79 +110,38 @@ class Extractor(Base):
yield element
def extractConcepts(self):
conceptElement = elementTypes['concept']
typeConcept = self.typeConcept
for name, obj in self.concepts.items():
if obj.conceptType is None:
raise ValueError('Concept type is None for %s.' % getName(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
if obj.conceptType != self.typeConcept:
yield self.getConceptElement(name, obj)
def extractResources(self):
elementClass = elementTypes['resource']
for name, obj in self.resources.items():
data = self.getObjectData(obj, IResourceSchema)
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
yield self.getResourceElement(name, obj)
def extractChildren(self):
childElement = elementTypes['child']
typePredicate = self.typePredicate
for c in self.concepts.values():
for r in c.getChildRelations():
if r.predicate != typePredicate:
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)
for r in self.getChildRelations(c):
yield r
def extractResourceRelations(self):
elementClass = elementTypes['resourceRelation']
typePredicate = self.typePredicate
for c in self.concepts.values():
for r in c.getResourceRelations():
if r.predicate != typePredicate:
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)
for r in self.getResourceRelations(c):
yield r
def extractNodes(self, parent=None, path=''):
if parent is None:
parent = self.views
elementClass = elementTypes['node']
for name, obj in parent.items():
data = {}
for attr in ('description', 'body', 'viewName'):
value = getattr(obj, attr)
for attr in ('description', 'body', 'viewName', 'pageName'):
value = getattr(obj, attr, None)
if value:
data[attr] = value
target = obj.target
if target is not None:
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)
self.provideSubElements(obj, elem)
yield elem
@ -190,8 +150,106 @@ class Extractor(Base):
#self.provideSubElements(obj, 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
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):
aObj = adapted(obj)
schemaFactory = component.getAdapter(aObj, ISchemaFactory)
@ -210,9 +268,3 @@ class Extractor(Base):
if not data['description']:
del data['description']
return data
def provideSubElements(self, obj, element):
for name, extractor in component.getAdapters((obj,), ISubExtractor):
for sub in extractor.extract():
element.add(sub)

32
external/browser.py vendored
View file

@ -30,7 +30,7 @@ from zope.app import zapi
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy
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.interfaces import IReader, IWriter
@ -73,7 +73,11 @@ class ExportImport(object):
def export(self):
f = StringIO()
extractor = Extractor(self.context, self.resourceExportDirectory)
elements = extractor.extract()
parentIds = self.request.form.get('parents')
if parentIds:
elements = self.extractForParents(extractor, parentIds)
else:
elements = extractor.extract()
writer = component.getUtility(IWriter)
writer.write(elements, f)
text = f.getvalue()
@ -81,6 +85,30 @@ class ExportImport(object):
self.setDownloadHeader(self.request, 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):
data = self.request.get('field.data', 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.external.interfaces import IElement
from loops.i18n.common import I18NValue
from loops.layout.base import LayoutNode
from loops.view import Node
class Element(dict):
@ -192,6 +194,7 @@ class NodeElement(Element):
elementType = 'node'
posArgs = ('name', 'title', 'path', 'type')
factory = Node
def __init__(self, *args, **kw):
for idx, arg in enumerate(args):
@ -205,13 +208,20 @@ class NodeElement(Element):
#target = self.pop('target', None)
kw = dict((k, v) for k, v in self.items()
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:
# targetObject = traverse(loader.context, target, None)
# node.target = targetObject
#self.object = node
class LayoutNodeElement(NodeElement):
elementType = 'layoutNode'
factory = LayoutNode
# element registry
elementTypes = dict(
@ -221,6 +231,7 @@ elementTypes = dict(
resource=ResourceElement,
resourceRelation=ResourceRelationElement,
node=NodeElement,
layoutNode=LayoutNodeElement,
I18NValue=I18NValue,
)

View file

@ -24,6 +24,36 @@
<div>&nbsp;</div>
<h4>Export Site</h4>
<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="controls">
<input type="submit" name="loops.export" value="Export" />

View file

@ -197,7 +197,7 @@ class SetupManager(object):
(resourceName, conceptName, getName(predicate)))
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:
container = self.views
nodeType = 'menu'
@ -209,7 +209,7 @@ class SetupManager(object):
self.log("Wrong node type for '%s': '%s' instead of '%s'." %
(name, n.nodeType, nodeType))
else:
n = addAndConfigureObject(container, Node, name, title=title,
n = addAndConfigureObject(container, factory, name, title=title,
description=description, body=body,
nodeType=nodeType, **kw)
self.log("Node '%s' ('%s') created." % (name, title))