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:
parent
dddc43086d
commit
c78bef8ec0
6 changed files with 207 additions and 63 deletions
23
external/README.txt
vendored
23
external/README.txt
vendored
|
@ -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
168
external/base.py
vendored
|
@ -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)
|
|
||||||
|
|
||||||
|
|
32
external/browser.py
vendored
32
external/browser.py
vendored
|
@ -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,7 +73,11 @@ 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)
|
||||||
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 = component.getUtility(IWriter)
|
||||||
writer.write(elements, f)
|
writer.write(elements, f)
|
||||||
text = f.getvalue()
|
text = f.getvalue()
|
||||||
|
@ -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
13
external/element.py
vendored
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
30
external/exportimport.pt
vendored
30
external/exportimport.pt
vendored
|
@ -24,6 +24,36 @@
|
||||||
<div> </div>
|
<div> </div>
|
||||||
<h4>Export Site</h4>
|
<h4>Export Site</h4>
|
||||||
<div> </div>
|
<div> </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> </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> </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" />
|
||||||
|
|
4
setup.py
4
setup.py
|
@ -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))
|
||||||
|
|
Loading…
Add table
Reference in a new issue