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:
helmutm 2006-08-07 13:13:31 +00:00
parent 89ae9aeab0
commit e860cf5a07
16 changed files with 349 additions and 298 deletions

View file

@ -17,12 +17,12 @@ with lower-level aspects like type or state management.
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
>>> site = placefulSetUp(True)
>>> from zope.app import zapi
>>> from zope.app.tests import ztapi
>>> from zope.interface import Interface
>>> from zope.publisher.browser import TestRequest
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
ConceptRelation):
>>> cc1.assignChild(cc2)
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
also the relationship to the context object using a combination
of URIs to item and the predicate of the relationship:
>>> [c.token for c in children]
['.loops/concepts/cc2:.loops/concepts/standard']
@ -207,11 +207,11 @@ types and predicates.
>>> from zope.schema.interfaces import IIterableSource
>>> ztapi.provideAdapter(IIterableSource, ITerms, LoopsTerms,
... with=(IBrowserRequest,))
>>> sorted((t.title, t.token) for t in view.conceptTypes())
[(u'Topic', '.loops/concepts/topic'), (u'Type', '.loops/concepts/type'),
(u'Unknown Type', '.loops/concepts/unknown')]
>>> sorted((t.title, t.token) for t in view.predicates())
[(u'subconcept', '.loops/concepts/standard')]
@ -222,7 +222,7 @@ Index attributes adapter
>>> idx = IndexAttributes(cc2)
>>> idx.text()
u'cc2 Zope 3'
>>> idx.title()
u'cc2 Zope 3'
@ -230,16 +230,16 @@ Index attributes adapter
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:
>>> from loops.resource import ResourceManager
>>> loopsRoot['resources'] = ResourceManager()
>>> resources = loopsRoot['resources']
A common type of resource is a document:
>>> from loops.interfaces import IDocument
>>> from loops.resource import Document
>>> doc1 = Document(u'Zope Info')
@ -247,9 +247,9 @@ A common type of resource is a document:
>>> doc1.title
u'Zope Info'
>>> doc1.data
u''
>>> doc1.contentType
''
>>> doc1.contentType
u''
Another one is a media asset:
@ -258,7 +258,7 @@ Another one is a media asset:
>>> img = MediaAsset(u'A png Image')
For testing we use some simple files from the tests directory:
>>> from loops import tests
>>> import os
>>> 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:
>>> from loops.browser.resource import ResourceConfigureView
Index attributes adapter
------------------------
@ -320,7 +320,7 @@ Index attributes adapter
>>> idx = IndexAttributes(doc1)
>>> idx.text()
u'doc1 Zope Info'
>>> idx.title()
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.
We first need a view manager:
>>> from loops.view import ViewManager, Node
>>> from zope.security.checker import NamesChecker, defineChecker
>>> 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
menu that may contain other nodes as menu or content items:
>>> m1 = Node(u'Menu')
>>> views['m1'] = m1
>>> m11 = Node(u'Zope')
@ -426,7 +426,7 @@ out - this is usually done through ZCML.)
>>> from cybertools.relation.interfaces import IRelationInvalidatedEvent
>>> ztapi.subscribe([ITargetRelation, IRelationInvalidatedEvent], None,
... removeTargetRelation)
>>> m111.target = cc1
>>> m111.target is cc1
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:
>>> 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,
... with=(IBrowserRequest,))
>>> ztapi.provideAdapter(IMediaAsset, Interface, MediaAssetView,
>>> ztapi.provideAdapter(IResource, Interface, ResourceView,
... with=(IBrowserRequest,))
>>> form = {'action': 'create', 'create.title': 'New Resource',
@ -592,10 +592,10 @@ Let's add some more nodes and reorder them:
>>> m11['m114'] = m114
>>> m11.keys()
['m111', 'm112', 'm113', 'm114']
A special management view provides methods for moving objects down, up,
to the bottom, and to the top.
>>> from cybertools.container.ordered import OrderedContainerView
>>> view = OrderedContainerView(m11, TestRequest())
>>> view.move_bottom(('m113',))
@ -641,7 +641,7 @@ instance to another.
>>> exporter.dumpData()
Load them again from the exported file:
>>> importer = NodesImporter(views)
>>> importer.filename = dumpname
>>> imported = importer.getData()

View file

@ -117,7 +117,7 @@ class BaseView(object):
@Lazy
def loopsRoot(self):
return self.context.getLoopsRoot()
@Lazy
def url(self):
return zapi.absoluteURL(self.context, self.request)
@ -199,9 +199,10 @@ class LoopsTerms(object):
@Lazy
def loopsRoot(self):
return self.context.getLoopsRoot()
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)
token = self.loopsRoot.getLoopsUri(value)
return SimpleTerm(value, token, title)

View file

@ -66,14 +66,14 @@ class ConceptEditForm(EditForm):
class ConceptView(BaseView):
template = NamedTemplate('loops.concept_macros')
@Lazy
def macro(self):
return self.template.macros['conceptdata']
def fieldData(self):
ti = IType(self.context).typeInterface
if not ti: return
if not ti: return
adapter = ti(self.context)
for n, f in schema.getFieldsInOrder(ti):
value = getattr(adapter, n, '')

View file

@ -233,6 +233,21 @@
<!-- 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
for="loops.interfaces.IResource"
class=".resource.ResourceConfigureView"
@ -246,12 +261,19 @@
</pages>
<zope:adapter
for="loops.interfaces.IResource
zope.publisher.interfaces.browser.IBrowserRequest"
provides="zope.interface.Interface"
factory="loops.browser.resource.ResourceView"
permission="zope.View"
<page
name="edit.html"
for="loops.interfaces.IResource"
class="loops.browser.resource.ResourceEditForm"
permission="zope.ManageContent"
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 -->
@ -263,33 +285,6 @@
class=".resource.DocumentView"
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
name="edit.html"
for="loops.interfaces.IDocument"
@ -322,25 +317,7 @@
<!-- media asset -->
<addform
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
<!--<editform
label="Edit Media Asset"
name="edit.html"
schema="loops.interfaces.IMediaAssetSchema"
@ -349,7 +326,7 @@
template="edit.pt"
permission="zope.ManageContent"
menu="zmi_views" title="Edit Media Asset"
/>
/>-->
<!--<page
name="edit.html"
@ -359,21 +336,6 @@
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 -->
<addform
@ -584,6 +546,10 @@
for="loops.type.TypeInterfaceSourceList
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"
for="loops.interfaces.INode"
type="zope.publisher.interfaces.browser.IBrowserRequest"

View file

@ -204,7 +204,7 @@ class NodeView(BaseView):
def active(self, item):
return item.context == self.context or item.context in self.parents
def targetDefaultView(self):
target = self.request.annotations.get('loops.view', {}).get('target')
if target is None:
@ -250,7 +250,7 @@ class ConfigureView(NodeView):
obj = self.targetObject
if obj is not None:
return zapi.getMultiAdapter((obj, self.request))
def update(self):
request = self.request
action = request.get('action')
@ -291,6 +291,8 @@ class ConfigureView(NodeView):
target.title = form.get('create.title', u'')
if IConcept.providedBy(target):
target.conceptType = type.typeProvider
elif IResource.providedBy(target):
target.resourceType = type.typeProvider
notify(ObjectCreatedEvent(target))
notify(ObjectModifiedEvent(target))
self.context.target = target

View file

@ -33,8 +33,8 @@ from zope.proxy import removeAllProxies
from zope.security import canAccess, canWrite
from zope.security.proxy import removeSecurityProxy
from loops.interfaces import IDocument, IMediaAsset
from loops.interfaces import IFileSystemResource, IControlledResource
from cybertools.typology.interfaces import IType
from loops.interfaces import IBaseResource, IDocument, IMediaAsset
from loops.browser.common import EditForm, BaseView
from loops.browser.concept import ConceptRelationView, ConceptConfigureView
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):
#form_fields = FormFields(IDocument, IFileSystemResource, IControlledResource)
form_fields = FormFields(IDocument)
for f in form_fields:
f.render_context |= DISPLAY_UNWRITEABLE
class MediaAssetEditForm(EditForm):
form_fields = FormFields(IMediaAsset)
@ -62,6 +77,20 @@ class ResourceView(BaseView):
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):
for r in self.context.getConceptRelations():
yield ConceptRelationView(r, self.request)
@ -130,8 +159,10 @@ class ResourceConfigureView(ResourceView, ConceptConfigureView):
class DocumentView(ResourceView):
macro = ResourceView.template.macros['render']
@property
def macro(self):
return ResourceView.template.macros['render']
def render(self):
""" Return the rendered content (data) of the context object.
"""
@ -143,19 +174,3 @@ class DocumentView(ResourceView):
view = zapi.getMultiAdapter((removeAllProxies(source), self.request))
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']

View file

@ -29,9 +29,54 @@ from zope.app.dublincore.zopedublincore import ScalarProperty
from zope.component import adapts
from zope.interface import implements
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):
implements(IZopeDublinCore)

View file

@ -125,6 +125,30 @@
</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=".interfaces.IDocument"
type="zope.app.content.interfaces.IContentType" />
@ -141,19 +165,12 @@
<require
permission="zope.View"
interface=".interfaces.IDocument
.interfaces.IFileSystemResource
.interfaces.IControlledResource
zope.app.size.interfaces.ISized" />
<require
permission="zope.ManageContent"
set_schema=".interfaces.IDocument" />
<require
permission="zope.ManageApplication"
set_schema=".interfaces.IFileSystemResource
.interfaces.IControlledResource" />
</content>
<interface
@ -171,11 +188,11 @@
<require
permission="zope.View"
interface=".interfaces.IMediaAsset" />
interface=".interfaces.IBaseResource" />
<require
permission="zope.ManageContent"
set_schema=".interfaces.IMediaAsset" />
set_schema=".interfaces.IBaseResource" />
</content>
@ -249,12 +266,7 @@
trusted="True" />
<adapter factory="loops.common.LoopsDCAdapter"
for="loops.interfaces.IDocument"
provides="zope.app.dublincore.interfaces.IZopeDublinCore"
trusted="True" />
<adapter factory="loops.common.LoopsDCAdapter"
for="loops.interfaces.IMediaAsset"
for="loops.interfaces.IResource"
provides="zope.app.dublincore.interfaces.IZopeDublinCore"
trusted="True" />
@ -264,16 +276,30 @@
<adapter factory="loops.concept.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.DocumentWriteFileAdapter" />
<adapter factory="loops.type.LoopsType" />
<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.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" />
<class class="loops.query.QueryConcept">
@ -283,6 +309,14 @@
set_schema="loops.query.IQueryConcept" />
</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.external.NodesLoader" />
@ -302,7 +336,7 @@
/>
<vocabulary
factory="loops.type.ResourceTypeSourceList"
factory="loops.resource.ResourceTypeSourceList"
name="loops.resourceTypeSource"
/>

View file

@ -29,6 +29,7 @@ from zope.app.container.constraints import contains, containers
from zope.app.container.interfaces import IContainer, IOrderedContainer
from zope.app.file.interfaces import IImage as IBaseAsset
from zope.app.folder.interfaces import IFolder
from zope.app.size.interfaces import ISized
from cybertools.relation.interfaces import IRelation
import util
@ -62,7 +63,7 @@ class IPotentialTarget(Interface):
class IConcept(ILoopsObject, IPotentialTarget):
""" The concept is the central element of the loops framework.
A concept is related to other concepts, may have resources
associated with it and may be referenced by views.
"""
@ -130,7 +131,7 @@ class IConcept(ILoopsObject, IPotentialTarget):
def getResources(predicates=None):
""" Return a sequence of resources assigned to self,
optionally restricted to the predicates given.
"""
"""
def getResourceRelations(predicates=None, resource=None):
""" Return a sequence of relations to resources assigned to self,
@ -143,12 +144,12 @@ class IConcept(ILoopsObject, IPotentialTarget):
The relationship defaults to ConceptResourceRelation.
"""
def deassignResource(resource, predicates=None):
""" Remove the relations to the resource given from self, optionally
restricting them to the predicates given.
"""
class IConceptView(Interface):
""" Used for accessing a concept via a node's target attribute"""
@ -178,12 +179,12 @@ class IConceptManagerContained(Interface):
# resource interfaces
class IBaseResource(Interface):
class IBaseResource(ILoopsObject):
""" New base interface for resources. Functionality beyond this simple
interface is provided by adapters that are chosen via the
resource type's typeInterface.
"""
title = schema.TextLine(
title=_(u'Title'),
description=_(u'Title of the resource'),
@ -199,6 +200,26 @@ class IBaseResource(Interface):
source="loops.resourceTypeSource",
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):
@ -224,29 +245,6 @@ class IResourceSchema(Interface):
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):
""" A resource is an atomic information element that is made
available via a view or a concept.
@ -323,10 +321,10 @@ class IMediaAssetView(IMediaAssetSchema):
class IMediaAsset(IMediaAssetSchema, IResource, IBaseAsset):
""" A resource containing a (typically binary) file-like content
or an image.
or an image.
"""
class IResourceManager(ILoopsObject, IContainer):
""" A manager/container for resources.
"""
@ -475,7 +473,7 @@ class ILoops(ILoopsObject):
""" Retrieve object specified by the loops uri (starting with
'.loops/') given.
"""
def getConceptManager():
""" Return the (default) concept manager.
"""
@ -545,7 +543,7 @@ class ITypeConcept(Interface):
# storage = schema.Choice()
class IResourceAdapter(Interface):
class IResourceAdapter(IBaseResourceSchema):
""" Base interface for adapters for resources. This is the base interface
of the interfaces to be used as typeInterface attribute on type concepts
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
may be downloaded instead.
"""
class IImage(IResourceAdapter):
""" A media asset that may be embedded in a (web) page as an image.
"""
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
(like e.g. OpenOffice); typical content types are text/html, text/xml,
text/restructured, etc.
@ -581,3 +579,27 @@ class IViewConfiguratorSchema(Interface):
default=u'',
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)

View file

@ -36,7 +36,8 @@ from loops.interfaces import IConcept, IResource
from loops.knowledge.interfaces import IPerson, ITask
from loops.organize.party import Person as BasePerson
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)

View file

@ -41,7 +41,8 @@ from cybertools.typology.interfaces import IType
from loops.concept import Concept
from loops.interfaces import IConcept
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)

View file

@ -26,7 +26,8 @@ from zope.interface import implements
from cybertools.organize.interfaces import ITask
from loops.interfaces import IConcept
from loops.type import TypeInterfaceSourceList, AdapterBase
from loops.common import AdapterBase
from loops.type import TypeInterfaceSourceList
TypeInterfaceSourceList.typeInterfaces += (ITask,)

View file

@ -33,7 +33,8 @@ from cybertools.typology.interfaces import IType
from cybertools.process.interfaces import IProcess
from cybertools.process.definition import Process as BaseProcess
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)

View file

@ -32,7 +32,8 @@ from zope.security.proxy import removeSecurityProxy
from cybertools.typology.type import BaseType, TypeManager
from loops.interfaces import IConcept
from loops.type import AdapterBase, TypeInterfaceSourceList
from loops.common import AdapterBase
from loops.type import TypeInterfaceSourceList
_ = MessageFactory('loops')

View file

@ -25,13 +25,15 @@ $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.app.file.image import Image
from zope.app.file.interfaces import IFile
from zope.app.filerepresentation.interfaces import IReadFile, IWriteFile
from zope.app.size.interfaces import ISized
from zope.cachedescriptors.property import Lazy
from zope.component import adapts
from zope.i18nmessageid import MessageFactory
from zope.interface import implements
from zope import schema
from persistent import Persistent
from cStringIO import StringIO
@ -39,36 +41,42 @@ from textindexng.interfaces import IIndexableContent
from textindexng.content import IndexContentCollector
from cybertools.relation.registry import getRelations
from cybertools.relation.interfaces import IRelatable
from cybertools.typology.interfaces import ITypeManager
from interfaces import IBaseResource, IResource
from interfaces import IFile
from interfaces import IDocument, IDocumentSchema, IDocumentView
from interfaces import IMediaAsset, IMediaAssetSchema, IMediaAssetView
from interfaces import IFileSystemResource, IControlledResource
from interfaces import IResourceManager, IResourceManagerContained
from interfaces import ILoopsContained
from interfaces import IIndexAttributes
from concept import ResourceRelation
from common import ResourceAdapterBase
from view import TargetRelation
_ = 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
_size = _width = _height = 0
def __init__(self, title=u''):
super(Resource, self).__init__()
self.title = title
def getResourceType(self):
typePred = self.getLoopsRoot().getConceptManager().getTypePredicate()
cm = self.getLoopsRoot().getConceptManager()
typePred = cm.getTypePredicate()
if typePred is None:
return None
concepts = self.getConcepts([typePred])
# 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):
current = self.getResourceType()
if current != concept:
@ -80,32 +88,32 @@ class Resource(Contained, Persistent):
self.deassignConcept(current, [typePred])
self.assignConcept(concept, typePred)
resourceType = property(getResourceType, setResourceType)
_title = u''
def getTitle(self): return self._title
def setTitle(self, title): self._title = title
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):
if contentType:
self._contentType = contentType
def getContentType(self): return self._contentType
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):
return zapi.getParent(self).getLoopsRoot()
@ -122,7 +130,7 @@ class Resource(Contained, Persistent):
relationships = [ResourceRelation(None, self, p) for p in predicates]
# TODO: sort...
return getRelations(first=concept, second=self, relationships=relationships)
def getConcepts(self, predicates=None):
return [r.first for r in self.getConceptRelations(predicates)]
@ -132,17 +140,7 @@ class Resource(Contained, Persistent):
def deassignConcept(self, concept, predicates=None):
concept.deassignResource(self, predicates)
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)
# ISized interface
def getSize(self):
return len(self.data)
@ -154,29 +152,24 @@ class Document(Resource):
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''):
super(MediaAsset, self).__init__()
self.title = title
def _setData(self, data):
dataFile = StringIO(data) # let File tear it into pieces
super(MediaAsset, self)._setData(dataFile)
if not self.contentType:
self.guessContentType(data)
_data = ''
def setData(self, data): self._data = data
def getData(self): return self._data
data = property(getData, setData)
data = property(BaseMediaAsset._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'
class MediaAsset(Resource):
implements(IMediaAsset)
class ResourceManager(BTreeContainer):
@ -188,17 +181,19 @@ class ResourceManager(BTreeContainer):
def getViewManager(self):
return self.getLoopsRoot().getViewManager()
# adapters and similar stuff
class FileAdapter(object):
class FileAdapter(ResourceAdapterBase):
""" A type adapter for providing file functionality for resources.
"""
def __init__(self, context):
self.context = context
implements(IFile)
# TODO: provide specialized access to data attribute analog to zope.app.file;
# automatically set contentType...
class DocumentWriteFileAdapter(object):
@ -259,3 +254,23 @@ class IndexableResource(object):
icc.addBinary(fields[0], context.data, context.contentType, language='de')
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
View file

@ -36,6 +36,7 @@ from loops.interfaces import ITypeConcept
from loops.interfaces import IResourceAdapter, IFile, IImage, ITextDocument
from loops.concept import Concept
from loops.resource import Resource, Document, MediaAsset
from loops.common import AdapterBase
class LoopsType(BaseType):
@ -65,7 +66,7 @@ class LoopsType(BaseType):
def typeInterface(self):
adapter = zapi.queryAdapter(self.typeProvider, ITypeConcept)
if adapter is not None:
return adapter.typeInterface
return removeSecurityProxy(adapter.typeInterface)
else:
conceptType = self.typeProvider
typeConcept = self.root.getConceptManager().getTypeConcept()
@ -130,7 +131,7 @@ class ResourceType(LoopsType):
type concepts as is already the case for concepts.
"""
adapts(IResource)
#adapts(IResource)
typeTitles = {'MediaAsset': u'Media Asset'}
@ -214,15 +215,13 @@ class LoopsTypeManager(TypeManager):
for cls in (Document, MediaAsset)])
class TypeConcept(object):
class TypeConcept(AdapterBase):
""" typeInterface adapter for concepts of type 'type'.
"""
implements(ITypeConcept)
adapts(IConcept)
def __init__(self, context):
self.context = removeSecurityProxy(context)
_schemas = list(ITypeConcept) + list(IConcept)
def getTypeInterface(self):
ti = getattr(self.context, '_typeInterface', None)
@ -251,56 +250,3 @@ class TypeInterfaceSourceList(object):
def __len__(self):
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