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
				
			
		
							
								
								
									
										10
									
								
								README.txt
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								README.txt
									
										
									
									
									
								
							|  | @ -230,7 +230,7 @@ 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: | ||||
| 
 | ||||
|  | @ -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: | ||||
| 
 | ||||
|  | @ -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', | ||||
|  |  | |||
|  | @ -201,7 +201,8 @@ class LoopsTerms(object): | |||
|         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) | ||||
|  |  | |||
|  | @ -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" | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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,7 +159,9 @@ 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'] | ||||
|  |  | |||
							
								
								
									
										47
									
								
								common.py
									
										
									
									
									
								
							
							
						
						
									
										47
									
								
								common.py
									
										
									
									
									
								
							|  | @ -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) | ||||
|  |  | |||
|  | @ -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" | ||||
|       /> | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  | @ -178,7 +179,7 @@ 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. | ||||
|  | @ -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. | ||||
|  | @ -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. | ||||
|  | @ -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) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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,) | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
							
								
								
									
										3
									
								
								query.py
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								query.py
									
										
									
									
									
								
							|  | @ -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') | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										115
									
								
								resource.py
									
										
									
									
									
								
							
							
						
						
									
										115
									
								
								resource.py
									
										
									
									
									
								
							|  | @ -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, IFileSystemResource, IControlledResource, | ||||
|                IResourceManagerContained, IRelatable) | ||||
|     implements(IBaseResource, IResource, IResourceManagerContained, IRelatable, ISized) | ||||
| 
 | ||||
|     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: | ||||
|  | @ -86,26 +94,26 @@ class Resource(Contained, Persistent): | |||
|     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() | ||||
| 
 | ||||
|  | @ -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): | ||||
|  | @ -193,12 +186,14 @@ class ResourceManager(BTreeContainer): | |||
| # 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
									
										
									
									
									
								
							
							
						
						
									
										64
									
								
								type.py
									
										
									
									
									
								
							|  | @ -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 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 helmutm
						helmutm