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')[
|
||||
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
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.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
32
external/browser.py
vendored
|
@ -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
13
external/element.py
vendored
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
30
external/exportimport.pt
vendored
30
external/exportimport.pt
vendored
|
@ -24,6 +24,36 @@
|
|||
<div> </div>
|
||||
<h4>Export Site</h4>
|
||||
<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="controls">
|
||||
<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)))
|
||||
|
||||
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))
|
||||
|
|
Loading…
Add table
Reference in a new issue