Added basic support for media assets; use '.loops' as traversal anchor to the loops root object for referencing resources
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1019 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
a7a06201c0
commit
921bbcf92d
7 changed files with 179 additions and 59 deletions
60
README.txt
60
README.txt
|
@ -26,14 +26,14 @@ top-level loops container and a concept manager:
|
||||||
>>> from loops.concept import ConceptManager, Concept
|
>>> from loops.concept import ConceptManager, Concept
|
||||||
>>> loops['concepts'] = ConceptManager()
|
>>> loops['concepts'] = ConceptManager()
|
||||||
>>> concepts = loops['concepts']
|
>>> concepts = loops['concepts']
|
||||||
>>> zope = Concept()
|
>>> cc1 = Concept()
|
||||||
>>> concepts['zope'] = zope
|
>>> concepts['cc1'] = cc1
|
||||||
>>> zope.title
|
>>> cc1.title
|
||||||
u''
|
u''
|
||||||
|
|
||||||
>>> zope3 = Concept(u'Zope 3')
|
>>> cc2 = Concept(u'Zope 3')
|
||||||
>>> concepts['zope3'] = zope3
|
>>> concepts['cc2'] = cc2
|
||||||
>>> zope3.title
|
>>> cc2.title
|
||||||
u'Zope 3'
|
u'Zope 3'
|
||||||
|
|
||||||
Now we want to relate the second concept to the first one.
|
Now we want to relate the second concept to the first one.
|
||||||
|
@ -48,25 +48,25 @@ testing we use a simple dummy implementation.
|
||||||
|
|
||||||
Now we can assign the concept c2 to c1 (using the standard ConceptRelation):
|
Now we can assign the concept c2 to c1 (using the standard ConceptRelation):
|
||||||
|
|
||||||
>>> zope.assignConcept(zope3)
|
>>> cc1.assignConcept(cc2)
|
||||||
|
|
||||||
We can now ask our concepts for their related concepts:
|
We can now ask our concepts for their related concepts:
|
||||||
|
|
||||||
>>> sc1 = zope.getSubConcepts()
|
>>> sc1 = cc1.getSubConcepts()
|
||||||
>>> len(sc1)
|
>>> len(sc1)
|
||||||
1
|
1
|
||||||
>>> zope3 in sc1
|
>>> cc2 in sc1
|
||||||
True
|
True
|
||||||
>>> len(zope.getParentConcepts())
|
>>> len(cc1.getParentConcepts())
|
||||||
0
|
0
|
||||||
|
|
||||||
>>> pc2 = zope3.getParentConcepts()
|
>>> pc2 = cc2.getParentConcepts()
|
||||||
>>> len(pc2)
|
>>> len(pc2)
|
||||||
1
|
1
|
||||||
|
|
||||||
>>> zope in pc2
|
>>> cc1 in pc2
|
||||||
True
|
True
|
||||||
>>> len(zope3.getSubConcepts())
|
>>> len(cc2.getSubConcepts())
|
||||||
0
|
0
|
||||||
|
|
||||||
TODO: Work with views...
|
TODO: Work with views...
|
||||||
|
@ -81,31 +81,33 @@ We first need a resource manager:
|
||||||
>>> loops['resources'] = ResourceManager()
|
>>> loops['resources'] = ResourceManager()
|
||||||
>>> resources = loops['resources']
|
>>> resources = loops['resources']
|
||||||
|
|
||||||
A common type of resource is a Document:
|
A common type of resource is a document:
|
||||||
|
|
||||||
>>> zope_info = Document(u'Zope Info')
|
>>> doc1 = Document(u'Zope Info')
|
||||||
>>> resources['zope_info'] = zope_info
|
>>> resources['doc1'] = doc1
|
||||||
>>> zope_info.title
|
>>> doc1.title
|
||||||
u'Zope Info'
|
u'Zope Info'
|
||||||
>>> zope_info.body
|
>>> doc1.data
|
||||||
u''
|
u''
|
||||||
>>> zope_info.format
|
>>> doc1.contentType
|
||||||
u'text/xml'
|
u'text/xml'
|
||||||
|
|
||||||
|
Another one is a media asset:
|
||||||
|
|
||||||
We can associate a resource with a concept by assigning it to the concept:
|
We can associate a resource with a concept by assigning it to the concept:
|
||||||
|
|
||||||
>>> zope.assignResource(zope_info)
|
>>> cc1.assignResource(doc1)
|
||||||
>>> res = zope.getResources()
|
>>> res = cc1.getResources()
|
||||||
>>> list(res)
|
>>> list(res)
|
||||||
[<loops.resource.Document ...>]
|
[<loops.resource.Document ...>]
|
||||||
|
|
||||||
The resource also provides access to the associated concepts (or views, see
|
The resource also provides access to the associated concepts (or views, see
|
||||||
below) via the getClients() method:
|
below) via the getClients() method:
|
||||||
|
|
||||||
>>> conc = zope_info.getClients()
|
>>> conc = doc1.getClients()
|
||||||
>>> len(conc)
|
>>> len(conc)
|
||||||
1
|
1
|
||||||
>>> conc[0] is zope
|
>>> conc[0] is cc1
|
||||||
True
|
True
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,14 +202,14 @@ Targets
|
||||||
We can associate a node with a concept or directly with a resource via the
|
We can associate a node with a concept or directly with a resource via the
|
||||||
view class's target attribute:
|
view class's target attribute:
|
||||||
|
|
||||||
>>> m111.target = zope_info
|
>>> m111.target = cc1
|
||||||
>>> m111.target is zope_info
|
>>> m111.target is cc1
|
||||||
True
|
True
|
||||||
>>> m111.target = zope_info
|
>>> m111.target = cc1
|
||||||
>>> m111.target is zope_info
|
>>> m111.target is cc1
|
||||||
True
|
True
|
||||||
>>> m111.target = zope3
|
>>> m111.target = cc2
|
||||||
>>> m111.target is zope3
|
>>> m111.target is cc2
|
||||||
True
|
True
|
||||||
|
|
||||||
Node views
|
Node views
|
||||||
|
|
|
@ -159,7 +159,7 @@
|
||||||
label="Add Document"
|
label="Add Document"
|
||||||
name="AddLoopsDocument.html"
|
name="AddLoopsDocument.html"
|
||||||
schema="loops.interfaces.IDocument"
|
schema="loops.interfaces.IDocument"
|
||||||
fields="title body format"
|
fields="title data contentType"
|
||||||
content_factory="loops.resource.Document"
|
content_factory="loops.resource.Document"
|
||||||
permission="zope.ManageContent"
|
permission="zope.ManageContent"
|
||||||
/>
|
/>
|
||||||
|
@ -176,12 +176,41 @@
|
||||||
label="Edit Document"
|
label="Edit Document"
|
||||||
name="edit.html"
|
name="edit.html"
|
||||||
schema="loops.interfaces.IDocument"
|
schema="loops.interfaces.IDocument"
|
||||||
fields="title body format"
|
fields="title data contentType"
|
||||||
for="loops.interfaces.IDocument"
|
for="loops.interfaces.IDocument"
|
||||||
permission="zope.ManageContent"
|
permission="zope.ManageContent"
|
||||||
menu="zmi_views" title="Edit"
|
menu="zmi_views" title="Edit"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- media asset -->
|
||||||
|
|
||||||
|
<addform
|
||||||
|
label="Add Media Asset"
|
||||||
|
name="AddLoopsMediaAsset.html"
|
||||||
|
schema="loops.interfaces.IMediaAsset"
|
||||||
|
fields="title data contentType"
|
||||||
|
content_factory="loops.resource.MediaAsset"
|
||||||
|
permission="zope.ManageContent"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<addMenuItem
|
||||||
|
class="loops.resource.MediaAsset"
|
||||||
|
title="Media Asset"
|
||||||
|
description="A media asset is a binary file, image, video or audio file"
|
||||||
|
permission="zope.ManageContent"
|
||||||
|
view="AddLoopsMediaAsset.html"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<editform
|
||||||
|
label="Edit Media Asset"
|
||||||
|
name="edit.html"
|
||||||
|
schema="loops.interfaces.IMediaAsset"
|
||||||
|
fields="title data contentType"
|
||||||
|
for="loops.interfaces.IMediaAsset"
|
||||||
|
permission="zope.ManageContent"
|
||||||
|
menu="zmi_views" title="Edit"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- view manager -->
|
<!-- view manager -->
|
||||||
|
|
||||||
<addform
|
<addform
|
||||||
|
|
|
@ -129,6 +129,29 @@
|
||||||
|
|
||||||
</content>
|
</content>
|
||||||
|
|
||||||
|
<interface
|
||||||
|
interface=".interfaces.IMediaAsset"
|
||||||
|
type="zope.app.content.interfaces.IContentType" />
|
||||||
|
|
||||||
|
<content class=".resource.MediaAsset">
|
||||||
|
|
||||||
|
<implements
|
||||||
|
interface="zope.app.annotation.interfaces.IAttributeAnnotatable" />
|
||||||
|
|
||||||
|
<factory
|
||||||
|
id="loops.MediaAsset"
|
||||||
|
description="Media Asset" />
|
||||||
|
|
||||||
|
<require
|
||||||
|
permission="zope.View"
|
||||||
|
interface=".interfaces.IMediaAsset" />
|
||||||
|
|
||||||
|
<require
|
||||||
|
permission="zope.ManageContent"
|
||||||
|
set_schema=".interfaces.IMediaAsset" />
|
||||||
|
|
||||||
|
</content>
|
||||||
|
|
||||||
<!-- view manager and view -->
|
<!-- view manager and view -->
|
||||||
|
|
||||||
<interface interface=".interfaces.IViewManager"
|
<interface interface=".interfaces.IViewManager"
|
||||||
|
@ -188,6 +211,17 @@
|
||||||
|
|
||||||
<adapter factory="loops.external.NodesImporter" />
|
<adapter factory="loops.external.NodesImporter" />
|
||||||
|
|
||||||
|
<!-- traversal adapter -->
|
||||||
|
|
||||||
|
<view factory="loops.view.NodeTraverser"
|
||||||
|
for="loops.interfaces.INode"
|
||||||
|
type="zope.publisher.interfaces.http.IHTTPRequest"
|
||||||
|
provides="zope.publisher.interfaces.IPublishTraverse"
|
||||||
|
allowed_interface="zope.publisher.interfaces.IPublishTraverse"
|
||||||
|
permission="zope.Public" />
|
||||||
|
|
||||||
|
<!--<adapter factory="loops.view.NodeTraversable" />-->
|
||||||
|
|
||||||
<!-- Register various browser related components, including all views -->
|
<!-- Register various browser related components, including all views -->
|
||||||
<include package=".browser" />
|
<include package=".browser" />
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ from zope.i18nmessageid import MessageFactory
|
||||||
from zope import schema
|
from zope import schema
|
||||||
from zope.app.container.constraints import contains, containers
|
from zope.app.container.constraints import contains, containers
|
||||||
from zope.app.container.interfaces import IContainer, IOrderedContainer
|
from zope.app.container.interfaces import IContainer, IOrderedContainer
|
||||||
from zope.app.file.interfaces import IFile as IBaseFile
|
from zope.app.file.interfaces import IImage as IBaseAsset
|
||||||
from zope.app.folder.interfaces import IFolder
|
from zope.app.folder.interfaces import IFolder
|
||||||
|
|
||||||
_ = MessageFactory('loops')
|
_ = MessageFactory('loops')
|
||||||
|
@ -102,8 +102,8 @@ class IConceptManagerContained(Interface):
|
||||||
# resource interfaces
|
# resource interfaces
|
||||||
|
|
||||||
class IResource(Interface):
|
class IResource(Interface):
|
||||||
""" A resource is an atomic information element that is usually
|
""" A resource is an atomic information element that is made
|
||||||
available via a concept.
|
available via a view or a concept.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
title = schema.TextLine(
|
title = schema.TextLine(
|
||||||
|
@ -111,6 +111,13 @@ class IResource(Interface):
|
||||||
description=_(u'Title of the document'),
|
description=_(u'Title of the document'),
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
contentType = schema.TextLine(
|
||||||
|
title=_(u'Content Type'),
|
||||||
|
description=_(u'Content type (format) of the body field, '
|
||||||
|
'default is "text/xml"'),
|
||||||
|
default=_(u'text/xml'),
|
||||||
|
required=False)
|
||||||
|
|
||||||
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.
|
||||||
|
@ -121,23 +128,22 @@ class IDocument(IResource):
|
||||||
""" A resource containing an editable body.
|
""" A resource containing an editable body.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
body = schema.Text(
|
data = schema.Text(
|
||||||
title=_(u'Body'),
|
title=_(u'Data'),
|
||||||
description=_(u'Body of the document'),
|
description=_(u'Raw body data of the document'),
|
||||||
required=False)
|
|
||||||
|
|
||||||
format = schema.TextLine(
|
|
||||||
title=_(u'Format'),
|
|
||||||
description=_(u'Format of the body field, default is "text/xml"'),
|
|
||||||
default=_(u'text/xml'),
|
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
class IFile(IResource, IBaseFile):
|
class IMediaAsset(IResource, IBaseAsset):
|
||||||
""" A resource containing a (typically binary) file-like content
|
""" A resource containing a (typically binary) file-like content
|
||||||
or an image.
|
or an image.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
data = schema.Bytes(
|
||||||
|
title=_(u'Data'),
|
||||||
|
description=_(u'Media asset raw data'),
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
class IResourceManager(IContainer):
|
class IResourceManager(IContainer):
|
||||||
""" A manager/container for resources.
|
""" A manager/container for resources.
|
||||||
|
@ -173,6 +179,10 @@ class IView(Interface):
|
||||||
class IBaseNode(IOrderedContainer):
|
class IBaseNode(IOrderedContainer):
|
||||||
""" Common abstract base class for different types of nodes
|
""" Common abstract base class for different types of nodes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def getLoopsRoot():
|
||||||
|
""" Return the loops root object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class INode(IView, IBaseNode):
|
class INode(IView, IBaseNode):
|
||||||
|
|
34
resource.py
34
resource.py
|
@ -25,11 +25,12 @@ $Id$
|
||||||
from zope.app import zapi
|
from zope.app import zapi
|
||||||
from zope.app.container.btree import BTreeContainer
|
from zope.app.container.btree import BTreeContainer
|
||||||
from zope.app.container.contained import Contained
|
from zope.app.container.contained import Contained
|
||||||
|
from zope.app.file.image import Image as BaseMediaAsset
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from persistent import Persistent
|
from persistent import Persistent
|
||||||
from cybertools.relation.registry import getRelations
|
from cybertools.relation.registry import getRelations
|
||||||
|
|
||||||
from interfaces import IResource, IDocument
|
from interfaces import IResource, IDocument, IMediaAsset
|
||||||
from interfaces import IResourceManager, IResourceManagerContained
|
from interfaces import IResourceManager, IResourceManagerContained
|
||||||
from interfaces import ILoopsContained
|
from interfaces import ILoopsContained
|
||||||
|
|
||||||
|
@ -43,27 +44,36 @@ class Resource(Contained, Persistent):
|
||||||
def setTitle(self, title): self._title = title
|
def setTitle(self, title): self._title = title
|
||||||
title = property(getTitle, setTitle)
|
title = property(getTitle, setTitle)
|
||||||
|
|
||||||
def __init__(self, title=u''):
|
_contentType = u'text/xml'
|
||||||
self.title = title
|
def setContentType(self, contentType): self._contentType = contentType
|
||||||
|
def getContentType(self): return self._contentType
|
||||||
|
contentType = property(getContentType, setContentType)
|
||||||
|
|
||||||
|
_data = u''
|
||||||
|
def setData(self, data): self._data = data
|
||||||
|
def getData(self): return self._data
|
||||||
|
data = property(getData, setData)
|
||||||
|
|
||||||
def getClients(self, relationships=None):
|
def getClients(self, relationships=None):
|
||||||
rels = getRelations(second=self, relationships=relationships)
|
rels = getRelations(second=self, relationships=relationships)
|
||||||
return [r.first for r in rels]
|
return [r.first for r in rels]
|
||||||
|
|
||||||
|
def __init__(self, title=u''):
|
||||||
|
self.title = title
|
||||||
|
|
||||||
|
|
||||||
class Document(Resource):
|
class Document(Resource):
|
||||||
|
|
||||||
implements(IDocument)
|
implements(IDocument)
|
||||||
|
|
||||||
_body = u''
|
|
||||||
def setBody(self, body): self._body = body
|
|
||||||
def getBody(self): return self._body
|
|
||||||
body = property(getBody, setBody)
|
|
||||||
|
|
||||||
_format = u'text/xml'
|
|
||||||
def setFormat(self, format): self._format = format
|
class MediaAsset(Resource, BaseMediaAsset):
|
||||||
def getFormat(self): return self._format
|
|
||||||
format = property(getFormat, setFormat)
|
implements(IMediaAsset)
|
||||||
|
|
||||||
|
def __init__(self, title=u''):
|
||||||
|
super(MediaAsset, self).__init__()
|
||||||
|
self.title = title
|
||||||
|
|
||||||
|
|
||||||
class ResourceManager(BTreeContainer):
|
class ResourceManager(BTreeContainer):
|
||||||
|
|
7
tests.py
7
tests.py
|
@ -10,10 +10,11 @@ from zope.app.intid.interfaces import IIntIds
|
||||||
|
|
||||||
from interfaces import ILoops
|
from interfaces import ILoops
|
||||||
from loops import Loops
|
from loops import Loops
|
||||||
from interfaces import IConcept, IConceptManager, IDocument, IResourceManager
|
from interfaces import IConcept, IConceptManager
|
||||||
|
from interfaces import IDocument, IMediaAsset, IResourceManager
|
||||||
from interfaces import INode, IViewManager
|
from interfaces import INode, IViewManager
|
||||||
from loops.concept import Concept, ConceptManager
|
from loops.concept import Concept, ConceptManager
|
||||||
from loops.resource import Document, ResourceManager
|
from loops.resource import Document, MediaAsset, ResourceManager
|
||||||
from loops.view import Node, ViewManager
|
from loops.view import Node, ViewManager
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
|
@ -28,6 +29,8 @@ class Test(unittest.TestCase):
|
||||||
self.assert_(IConceptManager.providedBy(ConceptManager()))
|
self.assert_(IConceptManager.providedBy(ConceptManager()))
|
||||||
verifyClass(IDocument, Document)
|
verifyClass(IDocument, Document)
|
||||||
self.assert_(IDocument.providedBy(Document()))
|
self.assert_(IDocument.providedBy(Document()))
|
||||||
|
verifyClass(IMediaAsset, MediaAsset)
|
||||||
|
self.assert_(IMediaAsset.providedBy(MediaAsset()))
|
||||||
verifyClass(IResourceManager, ResourceManager)
|
verifyClass(IResourceManager, ResourceManager)
|
||||||
self.assert_(IResourceManager.providedBy(ResourceManager()))
|
self.assert_(IResourceManager.providedBy(ResourceManager()))
|
||||||
verifyClass(INode, Node)
|
verifyClass(INode, Node)
|
||||||
|
|
32
view.py
32
view.py
|
@ -26,6 +26,9 @@ from zope.app import zapi
|
||||||
from zope.app.container.btree import BTreeContainer
|
from zope.app.container.btree import BTreeContainer
|
||||||
from zope.app.container.contained import Contained
|
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 ContainerTraversable
|
||||||
|
from zope.component import adapts
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from persistent import Persistent
|
from persistent import Persistent
|
||||||
from cybertools.relation import DyadicRelation
|
from cybertools.relation import DyadicRelation
|
||||||
|
@ -95,6 +98,9 @@ class Node(View, OrderedContainer):
|
||||||
|
|
||||||
contentType = u'zope.source.rest'
|
contentType = u'zope.source.rest'
|
||||||
|
|
||||||
|
def getLoopsRoot(self):
|
||||||
|
return zapi.getParent(self).getLoopsRoot()
|
||||||
|
|
||||||
def getParentNode(self, nodeTypes=None):
|
def getParentNode(self, nodeTypes=None):
|
||||||
parent = zapi.getParent(self)
|
parent = zapi.getParent(self)
|
||||||
while INode.providedBy(parent):
|
while INode.providedBy(parent):
|
||||||
|
@ -134,8 +140,34 @@ class ViewManager(OrderedContainer):
|
||||||
|
|
||||||
implements(IViewManager, ILoopsContained)
|
implements(IViewManager, ILoopsContained)
|
||||||
|
|
||||||
|
def getLoopsRoot(self):
|
||||||
|
return zapi.getParent(self)
|
||||||
|
|
||||||
|
|
||||||
class TargetRelation(DyadicRelation):
|
class TargetRelation(DyadicRelation):
|
||||||
""" A relation between a view and another object.
|
""" A relation between a view and another object.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class NodeTraverser(ItemTraverser):
|
||||||
|
|
||||||
|
adapts(INode)
|
||||||
|
|
||||||
|
def publishTraverse(self, request, name):
|
||||||
|
print name
|
||||||
|
if name == '.loops':
|
||||||
|
return self.context.getLoopsRoot()
|
||||||
|
return super(NodeTraverser, self).publishTraverse(request, name)
|
||||||
|
|
||||||
|
|
||||||
|
# class NodeTraversable(ContainerTraversable):
|
||||||
|
#
|
||||||
|
# adapts(INode)
|
||||||
|
#
|
||||||
|
# def traverse(self, name, furtherPath):
|
||||||
|
# print name
|
||||||
|
# if str(name) == '.loops':
|
||||||
|
# print self._container.getLoopsRoot()
|
||||||
|
# return self._container.getLoopsRoot()
|
||||||
|
# return super(NodeTraversable, self).traverse(name, furtherPath)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue