Media assets and documents as target objects for nodes: basically OK
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1043 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
b02329358a
commit
21b6af48b9
8 changed files with 117 additions and 52 deletions
32
README.txt
32
README.txt
|
@ -286,11 +286,6 @@ target may be moved or renamed without any problems.)
|
||||||
>>> m111.title
|
>>> m111.title
|
||||||
u'New title for m111'
|
u'New title for m111'
|
||||||
>>> nodeConfig.targetUri = '.loops/resources/doc1'
|
>>> nodeConfig.targetUri = '.loops/resources/doc1'
|
||||||
|
|
||||||
We have to get a new adapter to avoid problems with lazy variables:
|
|
||||||
|
|
||||||
>>> nodeConfig = INodeConfigSchema(m111)
|
|
||||||
>>> nodeConfig.title = 'New title for m111'
|
|
||||||
>>> m111.target is doc1
|
>>> m111.target is doc1
|
||||||
True
|
True
|
||||||
>>> nodeConfig.targetType
|
>>> nodeConfig.targetType
|
||||||
|
@ -327,16 +322,33 @@ application uses a subclass that does all the other stuff for form handling.)
|
||||||
>>> isinstance(resources['m1.m11.m111'], Document)
|
>>> isinstance(resources['m1.m11.m111'], Document)
|
||||||
True
|
True
|
||||||
|
|
||||||
It is also possible to edit a target's attributes directly in an
|
A node object provides the targetSchema of its target:
|
||||||
|
|
||||||
|
>>> from loops.interfaces import IDocumentView
|
||||||
|
>>> from loops.interfaces import IMediaAssetView
|
||||||
|
>>> IDocumentView.providedBy(m111)
|
||||||
|
True
|
||||||
|
>>> IMediaAssetView.providedBy(m111)
|
||||||
|
False
|
||||||
|
>>> m111.target = None
|
||||||
|
>>> IDocumentView.providedBy(m111)
|
||||||
|
False
|
||||||
|
>>> m111.target = resources['ma07']
|
||||||
|
>>> IDocumentView.providedBy(m111)
|
||||||
|
False
|
||||||
|
>>> IMediaAssetView.providedBy(m111)
|
||||||
|
True
|
||||||
|
|
||||||
|
It is possible to edit a target's attributes directly in an
|
||||||
edit form provided by the node:
|
edit form provided by the node:
|
||||||
|
|
||||||
>>> from loops.target import DocumentProxy, MediaAssetProxy
|
>>> from loops.target import DocumentProxy, MediaAssetProxy
|
||||||
>>> ztapi.provideAdapter(INode, IDocument, DocumentProxy)
|
>>> ztapi.provideAdapter(INode, IDocumentView, DocumentProxy)
|
||||||
>>> ztapi.provideAdapter(INode, IMediaAsset, MediaAssetProxy)
|
>>> ztapi.provideAdapter(INode, IMediaAssetView, MediaAssetProxy)
|
||||||
|
|
||||||
>>> proxy = zapi.getAdapter(m111, IDocument)
|
>>> proxy = zapi.getAdapter(m111, IDocumentView)
|
||||||
>>> proxy.title = u'Set via proxy'
|
>>> proxy.title = u'Set via proxy'
|
||||||
>>> resources['m1.m11.m111'].title
|
>>> resources['ma07'].title
|
||||||
u'Set via proxy'
|
u'Set via proxy'
|
||||||
|
|
||||||
Ordering Nodes
|
Ordering Nodes
|
||||||
|
|
|
@ -167,7 +167,7 @@
|
||||||
<addform
|
<addform
|
||||||
label="Add Document"
|
label="Add Document"
|
||||||
name="AddLoopsDocument.html"
|
name="AddLoopsDocument.html"
|
||||||
schema="loops.interfaces.IDocument"
|
schema="loops.interfaces.IDocumentSchema"
|
||||||
fields="title data contentType"
|
fields="title data contentType"
|
||||||
content_factory="loops.resource.Document"
|
content_factory="loops.resource.Document"
|
||||||
permission="zope.ManageContent" />
|
permission="zope.ManageContent" />
|
||||||
|
@ -184,7 +184,7 @@
|
||||||
<editform
|
<editform
|
||||||
label="Edit Document"
|
label="Edit Document"
|
||||||
name="edit.html"
|
name="edit.html"
|
||||||
schema="loops.interfaces.IDocument"
|
schema="loops.interfaces.IDocumentSchema"
|
||||||
fields="title data contentType"
|
fields="title data contentType"
|
||||||
for="loops.interfaces.IDocument"
|
for="loops.interfaces.IDocument"
|
||||||
permission="zope.ManageContent"
|
permission="zope.ManageContent"
|
||||||
|
@ -195,7 +195,7 @@
|
||||||
<addform
|
<addform
|
||||||
label="Add Media Asset"
|
label="Add Media Asset"
|
||||||
name="AddLoopsMediaAsset.html"
|
name="AddLoopsMediaAsset.html"
|
||||||
schema="loops.interfaces.IMediaAsset"
|
schema="loops.interfaces.IMediaAssetSchema"
|
||||||
fields="title data contentType"
|
fields="title data contentType"
|
||||||
content_factory="loops.resource.MediaAsset"
|
content_factory="loops.resource.MediaAsset"
|
||||||
permission="zope.ManageContent"
|
permission="zope.ManageContent"
|
||||||
|
@ -212,11 +212,11 @@
|
||||||
<editform
|
<editform
|
||||||
label="Edit Media Asset"
|
label="Edit Media Asset"
|
||||||
name="edit.html"
|
name="edit.html"
|
||||||
schema="loops.interfaces.IMediaAsset"
|
schema="loops.interfaces.IMediaAssetSchema"
|
||||||
fields="title data contentType"
|
fields="title data contentType"
|
||||||
for="loops.interfaces.IMediaAsset"
|
for="loops.interfaces.IMediaAsset"
|
||||||
permission="zope.ManageContent"
|
permission="zope.ManageContent"
|
||||||
menu="zmi_views" title="Edit"
|
menu="zmi_views" title="Edit Media Asset"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- suppress the upload menu item: -->
|
<!-- suppress the upload menu item: -->
|
||||||
|
@ -271,8 +271,8 @@
|
||||||
label="Add Node"
|
label="Add Node"
|
||||||
name="AddLoopsNode.html"
|
name="AddLoopsNode.html"
|
||||||
content_factory="loops.view.Node"
|
content_factory="loops.view.Node"
|
||||||
schema="loops.interfaces.INodeConfigSchema"
|
schema="loops.interfaces.INode"
|
||||||
fields="title description nodeType targetType targetUri createTarget"
|
fields="title description nodeType body"
|
||||||
class="loops.browser.node.ConfigureView"
|
class="loops.browser.node.ConfigureView"
|
||||||
permission="zope.ManageContent">
|
permission="zope.ManageContent">
|
||||||
|
|
||||||
|
@ -327,20 +327,25 @@
|
||||||
</editform>
|
</editform>
|
||||||
|
|
||||||
<editform
|
<editform
|
||||||
label="Edit Target"
|
label="Edit Media Asset"
|
||||||
name="edit_target.html"
|
name="edit_target.html"
|
||||||
schema="loops.interfaces.IMediaAsset"
|
schema="loops.interfaces.IMediaAsset"
|
||||||
fields="title data contentType"
|
fields="title data contentType"
|
||||||
for="loops.interfaces.INode"
|
for="loops.interfaces.IMediaAssetView"
|
||||||
permission="zope.ManageContent"
|
permission="zope.ManageContent"
|
||||||
|
menu="zmi_views" title="Edit Media Asset"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<menuItem
|
<editform
|
||||||
for="loops.interfaces.INode"
|
label="Edit Document"
|
||||||
menu="zmi_views" action="edit_target.html" title="Edit Target"
|
name="edit_target.html"
|
||||||
filter="context/target"
|
schema="loops.interfaces.IDocument"
|
||||||
|
fields="title data contentType"
|
||||||
|
for="loops.interfaces.IDocumentView"
|
||||||
|
permission="zope.ManageContent"
|
||||||
|
menu="zmi_views" title="Edit Document"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<page
|
<page
|
||||||
name="node.html"
|
name="node.html"
|
||||||
for="loops.interfaces.INode"
|
for="loops.interfaces.INode"
|
||||||
|
|
|
@ -26,7 +26,8 @@ from zope.cachedescriptors.property import Lazy
|
||||||
from zope.app import zapi
|
from zope.app import zapi
|
||||||
from zope.app.container.browser.contents import JustContents
|
from zope.app.container.browser.contents import JustContents
|
||||||
from zope.app.dublincore.interfaces import ICMFDublinCore
|
from zope.app.dublincore.interfaces import ICMFDublinCore
|
||||||
from zope.configuration.config import ConfigurationContext
|
#import zope.configuration.name
|
||||||
|
from zope.dottedname.resolve import resolve
|
||||||
from zope.proxy import removeAllProxies
|
from zope.proxy import removeAllProxies
|
||||||
from zope.security import canAccess, canWrite
|
from zope.security import canAccess, canWrite
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
|
@ -114,7 +115,7 @@ class ConfigureBaseView(object):
|
||||||
if form.get('field.createTarget', False):
|
if form.get('field.createTarget', False):
|
||||||
type = self.request.form.get('field.targetType',
|
type = self.request.form.get('field.targetType',
|
||||||
'loops.resource.MediaAsset')
|
'loops.resource.MediaAsset')
|
||||||
factory = ConfigurationContext().resolve(type)
|
factory = resolve(type)
|
||||||
uri = self.request.form.get('field.targetUri', None)
|
uri = self.request.form.get('field.targetUri', None)
|
||||||
if uri:
|
if uri:
|
||||||
path = uri.split('/')
|
path = uri.split('/')
|
||||||
|
|
|
@ -54,6 +54,8 @@ class Concept(Contained, Persistent):
|
||||||
|
|
||||||
implements(IConcept, IConceptManagerContained)
|
implements(IConcept, IConceptManagerContained)
|
||||||
|
|
||||||
|
proxyInterface = IConcept
|
||||||
|
|
||||||
_title = u''
|
_title = u''
|
||||||
def getTitle(self): return self._title
|
def getTitle(self): return self._title
|
||||||
def setTitle(self, title): self._title = title
|
def setTitle(self, title): self._title = title
|
||||||
|
|
|
@ -47,9 +47,18 @@ class ILoopsObject(Interface):
|
||||||
""" Return the (default) view manager.
|
""" Return the (default) view manager.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class IPotentialTarget(Interface):
|
||||||
|
""" For objects that may be used as target objects for view objects.
|
||||||
|
"""
|
||||||
|
|
||||||
|
proxyInterface = Attribute('An interface allowing an object to be '
|
||||||
|
'used as a target for a view/node (and '
|
||||||
|
'typically specifying the corresponding schema')
|
||||||
|
|
||||||
# concept interfaces
|
# concept interfaces
|
||||||
|
|
||||||
class IConcept(ILoopsObject):
|
class IConcept(ILoopsObject, IPotentialTarget):
|
||||||
""" The concept is the central element of the loops framework.
|
""" The concept is the central element of the loops framework.
|
||||||
|
|
||||||
A concept is related to other concepts, may have resources
|
A concept is related to other concepts, may have resources
|
||||||
|
@ -115,10 +124,7 @@ class IConceptManagerContained(Interface):
|
||||||
|
|
||||||
# resource interfaces
|
# resource interfaces
|
||||||
|
|
||||||
class IResource(ILoopsObject):
|
class IResourceSchema(Interface):
|
||||||
""" A resource is an atomic information element that is made
|
|
||||||
available via a view or a concept.
|
|
||||||
"""
|
|
||||||
|
|
||||||
title = schema.TextLine(
|
title = schema.TextLine(
|
||||||
title=_(u'Title'),
|
title=_(u'Title'),
|
||||||
|
@ -127,13 +133,6 @@ class IResource(ILoopsObject):
|
||||||
missing_value=u'',
|
missing_value=u'',
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
contentType = schema.BytesLine(
|
|
||||||
title=_(u'Content Type'),
|
|
||||||
description=_(u'Content type (format) of the data field'),
|
|
||||||
default='',
|
|
||||||
missing_value='',
|
|
||||||
required=False)
|
|
||||||
|
|
||||||
data = schema.Bytes(
|
data = schema.Bytes(
|
||||||
title=_(u'Data'),
|
title=_(u'Data'),
|
||||||
description=_(u'Resource raw data'),
|
description=_(u'Resource raw data'),
|
||||||
|
@ -141,15 +140,26 @@ class IResource(ILoopsObject):
|
||||||
missing_value='',
|
missing_value='',
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
contentType = schema.BytesLine(
|
||||||
|
title=_(u'Content Type'),
|
||||||
|
description=_(u'Content type (format) of the data field'),
|
||||||
|
default='',
|
||||||
|
missing_value='',
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
|
class IResource(ILoopsObject, IPotentialTarget):
|
||||||
|
""" A resource is an atomic information element that is made
|
||||||
|
available via a view or a concept.
|
||||||
|
"""
|
||||||
|
|
||||||
def getClients(relationships=None):
|
def getClients(relationships=None):
|
||||||
""" Return a sequence of objects that are clients of the resource,
|
""" Return a sequence of objects that are clients of the resource,
|
||||||
i.e. that have some relation with it.
|
i.e. that have some relation with it.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class IDocument(IResource):
|
class IDocumentSchema(IResourceSchema):
|
||||||
""" A resource containing an editable body.
|
|
||||||
"""
|
|
||||||
|
|
||||||
data = schema.Text(
|
data = schema.Text(
|
||||||
title=_(u'Data'),
|
title=_(u'Data'),
|
||||||
|
@ -159,11 +169,17 @@ class IDocument(IResource):
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
class IMediaAsset(IResource, IBaseAsset):
|
class IDocumentView(IDocumentSchema):
|
||||||
""" A resource containing a (typically binary) file-like content
|
""" Used for accessing a document via a node's target attribute"""
|
||||||
or an image.
|
|
||||||
|
|
||||||
|
class IDocument(IDocumentSchema, IResource):
|
||||||
|
""" A resource containing an editable body.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class IMediaAssetSchema(IResourceSchema):
|
||||||
|
|
||||||
data = schema.Bytes(
|
data = schema.Bytes(
|
||||||
title=_(u'Data'),
|
title=_(u'Data'),
|
||||||
description=_(u'Media asset file'),
|
description=_(u'Media asset file'),
|
||||||
|
@ -172,6 +188,16 @@ class IMediaAsset(IResource, IBaseAsset):
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
|
class IMediaAssetView(IMediaAssetSchema):
|
||||||
|
""" Used for accessing a media asset via a node's target attribute"""
|
||||||
|
|
||||||
|
|
||||||
|
class IMediaAsset(IMediaAssetSchema, IResource, IBaseAsset):
|
||||||
|
""" A resource containing a (typically binary) file-like content
|
||||||
|
or an image.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class IResourceManager(ILoopsObject, IContainer):
|
class IResourceManager(ILoopsObject, IContainer):
|
||||||
""" A manager/container for resources.
|
""" A manager/container for resources.
|
||||||
"""
|
"""
|
||||||
|
@ -203,6 +229,7 @@ class IView(ILoopsObject):
|
||||||
|
|
||||||
target = Attribute('Target object that is referenced by this view')
|
target = Attribute('Target object that is referenced by this view')
|
||||||
|
|
||||||
|
|
||||||
class IBaseNode(IOrderedContainer):
|
class IBaseNode(IOrderedContainer):
|
||||||
""" Common abstract base class for different types of nodes
|
""" Common abstract base class for different types of nodes
|
||||||
"""
|
"""
|
||||||
|
@ -323,4 +350,4 @@ class ILoops(ILoopsObject, IFolder):
|
||||||
class ILoopsContained(Interface):
|
class ILoopsContained(Interface):
|
||||||
containers(ILoops)
|
containers(ILoops)
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,9 @@ from persistent import Persistent
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
from cybertools.relation.registry import getRelations
|
from cybertools.relation.registry import getRelations
|
||||||
|
|
||||||
from interfaces import IResource, IDocument, IMediaAsset
|
from interfaces import IResource
|
||||||
|
from interfaces import IDocument, IDocumentSchema, IDocumentView
|
||||||
|
from interfaces import IMediaAsset, IMediaAssetSchema, IMediaAssetView
|
||||||
from interfaces import IResourceManager, IResourceManagerContained
|
from interfaces import IResourceManager, IResourceManagerContained
|
||||||
from interfaces import ILoopsContained
|
from interfaces import ILoopsContained
|
||||||
|
|
||||||
|
@ -72,6 +74,8 @@ class Document(Resource):
|
||||||
|
|
||||||
implements(IDocument)
|
implements(IDocument)
|
||||||
|
|
||||||
|
proxyInterface = IDocumentView
|
||||||
|
|
||||||
_data = u''
|
_data = u''
|
||||||
def setData(self, data): self._data = data
|
def setData(self, data): self._data = data
|
||||||
def getData(self): return self._data
|
def getData(self): return self._data
|
||||||
|
@ -82,6 +86,8 @@ class MediaAsset(Resource, BaseMediaAsset):
|
||||||
|
|
||||||
implements(IMediaAsset)
|
implements(IMediaAsset)
|
||||||
|
|
||||||
|
proxyInterface = IMediaAssetView
|
||||||
|
|
||||||
def __init__(self, title=u''):
|
def __init__(self, title=u''):
|
||||||
super(MediaAsset, self).__init__()
|
super(MediaAsset, self).__init__()
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
10
target.py
10
target.py
|
@ -29,7 +29,9 @@ from zope.component import adapts
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
|
|
||||||
from loops.interfaces import IResource, IDocument, IMediaAsset
|
from loops.interfaces import IResource
|
||||||
|
from loops.interfaces import IDocument, IMediaAsset
|
||||||
|
from loops.interfaces import IDocumentView, IMediaAssetView
|
||||||
from loops.interfaces import IView
|
from loops.interfaces import IView
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,8 +49,8 @@ class ResourceProxy(object):
|
||||||
contentType = property(getContentType, setContentType)
|
contentType = property(getContentType, setContentType)
|
||||||
|
|
||||||
def __init__(self, context):
|
def __init__(self, context):
|
||||||
self.context = context
|
#self.context = context
|
||||||
#self.context = removeSecurityProxy(context)
|
self.context = removeSecurityProxy(context)
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def target(self):
|
def target(self):
|
||||||
|
@ -58,6 +60,7 @@ class ResourceProxy(object):
|
||||||
class DocumentProxy(ResourceProxy):
|
class DocumentProxy(ResourceProxy):
|
||||||
|
|
||||||
implements(IDocument)
|
implements(IDocument)
|
||||||
|
adapts(IDocumentView)
|
||||||
|
|
||||||
def setData(self, data): self.target.data = data
|
def setData(self, data): self.target.data = data
|
||||||
def getData(self): return self.target.data
|
def getData(self): return self.target.data
|
||||||
|
@ -67,6 +70,7 @@ class DocumentProxy(ResourceProxy):
|
||||||
class MediaAssetProxy(ResourceProxy):
|
class MediaAssetProxy(ResourceProxy):
|
||||||
|
|
||||||
implements(IMediaAsset)
|
implements(IMediaAsset)
|
||||||
|
adapts(IMediaAssetView)
|
||||||
|
|
||||||
def setData(self, data): self.target.data = data
|
def setData(self, data): self.target.data = data
|
||||||
def getData(self): return self.target.data
|
def getData(self): return self.target.data
|
||||||
|
|
14
view.py
14
view.py
|
@ -28,9 +28,10 @@ from zope.app.container.contained import Contained
|
||||||
from zope.app.container.ordered import OrderedContainer
|
from zope.app.container.ordered import OrderedContainer
|
||||||
from zope.app.container.traversal import ContainerTraverser, ItemTraverser
|
from zope.app.container.traversal import ContainerTraverser, ItemTraverser
|
||||||
from zope.app.container.traversal import ContainerTraversable
|
from zope.app.container.traversal import ContainerTraversable
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy, readproperty
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
|
from zope.interface import alsoProvides, directlyProvides, directlyProvidedBy
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
from persistent import Persistent
|
from persistent import Persistent
|
||||||
from cybertools.relation import DyadicRelation
|
from cybertools.relation import DyadicRelation
|
||||||
|
@ -73,9 +74,14 @@ class View(object):
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
registry.unregister(oldRel)
|
registry.unregister(oldRel)
|
||||||
|
oldTargetSchema = oldRel.second.proxyInterface
|
||||||
|
directlyProvides(self, directlyProvidedBy(self) - oldTargetSchema)
|
||||||
|
|
||||||
if target:
|
if target:
|
||||||
|
targetSchema = target.proxyInterface
|
||||||
rel = TargetRelation(self, target)
|
rel = TargetRelation(self, target)
|
||||||
registry.register(rel)
|
registry.register(rel)
|
||||||
|
alsoProvides(self, targetSchema)
|
||||||
|
|
||||||
target = property(getTarget, setTarget)
|
target = property(getTarget, setTarget)
|
||||||
|
|
||||||
|
@ -194,7 +200,7 @@ class NodeConfigAdapter(object):
|
||||||
@Lazy
|
@Lazy
|
||||||
def loopsRoot(self): return self.context.getLoopsRoot()
|
def loopsRoot(self): return self.context.getLoopsRoot()
|
||||||
|
|
||||||
@Lazy
|
@readproperty
|
||||||
def target(self):
|
def target(self):
|
||||||
return self.context.target
|
return self.context.target
|
||||||
|
|
||||||
|
@ -225,5 +231,7 @@ class NodeConfigAdapter(object):
|
||||||
pass # only used whe a new target object is created
|
pass # only used whe a new target object is created
|
||||||
targetType = property(getTargetType, setTargetType)
|
targetType = property(getTargetType, setTargetType)
|
||||||
|
|
||||||
createTarget = False # not used
|
def getCreateTarget(self): return False
|
||||||
|
def setCreateTarget(self, value): pass
|
||||||
|
createTarget = property(getCreateTarget, setCreateTarget)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue