added export/import of resources and resource relations, storing resource data (text/content) in files
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2469 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
b7097a09c5
commit
c47cc6d9b1
8 changed files with 171 additions and 38 deletions
38
external/README.txt
vendored
38
external/README.txt
vendored
|
@ -48,6 +48,22 @@ Creating the corresponding objects
|
||||||
>>> adapted(concepts['myquery']).viewName
|
>>> adapted(concepts['myquery']).viewName
|
||||||
'mystuff.html'
|
'mystuff.html'
|
||||||
|
|
||||||
|
Working with resources
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
>>> import os
|
||||||
|
>>> from loops.external.tests import dataDirectory
|
||||||
|
>>> loader.resourceDirectory = os.path.join(dataDirectory, 'import')
|
||||||
|
|
||||||
|
>>> input = ("resource('doc04.txt', u'Document 4', 'textdocument')\n"
|
||||||
|
... "resourceRelation('myquery', 'doc04.txt', 'standard')")
|
||||||
|
>>> reader = PyReader()
|
||||||
|
>>> elements = reader.read(input)
|
||||||
|
>>> loader.load(elements)
|
||||||
|
|
||||||
|
>>> sorted(resources)
|
||||||
|
[u'd001.txt', u'd002.txt', u'd003.txt', u'doc04.txt']
|
||||||
|
|
||||||
Working with nodes
|
Working with nodes
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
@ -66,11 +82,10 @@ Extracting elements
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
>>> from loops.external.base import Extractor
|
>>> from loops.external.base import Extractor
|
||||||
|
>>> extractor = Extractor(loopsRoot, os.path.join(dataDirectory, 'export'))
|
||||||
>>> extractor = Extractor(loopsRoot)
|
|
||||||
>>> elements = list(extractor.extract())
|
>>> elements = list(extractor.extract())
|
||||||
>>> len(elements)
|
>>> len(elements)
|
||||||
15
|
20
|
||||||
|
|
||||||
Writing object information to the external storage
|
Writing object information to the external storage
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
@ -86,7 +101,9 @@ Writing object information to the external storage
|
||||||
type(u'query', u'Query', options=u'', typeInterface='loops.query.IQueryConcept',
|
type(u'query', u'Query', options=u'', typeInterface='loops.query.IQueryConcept',
|
||||||
viewName=u'')...
|
viewName=u'')...
|
||||||
concept(u'myquery', u'My Query', u'query', options=u'', viewName='mystuff.html')...
|
concept(u'myquery', u'My Query', u'query', options=u'', viewName='mystuff.html')...
|
||||||
child(u'projects', u'customer', u'standard')
|
child(u'projects', u'customer', u'standard')...
|
||||||
|
resource(u'doc04.txt', u'Document 4', u'textdocument', contentType='text/restructured')
|
||||||
|
resourceRelation(u'myquery', u'doc04.txt', u'standard')
|
||||||
node('home', u'Home', '', u'menu', body=u'Welcome')
|
node('home', u'Home', '', u'menu', body=u'Welcome')
|
||||||
node('myquery', u'My Query', 'home', u'page', target=u'concepts/myquery')...
|
node('myquery', u'My Query', 'home', u'page', target=u'concepts/myquery')...
|
||||||
|
|
||||||
|
@ -97,7 +114,18 @@ The Export/Import View
|
||||||
>>> from loops.external.browser import ExportImport
|
>>> from loops.external.browser import ExportImport
|
||||||
>>> from zope.publisher.browser import TestRequest
|
>>> from zope.publisher.browser import TestRequest
|
||||||
|
|
||||||
>>> input = {'field.data': output}
|
>>> input = {'field.data': output, 'resourceDirectory': dataDirectory}
|
||||||
>>> view = ExportImport(loopsRoot, TestRequest(input))
|
>>> view = ExportImport(loopsRoot, TestRequest(input))
|
||||||
>>> view.upload()
|
>>> view.upload()
|
||||||
False
|
False
|
||||||
|
|
||||||
|
|
||||||
|
Fin de Partie
|
||||||
|
=============
|
||||||
|
|
||||||
|
>>> placefulTearDown()
|
||||||
|
|
||||||
|
>>> exportDir = os.path.join(dataDirectory, 'export')
|
||||||
|
>>> for fname in os.listdir(exportDir):
|
||||||
|
... os.unlink(os.path.join(exportDir, fname))
|
||||||
|
|
||||||
|
|
32
external/base.py
vendored
32
external/base.py
vendored
|
@ -25,6 +25,8 @@ $Id$
|
||||||
|
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
import itertools
|
import itertools
|
||||||
|
import os
|
||||||
|
import zdaemon
|
||||||
from zope import component
|
from zope import component
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
|
@ -42,8 +44,9 @@ from loops.setup import SetupManager
|
||||||
|
|
||||||
class Base(object):
|
class Base(object):
|
||||||
|
|
||||||
def __init__(self, context):
|
def __init__(self, context, resourceDirectory=None):
|
||||||
self.context = context
|
self.context = context
|
||||||
|
self.resourceDirectory = resourceDirectory
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def concepts(self):
|
def concepts(self):
|
||||||
|
@ -70,8 +73,8 @@ class Loader(Base, SetupManager):
|
||||||
|
|
||||||
implements(ILoader)
|
implements(ILoader)
|
||||||
|
|
||||||
def __init__(self, context):
|
def __init__(self, context, resourceDirectory=None):
|
||||||
self.context = context
|
super(Loader, self).__init__(context, resourceDirectory)
|
||||||
self.logger = StringIO()
|
self.logger = StringIO()
|
||||||
|
|
||||||
def load(self, elements):
|
def load(self, elements):
|
||||||
|
@ -90,8 +93,8 @@ class Extractor(Base):
|
||||||
return itertools.chain(self.extractTypes(),
|
return itertools.chain(self.extractTypes(),
|
||||||
self.extractConcepts(),
|
self.extractConcepts(),
|
||||||
self.extractChildren(),
|
self.extractChildren(),
|
||||||
#self.extractResources(),
|
self.extractResources(),
|
||||||
#self.extractResourceRelations(),
|
self.extractResourceRelations(),
|
||||||
self.extractNodes(),
|
self.extractNodes(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -111,12 +114,14 @@ class Extractor(Base):
|
||||||
yield conceptElement(name, obj.title, tp, **data)
|
yield conceptElement(name, obj.title, tp, **data)
|
||||||
|
|
||||||
def extractResources(self):
|
def extractResources(self):
|
||||||
resourceElement = elementTypes['resource']
|
elementClass = elementTypes['resource']
|
||||||
for name, obj in self.resources.items():
|
for name, obj in self.resources.items():
|
||||||
# TODO: handle ``data`` attribute...
|
# TODO: handle ``data`` attribute...
|
||||||
data = self.getObjectData(obj)
|
data = self.getObjectData(obj)
|
||||||
tp = getName(obj.resourceType)
|
tp = getName(obj.resourceType)
|
||||||
yield resourceElement(name, obj.title, tp, **data)
|
element = elementClass(name, obj.title, tp, **data)
|
||||||
|
element.processExport(self)
|
||||||
|
yield element
|
||||||
|
|
||||||
def getObjectData(self, obj):
|
def getObjectData(self, obj):
|
||||||
aObj = adapted(obj)
|
aObj = adapted(obj)
|
||||||
|
@ -149,6 +154,19 @@ class Extractor(Base):
|
||||||
args.append(r.relevance)
|
args.append(r.relevance)
|
||||||
yield childElement(*args)
|
yield childElement(*args)
|
||||||
|
|
||||||
|
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:
|
||||||
|
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
|
||||||
|
|
27
external/browser.py
vendored
27
external/browser.py
vendored
|
@ -22,16 +22,19 @@ view class(es) for import/export.
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from cStringIO import StringIO
|
||||||
|
import os
|
||||||
from zope import component
|
from zope import component
|
||||||
from zope.interface import Interface, implements
|
from zope.interface import Interface, implements
|
||||||
from zope.app import zapi
|
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 cStringIO import StringIO
|
from zope.traversing.api import 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
|
||||||
|
from loops import util
|
||||||
|
|
||||||
|
|
||||||
class ExportImport(object):
|
class ExportImport(object):
|
||||||
|
@ -43,6 +46,22 @@ class ExportImport(object):
|
||||||
self.request = request
|
self.request = request
|
||||||
self.message = u''
|
self.message = u''
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def baseDirectory(self):
|
||||||
|
return util.getVarDirectory(self.request)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def sitePath(self):
|
||||||
|
return getPath(self.context)[1:].replace('/', '_')
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def resourceImportDirectory(self):
|
||||||
|
return os.path.join(self.baseDirectory, 'import', self.sitePath)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def resourceExportDirectory(self):
|
||||||
|
return os.path.join(self.baseDirectory, 'export', self.sitePath)
|
||||||
|
|
||||||
def submit(self):
|
def submit(self):
|
||||||
action = self.request.get('loops.action', None)
|
action = self.request.get('loops.action', None)
|
||||||
if action:
|
if action:
|
||||||
|
@ -53,7 +72,7 @@ class ExportImport(object):
|
||||||
|
|
||||||
def export(self):
|
def export(self):
|
||||||
f = StringIO()
|
f = StringIO()
|
||||||
extractor = Extractor(self.context)
|
extractor = Extractor(self.context, self.resourceExportDirectory)
|
||||||
elements = extractor.extract()
|
elements = extractor.extract()
|
||||||
writer = component.getUtility(IWriter)
|
writer = component.getUtility(IWriter)
|
||||||
writer.write(elements, f)
|
writer.write(elements, f)
|
||||||
|
@ -64,11 +83,13 @@ class ExportImport(object):
|
||||||
|
|
||||||
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)
|
||||||
|
or self.resourceImportDirectory)
|
||||||
if not data:
|
if not data:
|
||||||
return False
|
return False
|
||||||
reader = component.getUtility(IReader)
|
reader = component.getUtility(IReader)
|
||||||
elements = reader.read(data)
|
elements = reader.read(data)
|
||||||
loader = Loader(self.context)
|
loader = Loader(self.context, )
|
||||||
loader.load(elements)
|
loader.load(elements)
|
||||||
self.message = u'Content uploaded and imported.'
|
self.message = u'Content uploaded and imported.'
|
||||||
return False
|
return False
|
||||||
|
|
67
external/element.py
vendored
67
external/element.py
vendored
|
@ -23,6 +23,7 @@ and import of loops objects.
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.dottedname.resolve import resolve
|
from zope.dottedname.resolve import resolve
|
||||||
from zope.interface import Interface, implements
|
from zope.interface import Interface, implements
|
||||||
|
@ -45,6 +46,9 @@ class Element(dict):
|
||||||
for k, v in kw.items():
|
for k, v in kw.items():
|
||||||
self[k] = v
|
self[k] = v
|
||||||
|
|
||||||
|
def processExport(self, extractor):
|
||||||
|
pass
|
||||||
|
|
||||||
def __call__(self, loader):
|
def __call__(self, loader):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -95,6 +99,44 @@ class ChildElement(Element):
|
||||||
loader.assignChild(self['first'], self['second'], self['predicate'])
|
loader.assignChild(self['first'], self['second'], self['predicate'])
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceElement(Element):
|
||||||
|
|
||||||
|
elementType = 'resource'
|
||||||
|
posArgs = ('name', 'title', 'type')
|
||||||
|
|
||||||
|
def processExport(self, extractor):
|
||||||
|
content = self.pop('data', '')
|
||||||
|
if (self.get('contentType', '').startswith('text/')
|
||||||
|
and isinstance(content, unicode)):
|
||||||
|
content = content.encode('UTF-8')
|
||||||
|
dataPath = os.path.join(extractor.resourceDirectory, self['name'])
|
||||||
|
f = open(dataPath, 'w')
|
||||||
|
f.write(content)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
def __call__(self, loader):
|
||||||
|
type = loader.concepts[self['type']]
|
||||||
|
kw = dict((k, v) for k, v in self.items()
|
||||||
|
if k not in self.posArgs)
|
||||||
|
dataPath = os.path.join(loader.resourceDirectory, self['name'])
|
||||||
|
if os.path.exists(dataPath):
|
||||||
|
f = open(dataPath, 'r')
|
||||||
|
content = f.read()
|
||||||
|
if self.get('contentType', '').startswith('text/'):
|
||||||
|
content = content.decode('UTF-8')
|
||||||
|
kw['data'] = content
|
||||||
|
f.close()
|
||||||
|
loader.addResource(self['name'], self['title'], type, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceRelationElement(ChildElement):
|
||||||
|
|
||||||
|
elementType = 'resourceRelation'
|
||||||
|
|
||||||
|
def __call__(self, loader):
|
||||||
|
loader.assignResource(self['first'], self['second'], self['predicate'])
|
||||||
|
|
||||||
|
|
||||||
class NodeElement(Element):
|
class NodeElement(Element):
|
||||||
|
|
||||||
elementType = 'node'
|
elementType = 'node'
|
||||||
|
@ -118,34 +160,13 @@ class NodeElement(Element):
|
||||||
node.target = targetObject
|
node.target = targetObject
|
||||||
|
|
||||||
|
|
||||||
# not yet implemented
|
|
||||||
|
|
||||||
class ResourceElement(Element):
|
|
||||||
|
|
||||||
elementType = 'resource'
|
|
||||||
posArgs = ('name', 'title', 'type')
|
|
||||||
|
|
||||||
def __call__(self, loader):
|
|
||||||
type = loader.concepts[self['type']]
|
|
||||||
kw = dict((k, v) for k, v in self.items()
|
|
||||||
if k not in self.posArgs)
|
|
||||||
loader.addResource(self['name'], self['title'], type, **kw)
|
|
||||||
|
|
||||||
|
|
||||||
class ResourceRelationElement(ChildElement):
|
|
||||||
|
|
||||||
elementType = 'resourceRelation'
|
|
||||||
|
|
||||||
def __call__(self, loader):
|
|
||||||
loader.assignResource(self['first'], self['second'], self['predicate'])
|
|
||||||
|
|
||||||
|
|
||||||
# element registry
|
# element registry
|
||||||
|
|
||||||
elementTypes = dict(
|
elementTypes = dict(
|
||||||
type=TypeElement,
|
type=TypeElement,
|
||||||
concept=ConceptElement,
|
concept=ConceptElement,
|
||||||
resource=ResourceElement,
|
|
||||||
child=ChildElement,
|
child=ChildElement,
|
||||||
|
resource=ResourceElement,
|
||||||
|
resourceRelation=ResourceRelationElement,
|
||||||
node=NodeElement,
|
node=NodeElement,
|
||||||
)
|
)
|
||||||
|
|
1
external/testdata/import/doc04.txt
vendored
Normal file
1
external/testdata/import/doc04.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Test File Contents
|
4
external/tests.py
vendored
4
external/tests.py
vendored
|
@ -1,10 +1,14 @@
|
||||||
# $Id$
|
# $Id$
|
||||||
|
|
||||||
import unittest, doctest
|
import unittest, doctest
|
||||||
|
import os
|
||||||
from zope.testing.doctestunit import DocFileSuite
|
from zope.testing.doctestunit import DocFileSuite
|
||||||
from zope.interface.verify import verifyClass
|
from zope.interface.verify import verifyClass
|
||||||
|
|
||||||
|
|
||||||
|
dataDirectory = os.path.join(os.path.dirname(__file__), 'testdata')
|
||||||
|
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
"Basic tests for the loops.external package."
|
"Basic tests for the loops.external package."
|
||||||
|
|
||||||
|
|
27
setup.py
27
setup.py
|
@ -165,6 +165,33 @@ class SetupManager(object):
|
||||||
else:
|
else:
|
||||||
concept.assignChild(child, predicate)
|
concept.assignChild(child, predicate)
|
||||||
|
|
||||||
|
def addResource(self, name, title, resourceType, description=u'', **kw):
|
||||||
|
if name in self.resources:
|
||||||
|
self.log("Resource '%s' ('%s') already exists." % (name, title))
|
||||||
|
c = self.resources[name]
|
||||||
|
if c.resourceType != resourceType:
|
||||||
|
self.log("Wrong resource type for '%s': '%s' instead of '%s'." %
|
||||||
|
(name, getName(c.resourceType), getName(resourceType)))
|
||||||
|
else:
|
||||||
|
c = addAndConfigureObject(self.resources, Resource, name, title=title,
|
||||||
|
description=description,
|
||||||
|
resourceType=resourceType, **kw)
|
||||||
|
self.log("Resource '%s' ('%s') created." % (name, title))
|
||||||
|
return c
|
||||||
|
|
||||||
|
def assignResource(self, conceptName, resourceName, predicate=None):
|
||||||
|
if predicate is None:
|
||||||
|
predicate = self.concepts.getDefaultPredicate()
|
||||||
|
if isinstance(predicate, basestring):
|
||||||
|
predicate = self.concepts[predicate]
|
||||||
|
concept = self.concepts[conceptName]
|
||||||
|
resource = self.resources[resourceName]
|
||||||
|
if resource in concept.getResources([predicate]):
|
||||||
|
self.log("Concept '%s' is already assigned to '%s with predicate '%s'.'" %
|
||||||
|
(conceptName, resourceName, getName(predicate)))
|
||||||
|
else:
|
||||||
|
concept.assignResource(resource, predicate)
|
||||||
|
|
||||||
def addNode(self, name, title, container=None, nodeType='page',
|
def addNode(self, name, title, container=None, nodeType='page',
|
||||||
description=u'', body=u'', targetName=None, **kw):
|
description=u'', body=u'', targetName=None, **kw):
|
||||||
if container is None:
|
if container is None:
|
||||||
|
|
13
util.py
13
util.py
|
@ -22,12 +22,14 @@ Utility functions.
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
from zope import component
|
from zope import component
|
||||||
from zope.app.intid.interfaces import IIntIds
|
from zope.app.intid.interfaces import IIntIds
|
||||||
from zope.interface import directlyProvides, directlyProvidedBy
|
from zope.interface import directlyProvides, directlyProvidedBy
|
||||||
from zope.i18nmessageid import MessageFactory
|
from zope.i18nmessageid import MessageFactory
|
||||||
from zope.schema import vocabulary
|
from zope.schema import vocabulary
|
||||||
|
|
||||||
|
import cybertools
|
||||||
from loops.browser.util import html_quote
|
from loops.browser.util import html_quote
|
||||||
|
|
||||||
_ = MessageFactory('loops')
|
_ = MessageFactory('loops')
|
||||||
|
@ -94,3 +96,14 @@ def getUidForObject(obj):
|
||||||
intIds = component.getUtility(IIntIds)
|
intIds = component.getUtility(IIntIds)
|
||||||
return str(intIds.queryId(obj))
|
return str(intIds.queryId(obj))
|
||||||
|
|
||||||
|
|
||||||
|
def getVarDirectory(request=None):
|
||||||
|
instanceHome = None
|
||||||
|
if request is not None:
|
||||||
|
pub = request.publication
|
||||||
|
if pub is not None:
|
||||||
|
instanceHome = os.path.dirname(pub.db.getName())
|
||||||
|
if instanceHome is None:
|
||||||
|
instanceHome = os.path.dirname(os.path.dirname(os.path.dirname(
|
||||||
|
os.path.dirname(cybertools.__file__))))
|
||||||
|
return os.path.join(instanceHome, 'var')
|
||||||
|
|
Loading…
Add table
Reference in a new issue