diff --git a/browser/resource_macros.pt b/browser/resource_macros.pt index 74d2e45..27c35f6 100644 --- a/browser/resource_macros.pt +++ b/browser/resource_macros.pt @@ -42,11 +42,11 @@
-

Title


+

Title


-

Description

+

Description

@@ -55,8 +55,8 @@
-

Title

-

Description

+

Title

+

Description 

+ + + + + + @@ -353,6 +362,8 @@ + diff --git a/interfaces.py b/interfaces.py index f82aaee..fedbb28 100644 --- a/interfaces.py +++ b/interfaces.py @@ -752,7 +752,6 @@ class IStorageInfo(Interface): class IExternalFile(IFile): -#class IExternalFile(IFile, IStorageInfo): """ A file whose content (data attribute) is not stored in the ZODB but somewhere else, typically in the file system. """ @@ -764,18 +763,26 @@ class IExternalFile(IFile): missing_value='', required=False) - #externalAddress = schema.BytesLine( - # title=_(u'External Address'), - # description=_(u'The full address for accessing the object ' - # 'on the external storage, e.g. a filename or path.'), - # default='', - # missing_value='', - # required=False) - externalAddress = Attribute('The full address for accessing the object ' 'on the external storage, e.g. a filename or path.') +class IAddressableExternalFile(IExternalFile): + """ A file whose content (data attribute) is not stored in the ZODB + but somewhere else, typically in the file system; the data won't + be provided by uploading a file but by explicitly specifying + the address of the file. + """ + + externalAddress = schema.BytesLine( + title=_(u'External Address'), + description=_(u'The full address for accessing the object ' + 'on the external storage, e.g. a filename or path.'), + default='', + missing_value='', + required=False) + + class IImage(IResourceAdapter): """ A media asset that may be embedded in a (web) page as an image. """ diff --git a/resource.py b/resource.py index 6ab2838..9cbbbb6 100644 --- a/resource.py +++ b/resource.py @@ -30,6 +30,7 @@ from zope.app.container.btree import BTreeContainer from zope.app.container.contained import Contained from zope.app.file.image import Image from zope.app.security.interfaces import IAuthentication +from zope.contenttype import guess_content_type from zope.filerepresentation.interfaces import IReadFile, IWriteFile from zope.cachedescriptors.property import Lazy from zope.component import adapts @@ -53,7 +54,7 @@ from loops.base import ParentInfo from loops.common import ResourceAdapterBase, adapted from loops.concept import ResourceRelation from loops.interfaces import IBaseResource, IResource -from loops.interfaces import IFile, IExternalFile, INote +from loops.interfaces import IFile, IExternalFile, IAddressableExternalFile, INote from loops.interfaces import IDocument, ITextDocument, IDocumentSchema, IDocumentView from loops.interfaces import IMediaAsset, IMediaAssetView from loops.interfaces import IResourceManager, IResourceManagerContained @@ -387,6 +388,19 @@ class ExternalFileAdapter(FileAdapter): data = property(getData, setData) +class AddressableExternalFileAdapter(ExternalFileAdapter): + + implements(IAddressableExternalFile) + + def setExternalAddress(self, addr): + super(AddressableExternalFileAdapter, self).setExternalAddress(addr) + contentType = guess_content_type(self.externalAddress, self.data[:100]) + if contentType: + self.contentType = contentType[0] + externalAddress = property(ExternalFileAdapter.getExternalAddress, + setExternalAddress) + + class DocumentAdapter(ResourceAdapterBase): """ Common base class for all resource types with a text-like data attribute. diff --git a/schema/factory.py b/schema/factory.py index 33697af..9df0f6d 100644 --- a/schema/factory.py +++ b/schema/factory.py @@ -25,7 +25,7 @@ $Id$ from zope.component import adapts from cybertools.composer.schema.factory import SchemaFactory -from loops.interfaces import IResourceAdapter, IFile, INote +from loops.interfaces import IResourceAdapter, IFile, INote, IAddressableExternalFile class ResourceSchemaFactory(SchemaFactory): @@ -54,6 +54,17 @@ class FileSchemaFactory(SchemaFactory): return schema +class AddressableFileSchemaFactory(SchemaFactory): + + adapts(IAddressableExternalFile) + + def __call__(self, interface, **kw): + schema = super(AddressableFileSchemaFactory, self).__call__(interface, **kw) + schema.fields.remove('data') + #schema.fields.remove('contentType') + return schema + + class NoteSchemaFactory(SchemaFactory): adapts(INote) diff --git a/type.py b/type.py index 4e5f783..f83c492 100644 --- a/type.py +++ b/type.py @@ -34,7 +34,8 @@ from cybertools.typology.type import BaseType, TypeManager from cybertools.typology.interfaces import ITypeManager from loops.interfaces import ILoopsObject, IConcept, IResource from loops.interfaces import ITypeConcept -from loops.interfaces import IResourceAdapter, IFile, IExternalFile, IImage +from loops.interfaces import IResourceAdapter, IFile, IExternalFile, \ + IAddressableExternalFile, IImage from loops.interfaces import ITextDocument, INote from loops.concept import Concept from loops.resource import Resource, Document, MediaAsset @@ -272,7 +273,8 @@ class TypeInterfaceSourceList(object): implements(schema.interfaces.IIterableSource) - typeInterfaces = (ITypeConcept, IFile, IExternalFile, ITextDocument, INote) + typeInterfaces = (ITypeConcept, IFile, IExternalFile, IAddressableExternalFile, + ITextDocument, INote) def __init__(self, context): self.context = context