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
|
||||
u'New title for m111'
|
||||
>>> 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
|
||||
True
|
||||
>>> 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)
|
||||
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:
|
||||
|
||||
>>> from loops.target import DocumentProxy, MediaAssetProxy
|
||||
>>> ztapi.provideAdapter(INode, IDocument, DocumentProxy)
|
||||
>>> ztapi.provideAdapter(INode, IMediaAsset, MediaAssetProxy)
|
||||
>>> ztapi.provideAdapter(INode, IDocumentView, DocumentProxy)
|
||||
>>> ztapi.provideAdapter(INode, IMediaAssetView, MediaAssetProxy)
|
||||
|
||||
>>> proxy = zapi.getAdapter(m111, IDocument)
|
||||
>>> proxy = zapi.getAdapter(m111, IDocumentView)
|
||||
>>> proxy.title = u'Set via proxy'
|
||||
>>> resources['m1.m11.m111'].title
|
||||
>>> resources['ma07'].title
|
||||
u'Set via proxy'
|
||||
|
||||
Ordering Nodes
|
||||
|
|
|
@ -167,7 +167,7 @@
|
|||
<addform
|
||||
label="Add Document"
|
||||
name="AddLoopsDocument.html"
|
||||
schema="loops.interfaces.IDocument"
|
||||
schema="loops.interfaces.IDocumentSchema"
|
||||
fields="title data contentType"
|
||||
content_factory="loops.resource.Document"
|
||||
permission="zope.ManageContent" />
|
||||
|
@ -184,7 +184,7 @@
|
|||
<editform
|
||||
label="Edit Document"
|
||||
name="edit.html"
|
||||
schema="loops.interfaces.IDocument"
|
||||
schema="loops.interfaces.IDocumentSchema"
|
||||
fields="title data contentType"
|
||||
for="loops.interfaces.IDocument"
|
||||
permission="zope.ManageContent"
|
||||
|
@ -195,7 +195,7 @@
|
|||
<addform
|
||||
label="Add Media Asset"
|
||||
name="AddLoopsMediaAsset.html"
|
||||
schema="loops.interfaces.IMediaAsset"
|
||||
schema="loops.interfaces.IMediaAssetSchema"
|
||||
fields="title data contentType"
|
||||
content_factory="loops.resource.MediaAsset"
|
||||
permission="zope.ManageContent"
|
||||
|
@ -212,11 +212,11 @@
|
|||
<editform
|
||||
label="Edit Media Asset"
|
||||
name="edit.html"
|
||||
schema="loops.interfaces.IMediaAsset"
|
||||
schema="loops.interfaces.IMediaAssetSchema"
|
||||
fields="title data contentType"
|
||||
for="loops.interfaces.IMediaAsset"
|
||||
permission="zope.ManageContent"
|
||||
menu="zmi_views" title="Edit"
|
||||
menu="zmi_views" title="Edit Media Asset"
|
||||
/>
|
||||
|
||||
<!-- suppress the upload menu item: -->
|
||||
|
@ -271,8 +271,8 @@
|
|||
label="Add Node"
|
||||
name="AddLoopsNode.html"
|
||||
content_factory="loops.view.Node"
|
||||
schema="loops.interfaces.INodeConfigSchema"
|
||||
fields="title description nodeType targetType targetUri createTarget"
|
||||
schema="loops.interfaces.INode"
|
||||
fields="title description nodeType body"
|
||||
class="loops.browser.node.ConfigureView"
|
||||
permission="zope.ManageContent">
|
||||
|
||||
|
@ -327,20 +327,25 @@
|
|||
</editform>
|
||||
|
||||
<editform
|
||||
label="Edit Target"
|
||||
label="Edit Media Asset"
|
||||
name="edit_target.html"
|
||||
schema="loops.interfaces.IMediaAsset"
|
||||
fields="title data contentType"
|
||||
for="loops.interfaces.INode"
|
||||
for="loops.interfaces.IMediaAssetView"
|
||||
permission="zope.ManageContent"
|
||||
menu="zmi_views" title="Edit Media Asset"
|
||||
/>
|
||||
|
||||
<menuItem
|
||||
for="loops.interfaces.INode"
|
||||
menu="zmi_views" action="edit_target.html" title="Edit Target"
|
||||
filter="context/target"
|
||||
<editform
|
||||
label="Edit Document"
|
||||
name="edit_target.html"
|
||||
schema="loops.interfaces.IDocument"
|
||||
fields="title data contentType"
|
||||
for="loops.interfaces.IDocumentView"
|
||||
permission="zope.ManageContent"
|
||||
menu="zmi_views" title="Edit Document"
|
||||
/>
|
||||
|
||||
|
||||
<page
|
||||
name="node.html"
|
||||
for="loops.interfaces.INode"
|
||||
|
|
|
@ -26,7 +26,8 @@ from zope.cachedescriptors.property import Lazy
|
|||
from zope.app import zapi
|
||||
from zope.app.container.browser.contents import JustContents
|
||||
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.security import canAccess, canWrite
|
||||
from zope.security.proxy import removeSecurityProxy
|
||||
|
@ -114,7 +115,7 @@ class ConfigureBaseView(object):
|
|||
if form.get('field.createTarget', False):
|
||||
type = self.request.form.get('field.targetType',
|
||||
'loops.resource.MediaAsset')
|
||||
factory = ConfigurationContext().resolve(type)
|
||||
factory = resolve(type)
|
||||
uri = self.request.form.get('field.targetUri', None)
|
||||
if uri:
|
||||
path = uri.split('/')
|
||||
|
|
|
@ -54,6 +54,8 @@ class Concept(Contained, Persistent):
|
|||
|
||||
implements(IConcept, IConceptManagerContained)
|
||||
|
||||
proxyInterface = IConcept
|
||||
|
||||
_title = u''
|
||||
def getTitle(self): return self._title
|
||||
def setTitle(self, title): self._title = title
|
||||
|
|
|
@ -47,9 +47,18 @@ class ILoopsObject(Interface):
|
|||
""" 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
|
||||
|
||||
class IConcept(ILoopsObject):
|
||||
class IConcept(ILoopsObject, IPotentialTarget):
|
||||
""" The concept is the central element of the loops framework.
|
||||
|
||||
A concept is related to other concepts, may have resources
|
||||
|
@ -115,10 +124,7 @@ class IConceptManagerContained(Interface):
|
|||
|
||||
# resource interfaces
|
||||
|
||||
class IResource(ILoopsObject):
|
||||
""" A resource is an atomic information element that is made
|
||||
available via a view or a concept.
|
||||
"""
|
||||
class IResourceSchema(Interface):
|
||||
|
||||
title = schema.TextLine(
|
||||
title=_(u'Title'),
|
||||
|
@ -127,13 +133,6 @@ class IResource(ILoopsObject):
|
|||
missing_value=u'',
|
||||
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(
|
||||
title=_(u'Data'),
|
||||
description=_(u'Resource raw data'),
|
||||
|
@ -141,15 +140,26 @@ class IResource(ILoopsObject):
|
|||
missing_value='',
|
||||
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):
|
||||
""" Return a sequence of objects that are clients of the resource,
|
||||
i.e. that have some relation with it.
|
||||
"""
|
||||
|
||||
|
||||
class IDocument(IResource):
|
||||
""" A resource containing an editable body.
|
||||
"""
|
||||
class IDocumentSchema(IResourceSchema):
|
||||
|
||||
data = schema.Text(
|
||||
title=_(u'Data'),
|
||||
|
@ -159,11 +169,17 @@ class IDocument(IResource):
|
|||
required=False)
|
||||
|
||||
|
||||
class IMediaAsset(IResource, IBaseAsset):
|
||||
""" A resource containing a (typically binary) file-like content
|
||||
or an image.
|
||||
class IDocumentView(IDocumentSchema):
|
||||
""" Used for accessing a document via a node's target attribute"""
|
||||
|
||||
|
||||
class IDocument(IDocumentSchema, IResource):
|
||||
""" A resource containing an editable body.
|
||||
"""
|
||||
|
||||
|
||||
class IMediaAssetSchema(IResourceSchema):
|
||||
|
||||
data = schema.Bytes(
|
||||
title=_(u'Data'),
|
||||
description=_(u'Media asset file'),
|
||||
|
@ -172,6 +188,16 @@ class IMediaAsset(IResource, IBaseAsset):
|
|||
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):
|
||||
""" A manager/container for resources.
|
||||
"""
|
||||
|
@ -203,6 +229,7 @@ class IView(ILoopsObject):
|
|||
|
||||
target = Attribute('Target object that is referenced by this view')
|
||||
|
||||
|
||||
class IBaseNode(IOrderedContainer):
|
||||
""" Common abstract base class for different types of nodes
|
||||
"""
|
||||
|
@ -323,4 +350,4 @@ class ILoops(ILoopsObject, IFolder):
|
|||
class ILoopsContained(Interface):
|
||||
containers(ILoops)
|
||||
|
||||
|
||||
|
|
@ -31,7 +31,9 @@ from persistent import Persistent
|
|||
from cStringIO import StringIO
|
||||
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 ILoopsContained
|
||||
|
||||
|
@ -72,6 +74,8 @@ class Document(Resource):
|
|||
|
||||
implements(IDocument)
|
||||
|
||||
proxyInterface = IDocumentView
|
||||
|
||||
_data = u''
|
||||
def setData(self, data): self._data = data
|
||||
def getData(self): return self._data
|
||||
|
@ -82,6 +86,8 @@ class MediaAsset(Resource, BaseMediaAsset):
|
|||
|
||||
implements(IMediaAsset)
|
||||
|
||||
proxyInterface = IMediaAssetView
|
||||
|
||||
def __init__(self, title=u''):
|
||||
super(MediaAsset, self).__init__()
|
||||
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.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
|
||||
|
||||
|
||||
|
@ -47,8 +49,8 @@ class ResourceProxy(object):
|
|||
contentType = property(getContentType, setContentType)
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
#self.context = removeSecurityProxy(context)
|
||||
#self.context = context
|
||||
self.context = removeSecurityProxy(context)
|
||||
|
||||
@Lazy
|
||||
def target(self):
|
||||
|
@ -58,6 +60,7 @@ class ResourceProxy(object):
|
|||
class DocumentProxy(ResourceProxy):
|
||||
|
||||
implements(IDocument)
|
||||
adapts(IDocumentView)
|
||||
|
||||
def setData(self, data): self.target.data = data
|
||||
def getData(self): return self.target.data
|
||||
|
@ -67,6 +70,7 @@ class DocumentProxy(ResourceProxy):
|
|||
class MediaAssetProxy(ResourceProxy):
|
||||
|
||||
implements(IMediaAsset)
|
||||
adapts(IMediaAssetView)
|
||||
|
||||
def setData(self, data): self.target.data = 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.traversal import ContainerTraverser, ItemTraverser
|
||||
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.interface import implements
|
||||
from zope.interface import alsoProvides, directlyProvides, directlyProvidedBy
|
||||
from zope.security.proxy import removeSecurityProxy
|
||||
from persistent import Persistent
|
||||
from cybertools.relation import DyadicRelation
|
||||
|
@ -73,9 +74,14 @@ class View(object):
|
|||
return
|
||||
else:
|
||||
registry.unregister(oldRel)
|
||||
oldTargetSchema = oldRel.second.proxyInterface
|
||||
directlyProvides(self, directlyProvidedBy(self) - oldTargetSchema)
|
||||
|
||||
if target:
|
||||
targetSchema = target.proxyInterface
|
||||
rel = TargetRelation(self, target)
|
||||
registry.register(rel)
|
||||
alsoProvides(self, targetSchema)
|
||||
|
||||
target = property(getTarget, setTarget)
|
||||
|
||||
|
@ -194,7 +200,7 @@ class NodeConfigAdapter(object):
|
|||
@Lazy
|
||||
def loopsRoot(self): return self.context.getLoopsRoot()
|
||||
|
||||
@Lazy
|
||||
@readproperty
|
||||
def target(self):
|
||||
return self.context.target
|
||||
|
||||
|
@ -225,5 +231,7 @@ class NodeConfigAdapter(object):
|
|||
pass # only used whe a new target object is created
|
||||
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