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
|
||||
>>> loops['concepts'] = ConceptManager()
|
||||
>>> concepts = loops['concepts']
|
||||
>>> zope = Concept()
|
||||
>>> concepts['zope'] = zope
|
||||
>>> zope.title
|
||||
>>> cc1 = Concept()
|
||||
>>> concepts['cc1'] = cc1
|
||||
>>> cc1.title
|
||||
u''
|
||||
|
||||
>>> zope3 = Concept(u'Zope 3')
|
||||
>>> concepts['zope3'] = zope3
|
||||
>>> zope3.title
|
||||
>>> cc2 = Concept(u'Zope 3')
|
||||
>>> concepts['cc2'] = cc2
|
||||
>>> cc2.title
|
||||
u'Zope 3'
|
||||
|
||||
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):
|
||||
|
||||
>>> zope.assignConcept(zope3)
|
||||
>>> cc1.assignConcept(cc2)
|
||||
|
||||
We can now ask our concepts for their related concepts:
|
||||
|
||||
>>> sc1 = zope.getSubConcepts()
|
||||
>>> sc1 = cc1.getSubConcepts()
|
||||
>>> len(sc1)
|
||||
1
|
||||
>>> zope3 in sc1
|
||||
>>> cc2 in sc1
|
||||
True
|
||||
>>> len(zope.getParentConcepts())
|
||||
>>> len(cc1.getParentConcepts())
|
||||
0
|
||||
|
||||
>>> pc2 = zope3.getParentConcepts()
|
||||
>>> pc2 = cc2.getParentConcepts()
|
||||
>>> len(pc2)
|
||||
1
|
||||
|
||||
>>> zope in pc2
|
||||
>>> cc1 in pc2
|
||||
True
|
||||
>>> len(zope3.getSubConcepts())
|
||||
>>> len(cc2.getSubConcepts())
|
||||
0
|
||||
|
||||
TODO: Work with views...
|
||||
|
@ -81,31 +81,33 @@ We first need a resource manager:
|
|||
>>> loops['resources'] = ResourceManager()
|
||||
>>> 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')
|
||||
>>> resources['zope_info'] = zope_info
|
||||
>>> zope_info.title
|
||||
>>> doc1 = Document(u'Zope Info')
|
||||
>>> resources['doc1'] = doc1
|
||||
>>> doc1.title
|
||||
u'Zope Info'
|
||||
>>> zope_info.body
|
||||
>>> doc1.data
|
||||
u''
|
||||
>>> zope_info.format
|
||||
>>> doc1.contentType
|
||||
u'text/xml'
|
||||
|
||||
Another one is a media asset:
|
||||
|
||||
We can associate a resource with a concept by assigning it to the concept:
|
||||
|
||||
>>> zope.assignResource(zope_info)
|
||||
>>> res = zope.getResources()
|
||||
>>> cc1.assignResource(doc1)
|
||||
>>> res = cc1.getResources()
|
||||
>>> list(res)
|
||||
[<loops.resource.Document ...>]
|
||||
|
||||
The resource also provides access to the associated concepts (or views, see
|
||||
below) via the getClients() method:
|
||||
|
||||
>>> conc = zope_info.getClients()
|
||||
>>> conc = doc1.getClients()
|
||||
>>> len(conc)
|
||||
1
|
||||
>>> conc[0] is zope
|
||||
>>> conc[0] is cc1
|
||||
True
|
||||
|
||||
|
||||
|
@ -200,14 +202,14 @@ Targets
|
|||
We can associate a node with a concept or directly with a resource via the
|
||||
view class's target attribute:
|
||||
|
||||
>>> m111.target = zope_info
|
||||
>>> m111.target is zope_info
|
||||
>>> m111.target = cc1
|
||||
>>> m111.target is cc1
|
||||
True
|
||||
>>> m111.target = zope_info
|
||||
>>> m111.target is zope_info
|
||||
>>> m111.target = cc1
|
||||
>>> m111.target is cc1
|
||||
True
|
||||
>>> m111.target = zope3
|
||||
>>> m111.target is zope3
|
||||
>>> m111.target = cc2
|
||||
>>> m111.target is cc2
|
||||
True
|
||||
|
||||
Node views
|
||||
|
|
|
@ -159,7 +159,7 @@
|
|||
label="Add Document"
|
||||
name="AddLoopsDocument.html"
|
||||
schema="loops.interfaces.IDocument"
|
||||
fields="title body format"
|
||||
fields="title data contentType"
|
||||
content_factory="loops.resource.Document"
|
||||
permission="zope.ManageContent"
|
||||
/>
|
||||
|
@ -176,12 +176,41 @@
|
|||
label="Edit Document"
|
||||
name="edit.html"
|
||||
schema="loops.interfaces.IDocument"
|
||||
fields="title body format"
|
||||
fields="title data contentType"
|
||||
for="loops.interfaces.IDocument"
|
||||
permission="zope.ManageContent"
|
||||
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 -->
|
||||
|
||||
<addform
|
||||
|
|
|
@ -129,6 +129,29 @@
|
|||
|
||||
</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 -->
|
||||
|
||||
<interface interface=".interfaces.IViewManager"
|
||||
|
@ -188,6 +211,17 @@
|
|||
|
||||
<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 -->
|
||||
<include package=".browser" />
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ from zope.i18nmessageid import MessageFactory
|
|||
from zope import schema
|
||||
from zope.app.container.constraints import contains, containers
|
||||
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
|
||||
|
||||
_ = MessageFactory('loops')
|
||||
|
@ -102,8 +102,8 @@ class IConceptManagerContained(Interface):
|
|||
# resource interfaces
|
||||
|
||||
class IResource(Interface):
|
||||
""" A resource is an atomic information element that is usually
|
||||
available via a concept.
|
||||
""" A resource is an atomic information element that is made
|
||||
available via a view or a concept.
|
||||
"""
|
||||
|
||||
title = schema.TextLine(
|
||||
|
@ -111,6 +111,13 @@ class IResource(Interface):
|
|||
description=_(u'Title of the document'),
|
||||
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):
|
||||
""" Return a sequence of objects that are clients of the resource,
|
||||
i.e. that have some relation with it.
|
||||
|
@ -121,23 +128,22 @@ class IDocument(IResource):
|
|||
""" A resource containing an editable body.
|
||||
"""
|
||||
|
||||
body = schema.Text(
|
||||
title=_(u'Body'),
|
||||
description=_(u'Body 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'),
|
||||
data = schema.Text(
|
||||
title=_(u'Data'),
|
||||
description=_(u'Raw body data of the document'),
|
||||
required=False)
|
||||
|
||||
|
||||
class IFile(IResource, IBaseFile):
|
||||
class IMediaAsset(IResource, IBaseAsset):
|
||||
""" 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):
|
||||
""" A manager/container for resources.
|
||||
|
@ -173,6 +179,10 @@ class IView(Interface):
|
|||
class IBaseNode(IOrderedContainer):
|
||||
""" Common abstract base class for different types of nodes
|
||||
"""
|
||||
|
||||
def getLoopsRoot():
|
||||
""" Return the loops root object.
|
||||
"""
|
||||
|
||||
|
||||
class INode(IView, IBaseNode):
|
||||
|
|
34
resource.py
34
resource.py
|
@ -25,11 +25,12 @@ $Id$
|
|||
from zope.app import zapi
|
||||
from zope.app.container.btree import BTreeContainer
|
||||
from zope.app.container.contained import Contained
|
||||
from zope.app.file.image import Image as BaseMediaAsset
|
||||
from zope.interface import implements
|
||||
from persistent import Persistent
|
||||
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 ILoopsContained
|
||||
|
||||
|
@ -43,27 +44,36 @@ class Resource(Contained, Persistent):
|
|||
def setTitle(self, title): self._title = title
|
||||
title = property(getTitle, setTitle)
|
||||
|
||||
def __init__(self, title=u''):
|
||||
self.title = title
|
||||
_contentType = u'text/xml'
|
||||
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):
|
||||
rels = getRelations(second=self, relationships=relationships)
|
||||
return [r.first for r in rels]
|
||||
|
||||
def __init__(self, title=u''):
|
||||
self.title = title
|
||||
|
||||
|
||||
class Document(Resource):
|
||||
|
||||
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
|
||||
def getFormat(self): return self._format
|
||||
format = property(getFormat, setFormat)
|
||||
|
||||
class MediaAsset(Resource, BaseMediaAsset):
|
||||
|
||||
implements(IMediaAsset)
|
||||
|
||||
def __init__(self, title=u''):
|
||||
super(MediaAsset, self).__init__()
|
||||
self.title = title
|
||||
|
||||
|
||||
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 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 loops.concept import Concept, ConceptManager
|
||||
from loops.resource import Document, ResourceManager
|
||||
from loops.resource import Document, MediaAsset, ResourceManager
|
||||
from loops.view import Node, ViewManager
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
@ -28,6 +29,8 @@ class Test(unittest.TestCase):
|
|||
self.assert_(IConceptManager.providedBy(ConceptManager()))
|
||||
verifyClass(IDocument, Document)
|
||||
self.assert_(IDocument.providedBy(Document()))
|
||||
verifyClass(IMediaAsset, MediaAsset)
|
||||
self.assert_(IMediaAsset.providedBy(MediaAsset()))
|
||||
verifyClass(IResourceManager, ResourceManager)
|
||||
self.assert_(IResourceManager.providedBy(ResourceManager()))
|
||||
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.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.component import adapts
|
||||
from zope.interface import implements
|
||||
from persistent import Persistent
|
||||
from cybertools.relation import DyadicRelation
|
||||
|
@ -95,6 +98,9 @@ class Node(View, OrderedContainer):
|
|||
|
||||
contentType = u'zope.source.rest'
|
||||
|
||||
def getLoopsRoot(self):
|
||||
return zapi.getParent(self).getLoopsRoot()
|
||||
|
||||
def getParentNode(self, nodeTypes=None):
|
||||
parent = zapi.getParent(self)
|
||||
while INode.providedBy(parent):
|
||||
|
@ -134,8 +140,34 @@ class ViewManager(OrderedContainer):
|
|||
|
||||
implements(IViewManager, ILoopsContained)
|
||||
|
||||
def getLoopsRoot(self):
|
||||
return zapi.getParent(self)
|
||||
|
||||
|
||||
class TargetRelation(DyadicRelation):
|
||||
""" 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