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:
helmutm 2008-03-23 21:37:28 +00:00
parent b7097a09c5
commit c47cc6d9b1
8 changed files with 171 additions and 38 deletions

38
external/README.txt vendored
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -0,0 +1 @@
Test File Contents

4
external/tests.py vendored
View file

@ -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."

View file

@ -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
View file

@ -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')