reorganize resource stuff - dynamic typing, first type is 'file'
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1289 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
89ae9aeab0
commit
e860cf5a07
16 changed files with 349 additions and 298 deletions
46
README.txt
46
README.txt
|
@ -17,12 +17,12 @@ with lower-level aspects like type or state management.
|
||||||
|
|
||||||
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
||||||
>>> site = placefulSetUp(True)
|
>>> site = placefulSetUp(True)
|
||||||
|
|
||||||
>>> from zope.app import zapi
|
>>> from zope.app import zapi
|
||||||
>>> from zope.app.tests import ztapi
|
>>> from zope.app.tests import ztapi
|
||||||
>>> from zope.interface import Interface
|
>>> from zope.interface import Interface
|
||||||
>>> from zope.publisher.browser import TestRequest
|
>>> from zope.publisher.browser import TestRequest
|
||||||
|
|
||||||
|
|
||||||
Concepts and Relations
|
Concepts and Relations
|
||||||
======================
|
======================
|
||||||
|
@ -73,7 +73,7 @@ also need a default predicate concept; the default name for this is
|
||||||
|
|
||||||
Now we can assign the concept c2 as a child to c1 (using the standard
|
Now we can assign the concept c2 as a child to c1 (using the standard
|
||||||
ConceptRelation):
|
ConceptRelation):
|
||||||
|
|
||||||
>>> cc1.assignChild(cc2)
|
>>> cc1.assignChild(cc2)
|
||||||
|
|
||||||
We can now ask our concepts for their related child and parent concepts:
|
We can now ask our concepts for their related child and parent concepts:
|
||||||
|
@ -163,7 +163,7 @@ The token attribute provided with the items returned by the children() and
|
||||||
parents() methods identifies identifies not only the item itself but
|
parents() methods identifies identifies not only the item itself but
|
||||||
also the relationship to the context object using a combination
|
also the relationship to the context object using a combination
|
||||||
of URIs to item and the predicate of the relationship:
|
of URIs to item and the predicate of the relationship:
|
||||||
|
|
||||||
>>> [c.token for c in children]
|
>>> [c.token for c in children]
|
||||||
['.loops/concepts/cc2:.loops/concepts/standard']
|
['.loops/concepts/cc2:.loops/concepts/standard']
|
||||||
|
|
||||||
|
@ -207,11 +207,11 @@ types and predicates.
|
||||||
>>> from zope.schema.interfaces import IIterableSource
|
>>> from zope.schema.interfaces import IIterableSource
|
||||||
>>> ztapi.provideAdapter(IIterableSource, ITerms, LoopsTerms,
|
>>> ztapi.provideAdapter(IIterableSource, ITerms, LoopsTerms,
|
||||||
... with=(IBrowserRequest,))
|
... with=(IBrowserRequest,))
|
||||||
|
|
||||||
>>> sorted((t.title, t.token) for t in view.conceptTypes())
|
>>> sorted((t.title, t.token) for t in view.conceptTypes())
|
||||||
[(u'Topic', '.loops/concepts/topic'), (u'Type', '.loops/concepts/type'),
|
[(u'Topic', '.loops/concepts/topic'), (u'Type', '.loops/concepts/type'),
|
||||||
(u'Unknown Type', '.loops/concepts/unknown')]
|
(u'Unknown Type', '.loops/concepts/unknown')]
|
||||||
|
|
||||||
>>> sorted((t.title, t.token) for t in view.predicates())
|
>>> sorted((t.title, t.token) for t in view.predicates())
|
||||||
[(u'subconcept', '.loops/concepts/standard')]
|
[(u'subconcept', '.loops/concepts/standard')]
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ Index attributes adapter
|
||||||
>>> idx = IndexAttributes(cc2)
|
>>> idx = IndexAttributes(cc2)
|
||||||
>>> idx.text()
|
>>> idx.text()
|
||||||
u'cc2 Zope 3'
|
u'cc2 Zope 3'
|
||||||
|
|
||||||
>>> idx.title()
|
>>> idx.title()
|
||||||
u'cc2 Zope 3'
|
u'cc2 Zope 3'
|
||||||
|
|
||||||
|
@ -230,16 +230,16 @@ Index attributes adapter
|
||||||
Resources and what they have to do with Concepts
|
Resources and what they have to do with Concepts
|
||||||
================================================
|
================================================
|
||||||
|
|
||||||
>>> from loops.interfaces import IDocument, IMediaAsset
|
>>> from loops.interfaces import IResource, IDocument, IMediaAsset
|
||||||
|
|
||||||
We first need a resource manager:
|
We first need a resource manager:
|
||||||
|
|
||||||
>>> from loops.resource import ResourceManager
|
>>> from loops.resource import ResourceManager
|
||||||
>>> loopsRoot['resources'] = ResourceManager()
|
>>> loopsRoot['resources'] = ResourceManager()
|
||||||
>>> resources = loopsRoot['resources']
|
>>> resources = loopsRoot['resources']
|
||||||
|
|
||||||
A common type of resource is a document:
|
A common type of resource is a document:
|
||||||
|
|
||||||
>>> from loops.interfaces import IDocument
|
>>> from loops.interfaces import IDocument
|
||||||
>>> from loops.resource import Document
|
>>> from loops.resource import Document
|
||||||
>>> doc1 = Document(u'Zope Info')
|
>>> doc1 = Document(u'Zope Info')
|
||||||
|
@ -247,9 +247,9 @@ A common type of resource is a document:
|
||||||
>>> doc1.title
|
>>> doc1.title
|
||||||
u'Zope Info'
|
u'Zope Info'
|
||||||
>>> doc1.data
|
>>> doc1.data
|
||||||
u''
|
|
||||||
>>> doc1.contentType
|
|
||||||
''
|
''
|
||||||
|
>>> doc1.contentType
|
||||||
|
u''
|
||||||
|
|
||||||
Another one is a media asset:
|
Another one is a media asset:
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ Another one is a media asset:
|
||||||
>>> img = MediaAsset(u'A png Image')
|
>>> img = MediaAsset(u'A png Image')
|
||||||
|
|
||||||
For testing we use some simple files from the tests directory:
|
For testing we use some simple files from the tests directory:
|
||||||
|
|
||||||
>>> from loops import tests
|
>>> from loops import tests
|
||||||
>>> import os
|
>>> import os
|
||||||
>>> path = os.path.join(*tests.__path__)
|
>>> path = os.path.join(*tests.__path__)
|
||||||
|
@ -312,7 +312,7 @@ These relations may also be managed starting from a resource using
|
||||||
the resource configuration view:
|
the resource configuration view:
|
||||||
|
|
||||||
>>> from loops.browser.resource import ResourceConfigureView
|
>>> from loops.browser.resource import ResourceConfigureView
|
||||||
|
|
||||||
Index attributes adapter
|
Index attributes adapter
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ Index attributes adapter
|
||||||
>>> idx = IndexAttributes(doc1)
|
>>> idx = IndexAttributes(doc1)
|
||||||
>>> idx.text()
|
>>> idx.text()
|
||||||
u'doc1 Zope Info'
|
u'doc1 Zope Info'
|
||||||
|
|
||||||
>>> idx.title()
|
>>> idx.title()
|
||||||
u'doc1 Zope Info'
|
u'doc1 Zope Info'
|
||||||
|
|
||||||
|
@ -340,7 +340,7 @@ the views or nodes, however, present informations coming from the concepts
|
||||||
or resources they are related to.
|
or resources they are related to.
|
||||||
|
|
||||||
We first need a view manager:
|
We first need a view manager:
|
||||||
|
|
||||||
>>> from loops.view import ViewManager, Node
|
>>> from loops.view import ViewManager, Node
|
||||||
>>> from zope.security.checker import NamesChecker, defineChecker
|
>>> from zope.security.checker import NamesChecker, defineChecker
|
||||||
>>> nodeChecker = NamesChecker(('body',))
|
>>> nodeChecker = NamesChecker(('body',))
|
||||||
|
@ -351,7 +351,7 @@ We first need a view manager:
|
||||||
|
|
||||||
The view space is typically built up with nodes; a node may be a top-level
|
The view space is typically built up with nodes; a node may be a top-level
|
||||||
menu that may contain other nodes as menu or content items:
|
menu that may contain other nodes as menu or content items:
|
||||||
|
|
||||||
>>> m1 = Node(u'Menu')
|
>>> m1 = Node(u'Menu')
|
||||||
>>> views['m1'] = m1
|
>>> views['m1'] = m1
|
||||||
>>> m11 = Node(u'Zope')
|
>>> m11 = Node(u'Zope')
|
||||||
|
@ -426,7 +426,7 @@ out - this is usually done through ZCML.)
|
||||||
>>> from cybertools.relation.interfaces import IRelationInvalidatedEvent
|
>>> from cybertools.relation.interfaces import IRelationInvalidatedEvent
|
||||||
>>> ztapi.subscribe([ITargetRelation, IRelationInvalidatedEvent], None,
|
>>> ztapi.subscribe([ITargetRelation, IRelationInvalidatedEvent], None,
|
||||||
... removeTargetRelation)
|
... removeTargetRelation)
|
||||||
|
|
||||||
>>> m111.target = cc1
|
>>> m111.target = cc1
|
||||||
>>> m111.target is cc1
|
>>> m111.target is cc1
|
||||||
True
|
True
|
||||||
|
@ -487,10 +487,10 @@ accessing a target via a node view it is usually wrapped in a corresponding
|
||||||
view; these views we have to provide as multi-adapters:
|
view; these views we have to provide as multi-adapters:
|
||||||
|
|
||||||
>>> from loops.browser.node import ConfigureView
|
>>> from loops.browser.node import ConfigureView
|
||||||
>>> from loops.browser.resource import DocumentView, MediaAssetView
|
>>> from loops.browser.resource import DocumentView, ResourceView
|
||||||
>>> ztapi.provideAdapter(IDocument, Interface, DocumentView,
|
>>> ztapi.provideAdapter(IDocument, Interface, DocumentView,
|
||||||
... with=(IBrowserRequest,))
|
... with=(IBrowserRequest,))
|
||||||
>>> ztapi.provideAdapter(IMediaAsset, Interface, MediaAssetView,
|
>>> ztapi.provideAdapter(IResource, Interface, ResourceView,
|
||||||
... with=(IBrowserRequest,))
|
... with=(IBrowserRequest,))
|
||||||
|
|
||||||
>>> form = {'action': 'create', 'create.title': 'New Resource',
|
>>> form = {'action': 'create', 'create.title': 'New Resource',
|
||||||
|
@ -592,10 +592,10 @@ Let's add some more nodes and reorder them:
|
||||||
>>> m11['m114'] = m114
|
>>> m11['m114'] = m114
|
||||||
>>> m11.keys()
|
>>> m11.keys()
|
||||||
['m111', 'm112', 'm113', 'm114']
|
['m111', 'm112', 'm113', 'm114']
|
||||||
|
|
||||||
A special management view provides methods for moving objects down, up,
|
A special management view provides methods for moving objects down, up,
|
||||||
to the bottom, and to the top.
|
to the bottom, and to the top.
|
||||||
|
|
||||||
>>> from cybertools.container.ordered import OrderedContainerView
|
>>> from cybertools.container.ordered import OrderedContainerView
|
||||||
>>> view = OrderedContainerView(m11, TestRequest())
|
>>> view = OrderedContainerView(m11, TestRequest())
|
||||||
>>> view.move_bottom(('m113',))
|
>>> view.move_bottom(('m113',))
|
||||||
|
@ -641,7 +641,7 @@ instance to another.
|
||||||
>>> exporter.dumpData()
|
>>> exporter.dumpData()
|
||||||
|
|
||||||
Load them again from the exported file:
|
Load them again from the exported file:
|
||||||
|
|
||||||
>>> importer = NodesImporter(views)
|
>>> importer = NodesImporter(views)
|
||||||
>>> importer.filename = dumpname
|
>>> importer.filename = dumpname
|
||||||
>>> imported = importer.getData()
|
>>> imported = importer.getData()
|
||||||
|
|
|
@ -117,7 +117,7 @@ class BaseView(object):
|
||||||
@Lazy
|
@Lazy
|
||||||
def loopsRoot(self):
|
def loopsRoot(self):
|
||||||
return self.context.getLoopsRoot()
|
return self.context.getLoopsRoot()
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def url(self):
|
def url(self):
|
||||||
return zapi.absoluteURL(self.context, self.request)
|
return zapi.absoluteURL(self.context, self.request)
|
||||||
|
@ -199,9 +199,10 @@ class LoopsTerms(object):
|
||||||
@Lazy
|
@Lazy
|
||||||
def loopsRoot(self):
|
def loopsRoot(self):
|
||||||
return self.context.getLoopsRoot()
|
return self.context.getLoopsRoot()
|
||||||
|
|
||||||
def getTerm(self, value):
|
def getTerm(self, value):
|
||||||
#return BaseView(value, self.request)
|
#if value is None:
|
||||||
|
# return SimpleTerm(None, '', u'not assigned')
|
||||||
title = value.title or zapi.getName(value)
|
title = value.title or zapi.getName(value)
|
||||||
token = self.loopsRoot.getLoopsUri(value)
|
token = self.loopsRoot.getLoopsUri(value)
|
||||||
return SimpleTerm(value, token, title)
|
return SimpleTerm(value, token, title)
|
||||||
|
|
|
@ -66,14 +66,14 @@ class ConceptEditForm(EditForm):
|
||||||
class ConceptView(BaseView):
|
class ConceptView(BaseView):
|
||||||
|
|
||||||
template = NamedTemplate('loops.concept_macros')
|
template = NamedTemplate('loops.concept_macros')
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def macro(self):
|
def macro(self):
|
||||||
return self.template.macros['conceptdata']
|
return self.template.macros['conceptdata']
|
||||||
|
|
||||||
def fieldData(self):
|
def fieldData(self):
|
||||||
ti = IType(self.context).typeInterface
|
ti = IType(self.context).typeInterface
|
||||||
if not ti: return
|
if not ti: return
|
||||||
adapter = ti(self.context)
|
adapter = ti(self.context)
|
||||||
for n, f in schema.getFieldsInOrder(ti):
|
for n, f in schema.getFieldsInOrder(ti):
|
||||||
value = getattr(adapter, n, '')
|
value = getattr(adapter, n, '')
|
||||||
|
|
|
@ -233,6 +233,21 @@
|
||||||
|
|
||||||
<!-- resource in general -->
|
<!-- resource in general -->
|
||||||
|
|
||||||
|
<page
|
||||||
|
for="loops.interfaces.IResource"
|
||||||
|
name="index.html"
|
||||||
|
permission="zope.View"
|
||||||
|
class=".resource.ResourceView"
|
||||||
|
attribute="show" />
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
for="loops.interfaces.IResource
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
provides="zope.interface.Interface"
|
||||||
|
factory="loops.browser.resource.ResourceView"
|
||||||
|
permission="zope.View"
|
||||||
|
/>
|
||||||
|
|
||||||
<pages
|
<pages
|
||||||
for="loops.interfaces.IResource"
|
for="loops.interfaces.IResource"
|
||||||
class=".resource.ResourceConfigureView"
|
class=".resource.ResourceConfigureView"
|
||||||
|
@ -246,12 +261,19 @@
|
||||||
|
|
||||||
</pages>
|
</pages>
|
||||||
|
|
||||||
<zope:adapter
|
<page
|
||||||
for="loops.interfaces.IResource
|
name="edit.html"
|
||||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
for="loops.interfaces.IResource"
|
||||||
provides="zope.interface.Interface"
|
class="loops.browser.resource.ResourceEditForm"
|
||||||
factory="loops.browser.resource.ResourceView"
|
permission="zope.ManageContent"
|
||||||
permission="zope.View"
|
menu="zmi_views" title="Edit"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- suppress the upload menu item: -->
|
||||||
|
<menuItem
|
||||||
|
for="loops.interfaces.IResource"
|
||||||
|
menu="zmi_views" action="upload.html" title="Upload"
|
||||||
|
filter="nothing"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- document -->
|
<!-- document -->
|
||||||
|
@ -263,33 +285,6 @@
|
||||||
class=".resource.DocumentView"
|
class=".resource.DocumentView"
|
||||||
attribute="show" />
|
attribute="show" />
|
||||||
|
|
||||||
<addform
|
|
||||||
label="Add Document"
|
|
||||||
name="AddLoopsDocument.html"
|
|
||||||
schema="loops.interfaces.IDocumentSchema"
|
|
||||||
fields="title data contentType"
|
|
||||||
content_factory="loops.resource.Document"
|
|
||||||
template="add.pt"
|
|
||||||
permission="zope.ManageContent" />
|
|
||||||
|
|
||||||
<addMenuItem
|
|
||||||
class="loops.resource.Document"
|
|
||||||
title="Document"
|
|
||||||
description="A document is an editable information unit"
|
|
||||||
permission="zope.ManageContent"
|
|
||||||
view="AddLoopsDocument.html"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- <editform
|
|
||||||
label="Edit Document"
|
|
||||||
name="edit.html"
|
|
||||||
schema="loops.interfaces.IDocumentSchema"
|
|
||||||
fields="title data contentType"
|
|
||||||
for="loops.interfaces.IDocument"
|
|
||||||
template="edit.pt"
|
|
||||||
permission="zope.ManageContent"
|
|
||||||
menu="zmi_views" title="Edit" />-->
|
|
||||||
|
|
||||||
<page
|
<page
|
||||||
name="edit.html"
|
name="edit.html"
|
||||||
for="loops.interfaces.IDocument"
|
for="loops.interfaces.IDocument"
|
||||||
|
@ -322,25 +317,7 @@
|
||||||
|
|
||||||
<!-- media asset -->
|
<!-- media asset -->
|
||||||
|
|
||||||
<addform
|
<!--<editform
|
||||||
label="Add Media Asset"
|
|
||||||
name="AddLoopsMediaAsset.html"
|
|
||||||
schema="loops.interfaces.IMediaAssetSchema"
|
|
||||||
fields="title data contentType"
|
|
||||||
content_factory="loops.resource.MediaAsset"
|
|
||||||
template="add.pt"
|
|
||||||
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"
|
label="Edit Media Asset"
|
||||||
name="edit.html"
|
name="edit.html"
|
||||||
schema="loops.interfaces.IMediaAssetSchema"
|
schema="loops.interfaces.IMediaAssetSchema"
|
||||||
|
@ -349,7 +326,7 @@
|
||||||
template="edit.pt"
|
template="edit.pt"
|
||||||
permission="zope.ManageContent"
|
permission="zope.ManageContent"
|
||||||
menu="zmi_views" title="Edit Media Asset"
|
menu="zmi_views" title="Edit Media Asset"
|
||||||
/>
|
/>-->
|
||||||
|
|
||||||
<!--<page
|
<!--<page
|
||||||
name="edit.html"
|
name="edit.html"
|
||||||
|
@ -359,21 +336,6 @@
|
||||||
menu="zmi_views" title="Edit"
|
menu="zmi_views" title="Edit"
|
||||||
/>-->
|
/>-->
|
||||||
|
|
||||||
<!-- suppress the upload menu item: -->
|
|
||||||
<menuItem
|
|
||||||
for="loops.interfaces.IMediaAsset"
|
|
||||||
menu="zmi_views" action="upload.html" title="Upload"
|
|
||||||
filter="nothing"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<zope:adapter
|
|
||||||
for="loops.interfaces.IMediaAsset
|
|
||||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
|
||||||
provides="zope.interface.Interface"
|
|
||||||
factory="loops.browser.resource.MediaAssetView"
|
|
||||||
permission="zope.View"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- view manager -->
|
<!-- view manager -->
|
||||||
|
|
||||||
<addform
|
<addform
|
||||||
|
@ -584,6 +546,10 @@
|
||||||
for="loops.type.TypeInterfaceSourceList
|
for="loops.type.TypeInterfaceSourceList
|
||||||
zope.publisher.interfaces.browser.IBrowserRequest" />
|
zope.publisher.interfaces.browser.IBrowserRequest" />
|
||||||
|
|
||||||
|
<zope:adapter factory="loops.browser.common.LoopsTerms"
|
||||||
|
for="loops.resource.ResourceTypeSourceList
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest" />
|
||||||
|
|
||||||
<zope:view factory="loops.view.NodeTraverser"
|
<zope:view factory="loops.view.NodeTraverser"
|
||||||
for="loops.interfaces.INode"
|
for="loops.interfaces.INode"
|
||||||
type="zope.publisher.interfaces.browser.IBrowserRequest"
|
type="zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
|
|
@ -204,7 +204,7 @@ class NodeView(BaseView):
|
||||||
|
|
||||||
def active(self, item):
|
def active(self, item):
|
||||||
return item.context == self.context or item.context in self.parents
|
return item.context == self.context or item.context in self.parents
|
||||||
|
|
||||||
def targetDefaultView(self):
|
def targetDefaultView(self):
|
||||||
target = self.request.annotations.get('loops.view', {}).get('target')
|
target = self.request.annotations.get('loops.view', {}).get('target')
|
||||||
if target is None:
|
if target is None:
|
||||||
|
@ -250,7 +250,7 @@ class ConfigureView(NodeView):
|
||||||
obj = self.targetObject
|
obj = self.targetObject
|
||||||
if obj is not None:
|
if obj is not None:
|
||||||
return zapi.getMultiAdapter((obj, self.request))
|
return zapi.getMultiAdapter((obj, self.request))
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
request = self.request
|
request = self.request
|
||||||
action = request.get('action')
|
action = request.get('action')
|
||||||
|
@ -291,6 +291,8 @@ class ConfigureView(NodeView):
|
||||||
target.title = form.get('create.title', u'')
|
target.title = form.get('create.title', u'')
|
||||||
if IConcept.providedBy(target):
|
if IConcept.providedBy(target):
|
||||||
target.conceptType = type.typeProvider
|
target.conceptType = type.typeProvider
|
||||||
|
elif IResource.providedBy(target):
|
||||||
|
target.resourceType = type.typeProvider
|
||||||
notify(ObjectCreatedEvent(target))
|
notify(ObjectCreatedEvent(target))
|
||||||
notify(ObjectModifiedEvent(target))
|
notify(ObjectModifiedEvent(target))
|
||||||
self.context.target = target
|
self.context.target = target
|
||||||
|
|
|
@ -33,8 +33,8 @@ 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
|
||||||
|
|
||||||
from loops.interfaces import IDocument, IMediaAsset
|
from cybertools.typology.interfaces import IType
|
||||||
from loops.interfaces import IFileSystemResource, IControlledResource
|
from loops.interfaces import IBaseResource, IDocument, IMediaAsset
|
||||||
from loops.browser.common import EditForm, BaseView
|
from loops.browser.common import EditForm, BaseView
|
||||||
from loops.browser.concept import ConceptRelationView, ConceptConfigureView
|
from loops.browser.concept import ConceptRelationView, ConceptConfigureView
|
||||||
from loops.browser.node import NodeView
|
from loops.browser.node import NodeView
|
||||||
|
@ -48,12 +48,27 @@ renderingFactories = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceEditForm(EditForm):
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def typeInterface(self):
|
||||||
|
return IType(self.context).typeInterface
|
||||||
|
|
||||||
|
@property
|
||||||
|
def form_fields(self):
|
||||||
|
fields = FormFields(IBaseResource)
|
||||||
|
typeInterface = self.typeInterface
|
||||||
|
if typeInterface is not None:
|
||||||
|
fields = FormFields(fields, typeInterface)
|
||||||
|
return fields
|
||||||
|
|
||||||
|
|
||||||
class DocumentEditForm(EditForm):
|
class DocumentEditForm(EditForm):
|
||||||
#form_fields = FormFields(IDocument, IFileSystemResource, IControlledResource)
|
|
||||||
form_fields = FormFields(IDocument)
|
form_fields = FormFields(IDocument)
|
||||||
for f in form_fields:
|
for f in form_fields:
|
||||||
f.render_context |= DISPLAY_UNWRITEABLE
|
f.render_context |= DISPLAY_UNWRITEABLE
|
||||||
|
|
||||||
|
|
||||||
class MediaAssetEditForm(EditForm):
|
class MediaAssetEditForm(EditForm):
|
||||||
form_fields = FormFields(IMediaAsset)
|
form_fields = FormFields(IMediaAsset)
|
||||||
|
|
||||||
|
@ -62,6 +77,20 @@ class ResourceView(BaseView):
|
||||||
|
|
||||||
template = ViewPageTemplateFile('resource_macros.pt')
|
template = ViewPageTemplateFile('resource_macros.pt')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def macro(self):
|
||||||
|
if 'image/' in self.context.contentType:
|
||||||
|
return self.template.macros['image']
|
||||||
|
else:
|
||||||
|
return self.template.macros['download']
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
data = self.context.data
|
||||||
|
response = self.request.response
|
||||||
|
response.setHeader('Content-Type', self.context.contentType)
|
||||||
|
response.setHeader('Content-Length', len(data))
|
||||||
|
return data
|
||||||
|
|
||||||
def concepts(self):
|
def concepts(self):
|
||||||
for r in self.context.getConceptRelations():
|
for r in self.context.getConceptRelations():
|
||||||
yield ConceptRelationView(r, self.request)
|
yield ConceptRelationView(r, self.request)
|
||||||
|
@ -130,8 +159,10 @@ class ResourceConfigureView(ResourceView, ConceptConfigureView):
|
||||||
|
|
||||||
class DocumentView(ResourceView):
|
class DocumentView(ResourceView):
|
||||||
|
|
||||||
macro = ResourceView.template.macros['render']
|
@property
|
||||||
|
def macro(self):
|
||||||
|
return ResourceView.template.macros['render']
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
""" Return the rendered content (data) of the context object.
|
""" Return the rendered content (data) of the context object.
|
||||||
"""
|
"""
|
||||||
|
@ -143,19 +174,3 @@ class DocumentView(ResourceView):
|
||||||
view = zapi.getMultiAdapter((removeAllProxies(source), self.request))
|
view = zapi.getMultiAdapter((removeAllProxies(source), self.request))
|
||||||
return view.render()
|
return view.render()
|
||||||
|
|
||||||
def show(self):
|
|
||||||
data = self.context.data
|
|
||||||
response = self.request.response
|
|
||||||
response.setHeader('Content-Type', self.context.contentType)
|
|
||||||
response.setHeader('Content-Length', len(data))
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
class MediaAssetView(ResourceView):
|
|
||||||
|
|
||||||
@property
|
|
||||||
def macro(self):
|
|
||||||
if 'image/' in self.context.contentType:
|
|
||||||
return self.template.macros['image']
|
|
||||||
else:
|
|
||||||
return self.template.macros['download']
|
|
||||||
|
|
47
common.py
47
common.py
|
@ -29,9 +29,54 @@ from zope.app.dublincore.zopedublincore import ScalarProperty
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from loops.interfaces import ILoopsObject
|
from loops.interfaces import ILoopsObject, IConcept, IResource
|
||||||
|
from loops.interfaces import IResourceAdapter
|
||||||
|
|
||||||
|
|
||||||
|
# type interface adapters
|
||||||
|
|
||||||
|
class AdapterBase(object):
|
||||||
|
""" (Mix-in) Class for concept adapters that provide editing of fields
|
||||||
|
defined by the type interface.
|
||||||
|
"""
|
||||||
|
|
||||||
|
adapts(IConcept)
|
||||||
|
|
||||||
|
_attributes = ('context', '__parent__', )
|
||||||
|
_schemas = list(IConcept)
|
||||||
|
|
||||||
|
def __init__(self, context):
|
||||||
|
self.context = context # to get the permission stuff right
|
||||||
|
self.__parent__ = context
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
self.checkAttr(attr)
|
||||||
|
return getattr(self.context, '_' + attr, None)
|
||||||
|
|
||||||
|
def __setattr__(self, attr, value):
|
||||||
|
if attr in self._attributes:
|
||||||
|
object.__setattr__(self, attr, value)
|
||||||
|
else:
|
||||||
|
self.checkAttr(attr)
|
||||||
|
setattr(self.context, '_' + attr, value)
|
||||||
|
|
||||||
|
def checkAttr(self, attr):
|
||||||
|
if attr not in self._schemas:
|
||||||
|
raise AttributeError(attr)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.context == other.context
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceAdapterBase(AdapterBase):
|
||||||
|
|
||||||
|
adapts(IResource)
|
||||||
|
|
||||||
|
_schemas = list(IResourceAdapter)
|
||||||
|
|
||||||
|
|
||||||
|
# other adapters
|
||||||
|
|
||||||
class LoopsDCAdapter(ZDCAnnotatableAdapter):
|
class LoopsDCAdapter(ZDCAnnotatableAdapter):
|
||||||
|
|
||||||
implements(IZopeDublinCore)
|
implements(IZopeDublinCore)
|
||||||
|
|
|
@ -125,6 +125,30 @@
|
||||||
|
|
||||||
</content>
|
</content>
|
||||||
|
|
||||||
|
<interface
|
||||||
|
interface=".interfaces.IResource"
|
||||||
|
type="zope.app.content.interfaces.IContentType" />
|
||||||
|
|
||||||
|
<class class=".resource.Resource">
|
||||||
|
|
||||||
|
<implements
|
||||||
|
interface="zope.app.annotation.interfaces.IAttributeAnnotatable" />
|
||||||
|
|
||||||
|
<factory
|
||||||
|
id="loops.Resource"
|
||||||
|
description="Document" />
|
||||||
|
|
||||||
|
<require
|
||||||
|
permission="zope.View"
|
||||||
|
interface=".interfaces.IBaseResource
|
||||||
|
zope.app.size.interfaces.ISized" />
|
||||||
|
|
||||||
|
<require
|
||||||
|
permission="zope.ManageContent"
|
||||||
|
set_schema=".interfaces.IBaseResource" />
|
||||||
|
|
||||||
|
</class>
|
||||||
|
|
||||||
<interface
|
<interface
|
||||||
interface=".interfaces.IDocument"
|
interface=".interfaces.IDocument"
|
||||||
type="zope.app.content.interfaces.IContentType" />
|
type="zope.app.content.interfaces.IContentType" />
|
||||||
|
@ -141,19 +165,12 @@
|
||||||
<require
|
<require
|
||||||
permission="zope.View"
|
permission="zope.View"
|
||||||
interface=".interfaces.IDocument
|
interface=".interfaces.IDocument
|
||||||
.interfaces.IFileSystemResource
|
|
||||||
.interfaces.IControlledResource
|
|
||||||
zope.app.size.interfaces.ISized" />
|
zope.app.size.interfaces.ISized" />
|
||||||
|
|
||||||
<require
|
<require
|
||||||
permission="zope.ManageContent"
|
permission="zope.ManageContent"
|
||||||
set_schema=".interfaces.IDocument" />
|
set_schema=".interfaces.IDocument" />
|
||||||
|
|
||||||
<require
|
|
||||||
permission="zope.ManageApplication"
|
|
||||||
set_schema=".interfaces.IFileSystemResource
|
|
||||||
.interfaces.IControlledResource" />
|
|
||||||
|
|
||||||
</content>
|
</content>
|
||||||
|
|
||||||
<interface
|
<interface
|
||||||
|
@ -171,11 +188,11 @@
|
||||||
|
|
||||||
<require
|
<require
|
||||||
permission="zope.View"
|
permission="zope.View"
|
||||||
interface=".interfaces.IMediaAsset" />
|
interface=".interfaces.IBaseResource" />
|
||||||
|
|
||||||
<require
|
<require
|
||||||
permission="zope.ManageContent"
|
permission="zope.ManageContent"
|
||||||
set_schema=".interfaces.IMediaAsset" />
|
set_schema=".interfaces.IBaseResource" />
|
||||||
|
|
||||||
</content>
|
</content>
|
||||||
|
|
||||||
|
@ -249,12 +266,7 @@
|
||||||
trusted="True" />
|
trusted="True" />
|
||||||
|
|
||||||
<adapter factory="loops.common.LoopsDCAdapter"
|
<adapter factory="loops.common.LoopsDCAdapter"
|
||||||
for="loops.interfaces.IDocument"
|
for="loops.interfaces.IResource"
|
||||||
provides="zope.app.dublincore.interfaces.IZopeDublinCore"
|
|
||||||
trusted="True" />
|
|
||||||
|
|
||||||
<adapter factory="loops.common.LoopsDCAdapter"
|
|
||||||
for="loops.interfaces.IMediaAsset"
|
|
||||||
provides="zope.app.dublincore.interfaces.IZopeDublinCore"
|
provides="zope.app.dublincore.interfaces.IZopeDublinCore"
|
||||||
trusted="True" />
|
trusted="True" />
|
||||||
|
|
||||||
|
@ -264,16 +276,30 @@
|
||||||
|
|
||||||
<adapter factory="loops.concept.IndexAttributes" />
|
<adapter factory="loops.concept.IndexAttributes" />
|
||||||
<adapter factory="loops.resource.IndexAttributes" />
|
<adapter factory="loops.resource.IndexAttributes" />
|
||||||
<adapter factory="loops.resource.IndexableResource" />
|
<adapter factory="loops.resource.IndexableResource" trusted="True" />
|
||||||
|
<class class="loops.resource.IndexableResource">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="loops.interfaces.IBaseResourceSchema" />
|
||||||
|
</class>
|
||||||
|
|
||||||
<adapter factory="loops.resource.DocumentReadFileAdapter" />
|
<adapter factory="loops.resource.DocumentReadFileAdapter" />
|
||||||
<adapter factory="loops.resource.DocumentWriteFileAdapter" />
|
<adapter factory="loops.resource.DocumentWriteFileAdapter" />
|
||||||
|
|
||||||
|
<adapter factory="loops.type.LoopsType" />
|
||||||
<adapter factory="loops.type.ConceptType" />
|
<adapter factory="loops.type.ConceptType" />
|
||||||
<adapter factory="loops.type.ResourceType" />
|
<adapter factory="loops.type.ResourceType"
|
||||||
|
for="loops.interfaces.IDocument" />
|
||||||
|
<adapter factory="loops.type.ResourceType"
|
||||||
|
for="loops.interfaces.IMediaAsset" />
|
||||||
<adapter factory="loops.type.LoopsTypeManager" />
|
<adapter factory="loops.type.LoopsTypeManager" />
|
||||||
|
|
||||||
<adapter factory="loops.type.TypeConcept" />
|
<adapter factory="loops.type.TypeConcept" trusted="True" />
|
||||||
|
<class class="loops.type.TypeConcept">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="loops.interfaces.ITypeConcept" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="loops.interfaces.ITypeConcept" />
|
||||||
|
</class>
|
||||||
|
|
||||||
<adapter factory="loops.query.QueryConcept" trusted="True" />
|
<adapter factory="loops.query.QueryConcept" trusted="True" />
|
||||||
<class class="loops.query.QueryConcept">
|
<class class="loops.query.QueryConcept">
|
||||||
|
@ -283,6 +309,14 @@
|
||||||
set_schema="loops.query.IQueryConcept" />
|
set_schema="loops.query.IQueryConcept" />
|
||||||
</class>
|
</class>
|
||||||
|
|
||||||
|
<adapter factory="loops.resource.FileAdapter" trusted="True" />
|
||||||
|
<class class="loops.resource.FileAdapter">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="loops.interfaces.IFile" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="loops.interfaces.IFile" />
|
||||||
|
</class>
|
||||||
|
|
||||||
|
|
||||||
<adapter factory="loops.setup.SetupManager" />
|
<adapter factory="loops.setup.SetupManager" />
|
||||||
<adapter factory="loops.external.NodesLoader" />
|
<adapter factory="loops.external.NodesLoader" />
|
||||||
|
@ -302,7 +336,7 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<vocabulary
|
<vocabulary
|
||||||
factory="loops.type.ResourceTypeSourceList"
|
factory="loops.resource.ResourceTypeSourceList"
|
||||||
name="loops.resourceTypeSource"
|
name="loops.resourceTypeSource"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
100
interfaces.py
100
interfaces.py
|
@ -29,6 +29,7 @@ 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 IImage as IBaseAsset
|
from zope.app.file.interfaces import IImage as IBaseAsset
|
||||||
from zope.app.folder.interfaces import IFolder
|
from zope.app.folder.interfaces import IFolder
|
||||||
|
from zope.app.size.interfaces import ISized
|
||||||
from cybertools.relation.interfaces import IRelation
|
from cybertools.relation.interfaces import IRelation
|
||||||
|
|
||||||
import util
|
import util
|
||||||
|
@ -62,7 +63,7 @@ class IPotentialTarget(Interface):
|
||||||
|
|
||||||
class IConcept(ILoopsObject, IPotentialTarget):
|
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
|
||||||
associated with it and may be referenced by views.
|
associated with it and may be referenced by views.
|
||||||
"""
|
"""
|
||||||
|
@ -130,7 +131,7 @@ class IConcept(ILoopsObject, IPotentialTarget):
|
||||||
def getResources(predicates=None):
|
def getResources(predicates=None):
|
||||||
""" Return a sequence of resources assigned to self,
|
""" Return a sequence of resources assigned to self,
|
||||||
optionally restricted to the predicates given.
|
optionally restricted to the predicates given.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def getResourceRelations(predicates=None, resource=None):
|
def getResourceRelations(predicates=None, resource=None):
|
||||||
""" Return a sequence of relations to resources assigned to self,
|
""" Return a sequence of relations to resources assigned to self,
|
||||||
|
@ -143,12 +144,12 @@ class IConcept(ILoopsObject, IPotentialTarget):
|
||||||
|
|
||||||
The relationship defaults to ConceptResourceRelation.
|
The relationship defaults to ConceptResourceRelation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def deassignResource(resource, predicates=None):
|
def deassignResource(resource, predicates=None):
|
||||||
""" Remove the relations to the resource given from self, optionally
|
""" Remove the relations to the resource given from self, optionally
|
||||||
restricting them to the predicates given.
|
restricting them to the predicates given.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class IConceptView(Interface):
|
class IConceptView(Interface):
|
||||||
""" Used for accessing a concept via a node's target attribute"""
|
""" Used for accessing a concept via a node's target attribute"""
|
||||||
|
@ -178,12 +179,12 @@ class IConceptManagerContained(Interface):
|
||||||
# resource interfaces
|
# resource interfaces
|
||||||
|
|
||||||
|
|
||||||
class IBaseResource(Interface):
|
class IBaseResource(ILoopsObject):
|
||||||
""" New base interface for resources. Functionality beyond this simple
|
""" New base interface for resources. Functionality beyond this simple
|
||||||
interface is provided by adapters that are chosen via the
|
interface is provided by adapters that are chosen via the
|
||||||
resource type's typeInterface.
|
resource type's typeInterface.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
title = schema.TextLine(
|
title = schema.TextLine(
|
||||||
title=_(u'Title'),
|
title=_(u'Title'),
|
||||||
description=_(u'Title of the resource'),
|
description=_(u'Title of the resource'),
|
||||||
|
@ -199,6 +200,26 @@ class IBaseResource(Interface):
|
||||||
source="loops.resourceTypeSource",
|
source="loops.resourceTypeSource",
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
data = schema.Bytes(
|
||||||
|
title=_(u'Data'),
|
||||||
|
description=_(u'Resource raw data'),
|
||||||
|
default='',
|
||||||
|
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 IBaseResourceSchema(Interface):
|
||||||
|
""" New schema for resources; to be used by sub-interfaces that will
|
||||||
|
be implemented by type adapters.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class IResourceSchema(Interface):
|
class IResourceSchema(Interface):
|
||||||
|
|
||||||
|
@ -224,29 +245,6 @@ class IResourceSchema(Interface):
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
# the next two interfaces are probably obsolete:
|
|
||||||
|
|
||||||
class IFileSystemResource(Interface):
|
|
||||||
|
|
||||||
fsPath = schema.BytesLine(
|
|
||||||
title=_(u'Filesystem Path'),
|
|
||||||
description=_(u'Optional path to a file in the filesystem '
|
|
||||||
'to be used for storing the resource'),
|
|
||||||
default='',
|
|
||||||
missing_value='',
|
|
||||||
required=False)
|
|
||||||
|
|
||||||
|
|
||||||
class IControlledResource(Interface):
|
|
||||||
|
|
||||||
readOnly = schema.Bool(
|
|
||||||
title=_(u'Read only'),
|
|
||||||
description=_(u'Check this if resource may not be modified '
|
|
||||||
'after being first filled with non-empty content'),
|
|
||||||
default=False,
|
|
||||||
required=False)
|
|
||||||
|
|
||||||
|
|
||||||
class IResource(ILoopsObject, IPotentialTarget):
|
class IResource(ILoopsObject, IPotentialTarget):
|
||||||
""" A resource is an atomic information element that is made
|
""" A resource is an atomic information element that is made
|
||||||
available via a view or a concept.
|
available via a view or a concept.
|
||||||
|
@ -323,10 +321,10 @@ class IMediaAssetView(IMediaAssetSchema):
|
||||||
|
|
||||||
class IMediaAsset(IMediaAssetSchema, IResource, IBaseAsset):
|
class IMediaAsset(IMediaAssetSchema, 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.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class IResourceManager(ILoopsObject, IContainer):
|
class IResourceManager(ILoopsObject, IContainer):
|
||||||
""" A manager/container for resources.
|
""" A manager/container for resources.
|
||||||
"""
|
"""
|
||||||
|
@ -475,7 +473,7 @@ class ILoops(ILoopsObject):
|
||||||
""" Retrieve object specified by the loops uri (starting with
|
""" Retrieve object specified by the loops uri (starting with
|
||||||
'.loops/') given.
|
'.loops/') given.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def getConceptManager():
|
def getConceptManager():
|
||||||
""" Return the (default) concept manager.
|
""" Return the (default) concept manager.
|
||||||
"""
|
"""
|
||||||
|
@ -545,7 +543,7 @@ class ITypeConcept(Interface):
|
||||||
# storage = schema.Choice()
|
# storage = schema.Choice()
|
||||||
|
|
||||||
|
|
||||||
class IResourceAdapter(Interface):
|
class IResourceAdapter(IBaseResourceSchema):
|
||||||
""" Base interface for adapters for resources. This is the base interface
|
""" Base interface for adapters for resources. This is the base interface
|
||||||
of the interfaces to be used as typeInterface attribute on type concepts
|
of the interfaces to be used as typeInterface attribute on type concepts
|
||||||
specifying resource types.
|
specifying resource types.
|
||||||
|
@ -556,15 +554,15 @@ class IFile(IResourceAdapter):
|
||||||
""" A media asset that is not shown on a (web) page like an image but
|
""" A media asset that is not shown on a (web) page like an image but
|
||||||
may be downloaded instead.
|
may be downloaded instead.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class IImage(IResourceAdapter):
|
class IImage(IResourceAdapter):
|
||||||
""" A media asset that may be embedded in a (web) page as an image.
|
""" A media asset that may be embedded in a (web) page as an image.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ITextDocument(IResourceAdapter):
|
class ITextDocument(IResourceAdapter):
|
||||||
""" A resource containing some sort of plain text that may be rendered and
|
""" A resource containing some sort of plain text that may be rendered and
|
||||||
edited without necessarily involving a special external application
|
edited without necessarily involving a special external application
|
||||||
(like e.g. OpenOffice); typical content types are text/html, text/xml,
|
(like e.g. OpenOffice); typical content types are text/html, text/xml,
|
||||||
text/restructured, etc.
|
text/restructured, etc.
|
||||||
|
@ -581,3 +579,27 @@ class IViewConfiguratorSchema(Interface):
|
||||||
default=u'',
|
default=u'',
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
|
# the next two interfaces are obsolete, they will be replaced by IResourceStorage:
|
||||||
|
|
||||||
|
class IFileSystemResource(Interface):
|
||||||
|
|
||||||
|
fsPath = schema.BytesLine(
|
||||||
|
title=_(u'Filesystem Path'),
|
||||||
|
description=_(u'Optional path to a file in the filesystem '
|
||||||
|
'to be used for storing the resource'),
|
||||||
|
default='',
|
||||||
|
missing_value='',
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
|
class IControlledResource(Interface):
|
||||||
|
|
||||||
|
readOnly = schema.Bool(
|
||||||
|
title=_(u'Read only'),
|
||||||
|
description=_(u'Check this if resource may not be modified '
|
||||||
|
'after being first filled with non-empty content'),
|
||||||
|
default=False,
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,8 @@ from loops.interfaces import IConcept, IResource
|
||||||
from loops.knowledge.interfaces import IPerson, ITask
|
from loops.knowledge.interfaces import IPerson, ITask
|
||||||
from loops.organize.party import Person as BasePerson
|
from loops.organize.party import Person as BasePerson
|
||||||
from loops.organize.task import Task as BaseTask
|
from loops.organize.task import Task as BaseTask
|
||||||
from loops.type import TypeInterfaceSourceList, AdapterBase
|
from loops.common import AdapterBase
|
||||||
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
|
||||||
|
|
||||||
# register type interfaces - (TODO: use a function for this)
|
# register type interfaces - (TODO: use a function for this)
|
||||||
|
|
|
@ -41,7 +41,8 @@ from cybertools.typology.interfaces import IType
|
||||||
from loops.concept import Concept
|
from loops.concept import Concept
|
||||||
from loops.interfaces import IConcept
|
from loops.interfaces import IConcept
|
||||||
from loops.organize.interfaces import IPerson, ANNOTATION_KEY
|
from loops.organize.interfaces import IPerson, ANNOTATION_KEY
|
||||||
from loops.type import TypeInterfaceSourceList, AdapterBase
|
from loops.common import AdapterBase
|
||||||
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
|
||||||
|
|
||||||
# register type interfaces - (TODO: use a function for this)
|
# register type interfaces - (TODO: use a function for this)
|
||||||
|
|
|
@ -26,7 +26,8 @@ from zope.interface import implements
|
||||||
|
|
||||||
from cybertools.organize.interfaces import ITask
|
from cybertools.organize.interfaces import ITask
|
||||||
from loops.interfaces import IConcept
|
from loops.interfaces import IConcept
|
||||||
from loops.type import TypeInterfaceSourceList, AdapterBase
|
from loops.common import AdapterBase
|
||||||
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
|
||||||
|
|
||||||
TypeInterfaceSourceList.typeInterfaces += (ITask,)
|
TypeInterfaceSourceList.typeInterfaces += (ITask,)
|
||||||
|
|
|
@ -33,7 +33,8 @@ from cybertools.typology.interfaces import IType
|
||||||
from cybertools.process.interfaces import IProcess
|
from cybertools.process.interfaces import IProcess
|
||||||
from cybertools.process.definition import Process as BaseProcess
|
from cybertools.process.definition import Process as BaseProcess
|
||||||
from loops.interfaces import IConcept
|
from loops.interfaces import IConcept
|
||||||
from loops.type import TypeInterfaceSourceList, AdapterBase
|
from loops.common import AdapterBase
|
||||||
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
|
||||||
|
|
||||||
# register type interfaces - (TODO: use a function for this)
|
# register type interfaces - (TODO: use a function for this)
|
||||||
|
|
3
query.py
3
query.py
|
@ -32,7 +32,8 @@ from zope.security.proxy import removeSecurityProxy
|
||||||
|
|
||||||
from cybertools.typology.type import BaseType, TypeManager
|
from cybertools.typology.type import BaseType, TypeManager
|
||||||
from loops.interfaces import IConcept
|
from loops.interfaces import IConcept
|
||||||
from loops.type import AdapterBase, TypeInterfaceSourceList
|
from loops.common import AdapterBase
|
||||||
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
|
||||||
_ = MessageFactory('loops')
|
_ = MessageFactory('loops')
|
||||||
|
|
||||||
|
|
127
resource.py
127
resource.py
|
@ -25,13 +25,15 @@ $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.app.file.image import Image
|
||||||
from zope.app.file.interfaces import IFile
|
from zope.app.file.interfaces import IFile
|
||||||
from zope.app.filerepresentation.interfaces import IReadFile, IWriteFile
|
from zope.app.filerepresentation.interfaces import IReadFile, IWriteFile
|
||||||
from zope.app.size.interfaces import ISized
|
from zope.app.size.interfaces import ISized
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
from zope.i18nmessageid import MessageFactory
|
from zope.i18nmessageid import MessageFactory
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
|
from zope import schema
|
||||||
from persistent import Persistent
|
from persistent import Persistent
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
|
||||||
|
@ -39,36 +41,42 @@ from textindexng.interfaces import IIndexableContent
|
||||||
from textindexng.content import IndexContentCollector
|
from textindexng.content import IndexContentCollector
|
||||||
from cybertools.relation.registry import getRelations
|
from cybertools.relation.registry import getRelations
|
||||||
from cybertools.relation.interfaces import IRelatable
|
from cybertools.relation.interfaces import IRelatable
|
||||||
|
from cybertools.typology.interfaces import ITypeManager
|
||||||
|
|
||||||
from interfaces import IBaseResource, IResource
|
from interfaces import IBaseResource, IResource
|
||||||
|
from interfaces import IFile
|
||||||
from interfaces import IDocument, IDocumentSchema, IDocumentView
|
from interfaces import IDocument, IDocumentSchema, IDocumentView
|
||||||
from interfaces import IMediaAsset, IMediaAssetSchema, IMediaAssetView
|
from interfaces import IMediaAsset, IMediaAssetSchema, IMediaAssetView
|
||||||
from interfaces import IFileSystemResource, IControlledResource
|
|
||||||
from interfaces import IResourceManager, IResourceManagerContained
|
from interfaces import IResourceManager, IResourceManagerContained
|
||||||
from interfaces import ILoopsContained
|
from interfaces import ILoopsContained
|
||||||
from interfaces import IIndexAttributes
|
from interfaces import IIndexAttributes
|
||||||
from concept import ResourceRelation
|
from concept import ResourceRelation
|
||||||
|
from common import ResourceAdapterBase
|
||||||
from view import TargetRelation
|
from view import TargetRelation
|
||||||
|
|
||||||
_ = MessageFactory('loops')
|
_ = MessageFactory('loops')
|
||||||
|
|
||||||
|
|
||||||
class Resource(Contained, Persistent):
|
class Resource(Image, Contained):
|
||||||
|
|
||||||
|
implements(IBaseResource, IResource, IResourceManagerContained, IRelatable, ISized)
|
||||||
|
|
||||||
implements(IBaseResource, IResource, IFileSystemResource, IControlledResource,
|
|
||||||
IResourceManagerContained, IRelatable)
|
|
||||||
|
|
||||||
proxyInterface = IMediaAssetView
|
proxyInterface = IMediaAssetView
|
||||||
|
|
||||||
_size = _width = _height = 0
|
_size = _width = _height = 0
|
||||||
|
|
||||||
|
def __init__(self, title=u''):
|
||||||
|
super(Resource, self).__init__()
|
||||||
|
self.title = title
|
||||||
|
|
||||||
def getResourceType(self):
|
def getResourceType(self):
|
||||||
typePred = self.getLoopsRoot().getConceptManager().getTypePredicate()
|
cm = self.getLoopsRoot().getConceptManager()
|
||||||
|
typePred = cm.getTypePredicate()
|
||||||
if typePred is None:
|
if typePred is None:
|
||||||
return None
|
return None
|
||||||
concepts = self.getConcepts([typePred])
|
concepts = self.getConcepts([typePred])
|
||||||
# TODO (?): check for multiple types (->Error)
|
# TODO (?): check for multiple types (->Error)
|
||||||
return concepts and concepts[0] or None
|
return concepts and concepts[0] or cm.get('file', None)
|
||||||
def setResourceType(self, concept):
|
def setResourceType(self, concept):
|
||||||
current = self.getResourceType()
|
current = self.getResourceType()
|
||||||
if current != concept:
|
if current != concept:
|
||||||
|
@ -80,32 +88,32 @@ class Resource(Contained, Persistent):
|
||||||
self.deassignConcept(current, [typePred])
|
self.deassignConcept(current, [typePred])
|
||||||
self.assignConcept(concept, typePred)
|
self.assignConcept(concept, typePred)
|
||||||
resourceType = property(getResourceType, setResourceType)
|
resourceType = property(getResourceType, setResourceType)
|
||||||
|
|
||||||
_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
|
||||||
title = property(getTitle, setTitle)
|
title = property(getTitle, setTitle)
|
||||||
|
|
||||||
_contentType = ''
|
def _setData(self, data):
|
||||||
|
dataFile = StringIO(data) # let File tear it into pieces
|
||||||
|
super(Resource, self)._setData(dataFile)
|
||||||
|
if not self.contentType:
|
||||||
|
self.guessContentType(data)
|
||||||
|
data = property(Image._getData, _setData)
|
||||||
|
|
||||||
|
def guessContentType(self, data):
|
||||||
|
if not isinstance(data, str): # seems to be a file object
|
||||||
|
data = data.read(20)
|
||||||
|
if data.startswith('%PDF'):
|
||||||
|
self.contentType = 'application/pdf'
|
||||||
|
|
||||||
|
_contentType = u''
|
||||||
def setContentType(self, contentType):
|
def setContentType(self, contentType):
|
||||||
if contentType:
|
if contentType:
|
||||||
self._contentType = contentType
|
self._contentType = contentType
|
||||||
def getContentType(self): return self._contentType
|
def getContentType(self): return self._contentType
|
||||||
contentType = property(getContentType, setContentType)
|
contentType = property(getContentType, setContentType)
|
||||||
|
|
||||||
_fsPath = ''
|
|
||||||
def setFsPath(self, fsPath): self._fsPath = fsPath
|
|
||||||
def getFsPath(self): return self._fsPath
|
|
||||||
fsPath = property(getFsPath, setFsPath)
|
|
||||||
|
|
||||||
_readOnly = ''
|
|
||||||
def setReadOnly(self, readOnly): self._readOnly = readOnly
|
|
||||||
def getReadOnly(self): return self._readOnly
|
|
||||||
readOnly = property(getReadOnly, setReadOnly)
|
|
||||||
|
|
||||||
def __init__(self, title=u''):
|
|
||||||
self.title = title
|
|
||||||
|
|
||||||
def getLoopsRoot(self):
|
def getLoopsRoot(self):
|
||||||
return zapi.getParent(self).getLoopsRoot()
|
return zapi.getParent(self).getLoopsRoot()
|
||||||
|
|
||||||
|
@ -122,7 +130,7 @@ class Resource(Contained, Persistent):
|
||||||
relationships = [ResourceRelation(None, self, p) for p in predicates]
|
relationships = [ResourceRelation(None, self, p) for p in predicates]
|
||||||
# TODO: sort...
|
# TODO: sort...
|
||||||
return getRelations(first=concept, second=self, relationships=relationships)
|
return getRelations(first=concept, second=self, relationships=relationships)
|
||||||
|
|
||||||
def getConcepts(self, predicates=None):
|
def getConcepts(self, predicates=None):
|
||||||
return [r.first for r in self.getConceptRelations(predicates)]
|
return [r.first for r in self.getConceptRelations(predicates)]
|
||||||
|
|
||||||
|
@ -132,17 +140,7 @@ class Resource(Contained, Persistent):
|
||||||
def deassignConcept(self, concept, predicates=None):
|
def deassignConcept(self, concept, predicates=None):
|
||||||
concept.deassignResource(self, predicates)
|
concept.deassignResource(self, predicates)
|
||||||
|
|
||||||
|
# ISized interface
|
||||||
class Document(Resource):
|
|
||||||
|
|
||||||
implements(IDocument, ISized)
|
|
||||||
|
|
||||||
proxyInterface = IDocumentView
|
|
||||||
|
|
||||||
_data = u''
|
|
||||||
def setData(self, data): self._data = data
|
|
||||||
def getData(self): return self._data
|
|
||||||
data = property(getData, setData)
|
|
||||||
|
|
||||||
def getSize(self):
|
def getSize(self):
|
||||||
return len(self.data)
|
return len(self.data)
|
||||||
|
@ -154,29 +152,24 @@ class Document(Resource):
|
||||||
return '%i Bytes' % self.getSize()
|
return '%i Bytes' % self.getSize()
|
||||||
|
|
||||||
|
|
||||||
class MediaAsset(Resource, BaseMediaAsset):
|
class Document(Resource):
|
||||||
|
|
||||||
implements(IMediaAsset)
|
implements(IDocument)
|
||||||
|
|
||||||
proxyInterface = IMediaAssetView
|
proxyInterface = IDocumentView
|
||||||
|
|
||||||
def __init__(self, title=u''):
|
def __init__(self, title=u''):
|
||||||
super(MediaAsset, self).__init__()
|
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
||||||
def _setData(self, data):
|
_data = ''
|
||||||
dataFile = StringIO(data) # let File tear it into pieces
|
def setData(self, data): self._data = data
|
||||||
super(MediaAsset, self)._setData(dataFile)
|
def getData(self): return self._data
|
||||||
if not self.contentType:
|
data = property(getData, setData)
|
||||||
self.guessContentType(data)
|
|
||||||
|
|
||||||
data = property(BaseMediaAsset._getData, _setData)
|
|
||||||
|
|
||||||
def guessContentType(self, data):
|
class MediaAsset(Resource):
|
||||||
if not isinstance(data, str): # seems to be a file object
|
|
||||||
data = data.read(20)
|
implements(IMediaAsset)
|
||||||
if data.startswith('%PDF'):
|
|
||||||
self.contentType = 'application/pdf'
|
|
||||||
|
|
||||||
|
|
||||||
class ResourceManager(BTreeContainer):
|
class ResourceManager(BTreeContainer):
|
||||||
|
@ -188,17 +181,19 @@ class ResourceManager(BTreeContainer):
|
||||||
|
|
||||||
def getViewManager(self):
|
def getViewManager(self):
|
||||||
return self.getLoopsRoot().getViewManager()
|
return self.getLoopsRoot().getViewManager()
|
||||||
|
|
||||||
|
|
||||||
# adapters and similar stuff
|
# adapters and similar stuff
|
||||||
|
|
||||||
|
|
||||||
class FileAdapter(object):
|
class FileAdapter(ResourceAdapterBase):
|
||||||
""" A type adapter for providing file functionality for resources.
|
""" A type adapter for providing file functionality for resources.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, context):
|
implements(IFile)
|
||||||
self.context = context
|
|
||||||
|
# TODO: provide specialized access to data attribute analog to zope.app.file;
|
||||||
|
# automatically set contentType...
|
||||||
|
|
||||||
|
|
||||||
class DocumentWriteFileAdapter(object):
|
class DocumentWriteFileAdapter(object):
|
||||||
|
@ -259,3 +254,23 @@ class IndexableResource(object):
|
||||||
icc.addBinary(fields[0], context.data, context.contentType, language='de')
|
icc.addBinary(fields[0], context.data, context.contentType, language='de')
|
||||||
return icc
|
return icc
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceTypeSourceList(object):
|
||||||
|
|
||||||
|
implements(schema.interfaces.IIterableSource)
|
||||||
|
|
||||||
|
def __init__(self, context):
|
||||||
|
self.context = context
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self.resourceTypes)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def resourceTypes(self):
|
||||||
|
types = ITypeManager(self.context).listTypes(include=('resource',))
|
||||||
|
return [t.typeProvider for t in types if t.typeProvider is not None]
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.resourceTypes)
|
||||||
|
|
||||||
|
|
||||||
|
|
64
type.py
64
type.py
|
@ -36,6 +36,7 @@ from loops.interfaces import ITypeConcept
|
||||||
from loops.interfaces import IResourceAdapter, IFile, IImage, ITextDocument
|
from loops.interfaces import IResourceAdapter, IFile, IImage, ITextDocument
|
||||||
from loops.concept import Concept
|
from loops.concept import Concept
|
||||||
from loops.resource import Resource, Document, MediaAsset
|
from loops.resource import Resource, Document, MediaAsset
|
||||||
|
from loops.common import AdapterBase
|
||||||
|
|
||||||
|
|
||||||
class LoopsType(BaseType):
|
class LoopsType(BaseType):
|
||||||
|
@ -65,7 +66,7 @@ class LoopsType(BaseType):
|
||||||
def typeInterface(self):
|
def typeInterface(self):
|
||||||
adapter = zapi.queryAdapter(self.typeProvider, ITypeConcept)
|
adapter = zapi.queryAdapter(self.typeProvider, ITypeConcept)
|
||||||
if adapter is not None:
|
if adapter is not None:
|
||||||
return adapter.typeInterface
|
return removeSecurityProxy(adapter.typeInterface)
|
||||||
else:
|
else:
|
||||||
conceptType = self.typeProvider
|
conceptType = self.typeProvider
|
||||||
typeConcept = self.root.getConceptManager().getTypeConcept()
|
typeConcept = self.root.getConceptManager().getTypeConcept()
|
||||||
|
@ -130,7 +131,7 @@ class ResourceType(LoopsType):
|
||||||
type concepts as is already the case for concepts.
|
type concepts as is already the case for concepts.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
adapts(IResource)
|
#adapts(IResource)
|
||||||
|
|
||||||
typeTitles = {'MediaAsset': u'Media Asset'}
|
typeTitles = {'MediaAsset': u'Media Asset'}
|
||||||
|
|
||||||
|
@ -214,15 +215,13 @@ class LoopsTypeManager(TypeManager):
|
||||||
for cls in (Document, MediaAsset)])
|
for cls in (Document, MediaAsset)])
|
||||||
|
|
||||||
|
|
||||||
class TypeConcept(object):
|
class TypeConcept(AdapterBase):
|
||||||
""" typeInterface adapter for concepts of type 'type'.
|
""" typeInterface adapter for concepts of type 'type'.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
implements(ITypeConcept)
|
implements(ITypeConcept)
|
||||||
adapts(IConcept)
|
|
||||||
|
|
||||||
def __init__(self, context):
|
_schemas = list(ITypeConcept) + list(IConcept)
|
||||||
self.context = removeSecurityProxy(context)
|
|
||||||
|
|
||||||
def getTypeInterface(self):
|
def getTypeInterface(self):
|
||||||
ti = getattr(self.context, '_typeInterface', None)
|
ti = getattr(self.context, '_typeInterface', None)
|
||||||
|
@ -251,56 +250,3 @@ class TypeInterfaceSourceList(object):
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.typeInterfaces)
|
return len(self.typeInterfaces)
|
||||||
|
|
||||||
|
|
||||||
class ResourceTypeSourceList(object):
|
|
||||||
|
|
||||||
implements(schema.interfaces.IIterableSource)
|
|
||||||
|
|
||||||
def __init__(self, context):
|
|
||||||
self.context = context
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return iter(self.resourceTypes)
|
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def resourceTypes(self):
|
|
||||||
types = ITypeManager(self.context).listTypes(include=('resource',))
|
|
||||||
return [t.typeProvider for t in types]
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self.resourceTypes)
|
|
||||||
|
|
||||||
|
|
||||||
class AdapterBase(object):
|
|
||||||
""" (Mix-in) Class for concept adapters that provide editing of fields
|
|
||||||
defined by the type interface.
|
|
||||||
"""
|
|
||||||
|
|
||||||
adapts(IConcept)
|
|
||||||
|
|
||||||
_attributes = ('context', '__parent__', )
|
|
||||||
_schemas = list(IConcept)
|
|
||||||
|
|
||||||
def __init__(self, context):
|
|
||||||
self.context = context # to get the permission stuff right
|
|
||||||
self.__parent__ = context
|
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
|
||||||
self.checkAttr(attr)
|
|
||||||
return getattr(self.context, '_' + attr, None)
|
|
||||||
|
|
||||||
def __setattr__(self, attr, value):
|
|
||||||
if attr in self._attributes:
|
|
||||||
object.__setattr__(self, attr, value)
|
|
||||||
else:
|
|
||||||
self.checkAttr(attr)
|
|
||||||
setattr(self.context, '_' + attr, value)
|
|
||||||
|
|
||||||
def checkAttr(self, attr):
|
|
||||||
if attr not in self._schemas:
|
|
||||||
raise AttributeError(attr)
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self.context == other.context
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue