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

@ -230,7 +230,7 @@ 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:
@ -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:
@ -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',

View file

@ -201,7 +201,8 @@ class LoopsTerms(object):
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)

View file

@ -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"

View file

@ -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

View file

@ -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,7 +159,9 @@ 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']

View file

@ -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)

View file

@ -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"
/> />

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.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
@ -178,7 +179,7 @@ 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.
@ -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.
@ -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.
@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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,)

View file

@ -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)

View file

@ -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')

View file

@ -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, IFileSystemResource, IControlledResource, implements(IBaseResource, IResource, IResourceManagerContained, IRelatable, ISized)
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:
@ -86,26 +94,26 @@ class Resource(Contained, Persistent):
def setTitle(self, title): self._title = title def setTitle(self, title): self._title = title
title = property(getTitle, setTitle) title = property(getTitle, setTitle)
_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()
@ -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):
@ -193,12 +186,14 @@ class ResourceManager(BTreeContainer):
# 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
View file

@ -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