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
'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
------------------
@ -66,11 +82,10 @@ Extracting elements
-------------------
>>> from loops.external.base import Extractor
>>> extractor = Extractor(loopsRoot)
>>> extractor = Extractor(loopsRoot, os.path.join(dataDirectory, 'export'))
>>> elements = list(extractor.extract())
>>> len(elements)
15
20
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',
viewName=u'')...
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('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 zope.publisher.browser import TestRequest
>>> input = {'field.data': output}
>>> input = {'field.data': output, 'resourceDirectory': dataDirectory}
>>> view = ExportImport(loopsRoot, TestRequest(input))
>>> view.upload()
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
import itertools
import os
import zdaemon
from zope import component
from zope.cachedescriptors.property import Lazy
from zope.interface import implements
@ -42,8 +44,9 @@ from loops.setup import SetupManager
class Base(object):
def __init__(self, context):
def __init__(self, context, resourceDirectory=None):
self.context = context
self.resourceDirectory = resourceDirectory
@Lazy
def concepts(self):
@ -70,8 +73,8 @@ class Loader(Base, SetupManager):
implements(ILoader)
def __init__(self, context):
self.context = context
def __init__(self, context, resourceDirectory=None):
super(Loader, self).__init__(context, resourceDirectory)
self.logger = StringIO()
def load(self, elements):
@ -90,8 +93,8 @@ class Extractor(Base):
return itertools.chain(self.extractTypes(),
self.extractConcepts(),
self.extractChildren(),
#self.extractResources(),
#self.extractResourceRelations(),
self.extractResources(),
self.extractResourceRelations(),
self.extractNodes(),
)
@ -111,12 +114,14 @@ class Extractor(Base):
yield conceptElement(name, obj.title, tp, **data)
def extractResources(self):
resourceElement = elementTypes['resource']
elementClass = elementTypes['resource']
for name, obj in self.resources.items():
# TODO: handle ``data`` attribute...
data = self.getObjectData(obj)
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):
aObj = adapted(obj)
@ -149,6 +154,19 @@ class Extractor(Base):
args.append(r.relevance)
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=''):
if parent is None:
parent = self.views

27
external/browser.py vendored
View file

@ -22,16 +22,19 @@ view class(es) for import/export.
$Id$
"""
from cStringIO import StringIO
import os
from zope import component
from zope.interface import Interface, implements
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 cStringIO import StringIO
from zope.traversing.api import getPath
from loops.external.base import Loader, Extractor
from loops.external.interfaces import IReader, IWriter
from loops import util
class ExportImport(object):
@ -43,6 +46,22 @@ class ExportImport(object):
self.request = request
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):
action = self.request.get('loops.action', None)
if action:
@ -53,7 +72,7 @@ class ExportImport(object):
def export(self):
f = StringIO()
extractor = Extractor(self.context)
extractor = Extractor(self.context, self.resourceExportDirectory)
elements = extractor.extract()
writer = component.getUtility(IWriter)
writer.write(elements, f)
@ -64,11 +83,13 @@ class ExportImport(object):
def upload(self):
data = self.request.get('field.data', None)
resourceImportDirectory = (self.request.get('resourceImportDirectory', None)
or self.resourceImportDirectory)
if not data:
return False
reader = component.getUtility(IReader)
elements = reader.read(data)
loader = Loader(self.context)
loader = Loader(self.context, )
loader.load(elements)
self.message = u'Content uploaded and imported.'
return False

67
external/element.py vendored
View file

@ -23,6 +23,7 @@ and import of loops objects.
$Id$
"""
import os
from zope.cachedescriptors.property import Lazy
from zope.dottedname.resolve import resolve
from zope.interface import Interface, implements
@ -45,6 +46,9 @@ class Element(dict):
for k, v in kw.items():
self[k] = v
def processExport(self, extractor):
pass
def __call__(self, loader):
pass
@ -95,6 +99,44 @@ class ChildElement(Element):
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):
elementType = 'node'
@ -118,34 +160,13 @@ class NodeElement(Element):
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
elementTypes = dict(
type=TypeElement,
concept=ConceptElement,
resource=ResourceElement,
child=ChildElement,
resource=ResourceElement,
resourceRelation=ResourceRelationElement,
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$
import unittest, doctest
import os
from zope.testing.doctestunit import DocFileSuite
from zope.interface.verify import verifyClass
dataDirectory = os.path.join(os.path.dirname(__file__), 'testdata')
class Test(unittest.TestCase):
"Basic tests for the loops.external package."

View file

@ -165,6 +165,33 @@ class SetupManager(object):
else:
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',
description=u'', body=u'', targetName=None, **kw):
if container is None:

13
util.py
View file

@ -22,12 +22,14 @@ Utility functions.
$Id$
"""
import os
from zope import component
from zope.app.intid.interfaces import IIntIds
from zope.interface import directlyProvides, directlyProvidedBy
from zope.i18nmessageid import MessageFactory
from zope.schema import vocabulary
import cybertools
from loops.browser.util import html_quote
_ = MessageFactory('loops')
@ -94,3 +96,14 @@ def getUidForObject(obj):
intIds = component.getUtility(IIntIds)
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')