open up media asset type for all kinds of external files

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3205 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2009-02-05 10:29:01 +00:00
parent b3962aba0e
commit 1c1147cda9
13 changed files with 332 additions and 16 deletions

View file

@ -403,6 +403,10 @@ class BaseView(GenericView, I18NView):
def globalOptions(self): def globalOptions(self):
return IOptions(self.loopsRoot) return IOptions(self.loopsRoot)
@Lazy
def typeOptions(self):
return IOptions(adapted(self.typeProvider))
# versioning # versioning
@Lazy @Lazy

View file

@ -140,9 +140,16 @@
<containerViews <containerViews
for="loops.interfaces.IConceptManager" for="loops.interfaces.IConceptManager"
index="loops.ManageSite" index="loops.ManageSite"
contents="loops.ManageSite"
add="loops.ManageSite" /> add="loops.ManageSite" />
<page
for="loops.interfaces.IConceptManager"
name="contents.html"
template="contents.pt"
class="cybertools.container.ordered.ContainerView"
permission="loops.ManageSite"
menu="zmi_views" title="Contents" />
<!-- concept --> <!-- concept -->
<addform <addform
@ -237,15 +244,21 @@
schema="loops.interfaces.IResourceManager" schema="loops.interfaces.IResourceManager"
content_factory="loops.resource.ResourceManager" content_factory="loops.resource.ResourceManager"
template="add.pt" template="add.pt"
permission="zope.ManageContent" permission="zope.ManageContent" />
/>
<containerViews <containerViews
for="loops.interfaces.IResourceManager" for="loops.interfaces.IResourceManager"
index="loops.ManageSite" index="loops.ManageSite"
contents="loops.ManageSite"
add="loops.ManageSite" /> add="loops.ManageSite" />
<page
for="loops.interfaces.IResourceManager"
name="contents.html"
template="contents.pt"
class="cybertools.container.ordered.ContainerView"
permission="loops.ManageSite"
menu="zmi_views" title="Contents" />
<!-- resource in general --> <!-- resource in general -->
<page <page

234
browser/contents.pt Normal file
View file

@ -0,0 +1,234 @@
<html metal:use-macro="context/@@standard_macros/view"
i18n:domain="zope">
<body>
<metal:ecmascript fill-slot="ecmascript_slot">
<metal:use use-macro="views/ajax.dojo/main" />
</metal:ecmascript>
<div metal:fill-slot="body">
<div metal:define-macro="contents"
id="body.contents">
<tal:checkmove define="dummy view/checkMoveAction">
<form name="contents" method="post" action="."
tal:attributes="action request/URL"
tal:define="container_contents view/listContentInfo">
<metal:keep-batch define-macro="keep_batch_params">
<tal:param repeat="param python:('b_page', 'b_size', 'b_overlap', 'b_orphan')">
<input type="hidden"
tal:define="value request/?param|nothing"
tal:condition="value"
tal:attributes="name param;
value value" />
</tal:param>
</metal:keep-batch>
<input type="hidden" name="type_name" value=""
tal:attributes="value request/type_name"
tal:condition="request/type_name|nothing" />
<input type="hidden" name="retitle_id" value=""
tal:attributes="value request/retitle_id"
tal:condition="request/retitle_id|nothing" />
<div class="page_error"
tal:condition="view/error"
tal:content="view/error"
i18n:translate="">
Error message
</div>
<table id="sortable" class="listing" summary="Content listing"
i18n:attributes="summary">
<thead>
<tr>
<th style="margin:0; padding:0">
<input type="checkbox" class="noborder" title="Select all items"
i18n:attributes="title"
onclick="f = document.forms.contents['ids:list'];
for (i in f) f[i].checked=this.checked;" /></th>
<th i18n:translate="">Name</th>
<th i18n:translate="">Title</th>
<th i18n:translate="">Size</th>
<th i18n:translate="">Created</th>
<th i18n:translate="">Modified</th>
</tr>
</thead>
<tbody>
<metal:block tal:condition="view/hasAdding">
<tr tal:define="names_required context/@@+/nameAllowed"
tal:condition="python:names_required and request.has_key('type_name')">
<td></td>
<td><input name="new_value" id="focusid" value="" /></td>
<td></td><td></td><td></td>
</tr>
</metal:block>
<metal:block tal:define="supportsRename view/supportsRename;
batch nocall:context/@@cybertools.reporter.batch;
batch python:batch.setup(container_contents)">
<tal:list repeat="item batch/items">
<tr tal:define="oddrow repeat/item/odd;
url item/url;
id_quoted item/id/url:quote"
tal:attributes="class python:oddrow and 'even' or 'odd'" >
<td>
<input type="checkbox" class="noborder" name="ids:list"
tal:attributes="value item/id;
id item/cb_id;
checked request/ids_checked|nothing;"/>
</td>
<td>
<a href="#"
tal:attributes="href string:${url}/@@SelectedManagementView.html"
tal:content="structure item/icon|default"></a>
<span tal:condition="item/rename">
<input name="new_value:list"
tal:attributes="value item/id"/>
<input type="hidden" name="rename_ids:list" value=""
tal:attributes="value item/rename" />
</span>
<span tal:condition="not:item/rename">
<a href="#"
tal:attributes="href
string:${url}/@@SelectedManagementView.html"
tal:content="item/id">foo</a>
</span>
</td>
<td>
<a href="#"
tal:attributes="href string:${url}/@@SelectedManagementView.html"
tal:content="item/title|default">Title</a>
</td>
<td><span tal:content="item/size/sizeForDisplay|nothing"
i18n:translate="">
&nbsp;</span></td>
<td><span tal:define="created item/created|default"
tal:content="created"
i18n:translate="">&nbsp;</span></td>
<td><span tal:define="modified item/modified|default"
tal:content="modified"
i18n:translate="">&nbsp;</span></td>
</tr>
</tal:list>
<metal:nav define-macro="batch_navigation_tr">
<tr class="batch_navigation"
style="border-top: 1px solid #ccc"
tal:condition="batch/showNavigation">
<td colspan="6"
style="text-align: center">
Pages:
<metal:nav define-macro="batch_navigation"
tal:define="first batch/first/title;
previous batch/previous/title;
current batch/current/title;
next batch/next/title;
last batch/last/title;">
<a href="#"
tal:attributes="href batch/first/url;"
tal:content="first"
tal:condition="python: first != current">1</a>
<span tal:condition="python: first &lt; previous-1">...</span>
<a href="#"
tal:attributes="href batch/previous/url;"
tal:content="batch/previous/title"
tal:condition="python: first != previous and previous != current">2</a>
<b tal:content="batch/current/title">3</b>
<a href="#"
tal:attributes="href batch/next/url;"
tal:content="batch/next/title"
tal:condition="python: last != next and next != current">3</a>
<span tal:condition="python: last > next+1">...</span>
<a href="#"
tal:attributes="href batch/last/url;"
tal:content="batch/last/title"
tal:condition="python: last != current">5</a>
</metal:nav>
</td>
</tr>
</metal:nav>
</metal:block>
</tbody>
</table>
<div tal:condition="view/normalButtons">
<input type="submit" name="container_rename_button" value="Rename"
i18n:attributes="value container-rename-button"
tal:condition="view/supportsRename" />
<input type="submit" name="container_cut_button" value="Cut"
i18n:attributes="value container-cut-button"
tal:condition="view/supportsCut" />
<input type="submit" name="container_copy_button" value="Copy"
i18n:attributes="value container-copy-button"
tal:condition="view/supportsCopy" />
<input type="submit" name="container_paste_button" value="Paste"
tal:condition="view/hasClipboardContents"
i18n:attributes="value container-paste-button" />
<input type="submit" name="container_delete_button" value="Delete"
i18n:attributes="value container-delete-button"
tal:condition="view/supportsDelete"
i18n:domain="zope" />
<div tal:condition="view/hasAdding" tal:omit-tag="">
<div tal:omit-tag=""
tal:define="adding nocall:context/@@+;
addingInfo adding/addingInfo;
has_custom_add_view adding/hasCustomAddView;
names_required adding/nameAllowed"
tal:condition="adding/isSingleMenuItem">
<input type="submit" name="container_add_button" value="Add"
i18n:attributes="value add-button"
i18n:domain="zope" />
<input type="text" name="single_new_value" id="focusid"
tal:condition="python:names_required and not has_custom_add_view"
i18n:domain="zope" />
<input type="hidden" name="single_type_name"
tal:attributes="value python:addingInfo[0]['action']" />
</div>
</div>
<div tal:condition="view/orderable">
<input type="submit" name="move_top" value="Top"
i18n:attributes="value container-movetop-button"
i18n:domain="zope" />
<input type="submit" name="move_up" value="Up"
i18n:attributes="value container-moveup-button"
i18n:domain="zope" />
<input type="text" size="2" name="delta" value="1" />
<input type="submit" name="move_down" value="Down"
i18n:attributes="value container-moveup-button"
i18n:domain="zope" />
<input type="submit" name="move_bottom" value="Bottom"
i18n:attributes="value container-movebottom-button"
i18n:domain="zope" />
</div>
</div>
<div tal:condition="view/specialButtons">
<input type="submit" value="Apply"
i18n:attributes="value container-apply-button" />
<input type="submit" name="container_cancel_button" value="Cancel"
i18n:attributes="value container-cancel-button" />
</div>
</form>
</tal:checkmove>
<script type="text/javascript"><!--
if (document.forms.contents.new_value)
document.forms.contents.new_value.focus();
//-->
</script>
</div>
</div>
</body>
</html>

View file

@ -283,6 +283,7 @@ class CreateObjectForm(ObjectForm):
def adapted(self): def adapted(self):
ad = self.typeInterface(Resource()) ad = self.typeInterface(Resource())
ad.storageName = 'unknown' # hack for file objects: don't try to retrieve data ad.storageName = 'unknown' # hack for file objects: don't try to retrieve data
ad.__type__ = adapted(self.typeConcept)
return ad return ad
@Lazy @Lazy

View file

@ -58,6 +58,9 @@ from loops.versioning.interfaces import IVersionable
from loops.util import _ from loops.util import _
resource_macros = ViewPageTemplateFile('resource_macros.pt')
class CustomFileWidget(FileWidget): class CustomFileWidget(FileWidget):
def hasInput(self): def hasInput(self):
@ -103,7 +106,8 @@ class MediaAssetEditForm(EditForm):
class ResourceView(BaseView): class ResourceView(BaseView):
template = ViewPageTemplateFile('resource_macros.pt') #template = ViewPageTemplateFile('resource_macros.pt')
template = resource_macros
@Lazy @Lazy
def icon(self): def icon(self):

View file

@ -97,6 +97,7 @@ class AdapterBase(object):
_textIndexAttributes = () _textIndexAttributes = ()
__is_dummy__ = False __is_dummy__ = False
__type__ = None
languageInfo = None languageInfo = None
@ -138,6 +139,13 @@ class AdapterBase(object):
def name(self): def name(self):
return getName(self.context) return getName(self.context)
@Lazy
def type(self):
return self.__type__ or self.getType()
def getType(self):
return adapted(self.context.getType())
@Lazy @Lazy
def uid(self): def uid(self):
return util.getUidForObject(self.context) return util.getUidForObject(self.context)

View file

@ -33,7 +33,7 @@ from cybertools.meta.config import GlobalOptions as BaseGlobalOptions
from cybertools.meta.interfaces import IOptions from cybertools.meta.interfaces import IOptions
from cybertools.meta.namespace import Executor, ExecutionError from cybertools.meta.namespace import Executor, ExecutionError
from cybertools.typology.interfaces import IType from cybertools.typology.interfaces import IType
from loops.interfaces import ILoops, ILoopsObject from loops.interfaces import ILoops, ILoopsObject, ITypeConcept
#from loops.query import IQueryConcept #from loops.query import IQueryConcept
from loops.expert.concept import IQueryConcept from loops.expert.concept import IQueryConcept
from loops import util from loops import util
@ -91,6 +91,11 @@ class LoopsOptions(Options):
raise ExecutionError('\n' + rc) raise ExecutionError('\n' + rc)
class TypeOptions(LoopsOptions):
adapts(ITypeConcept)
class QueryOptions(LoopsOptions): class QueryOptions(LoopsOptions):
adapts(IQueryConcept) adapts(IQueryConcept)

View file

@ -12,6 +12,11 @@
<allow interface="cybertools.meta.interfaces.IOptions" /> <allow interface="cybertools.meta.interfaces.IOptions" />
</zope:class> </zope:class>
<zope:adapter factory="loops.config.base.TypeOptions" trusted="True" />
<zope:class class="loops.config.base.TypeOptions">
<allow interface="cybertools.meta.interfaces.IOptions" />
</zope:class>
<zope:adapter factory="loops.config.base.QueryOptions" trusted="True" /> <zope:adapter factory="loops.config.base.QueryOptions" trusted="True" />
<zope:class class="loops.config.base.QueryOptions"> <zope:class class="loops.config.base.QueryOptions">
<allow interface="cybertools.meta.interfaces.IOptions" /> <allow interface="cybertools.meta.interfaces.IOptions" />

View file

@ -763,8 +763,13 @@ class IExternalFile(IFile):
missing_value='', missing_value='',
required=False) required=False)
externalAddress = Attribute('The full address for accessing the object ' externalAddress = schema.BytesLine(
'on the external storage, e.g. a filename or path.') 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 IAddressableExternalFile(IExternalFile): class IAddressableExternalFile(IExternalFile):

View file

@ -28,7 +28,7 @@ from zope.app.pagetemplate import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from loops.browser.node import NodeView from loops.browser.node import NodeView
from loops.browser.resource import ResourceView from loops.browser.resource import ResourceView, resource_macros
from loops.common import adapted from loops.common import adapted
from loops import util from loops import util
@ -39,7 +39,11 @@ class MediaAssetView(ResourceView):
@Lazy @Lazy
def macro(self): def macro(self):
return template.macros['asset'] #return template.macros['asset']
if 'image/' in self.context.contentType:
return template.macros['asset']
else:
return resource_macros.macros['download']
def show(self, useAttachment=False): def show(self, useAttachment=False):
versionId = self.request.get('v') versionId = self.request.get('v')

View file

@ -224,6 +224,11 @@ class Resource(Image, Contained):
def getSize(self): def getSize(self):
if self._size: if self._size:
return self._size return self._size
size = getattr(adapted(self), 'size', None)
if size is None:
return len(adapted(self).data)
return size
tp = IType(self, None) tp = IType(self, None)
if tp is not None: if tp is not None:
ti = tp.typeInterface ti = tp.typeInterface
@ -357,9 +362,15 @@ class ExternalFileAdapter(FileAdapter):
storageParams = property(getStorageParams, setStorageParams) storageParams = property(getStorageParams, setStorageParams)
def getExternalAddress(self): def getExternalAddress(self):
return getattr(self.context, '_externalAddress', self.context.__name__) return getattr(self.context, '_externalAddress', None) or self.context.__name__
def setExternalAddress(self, addr): def setExternalAddress(self, addr):
self.context._externalAddress = addr self.context._externalAddress = addr
if addr:
data = self.data
self.context._size = len(data)
contentType = guess_content_type(addr, self.data[:100])
if contentType:
self.contentType = contentType[0]
externalAddress = property(getExternalAddress, setExternalAddress) externalAddress = property(getExternalAddress, setExternalAddress)
@property @property
@ -372,12 +383,14 @@ class ExternalFileAdapter(FileAdapter):
def setData(self, data): def setData(self, data):
storageParams = self.storageParams storageParams = self.storageParams
storageName = self.storageName storageName = self.storageName
externalAddress = self.externalAddress
storage = component.getUtility(IExternalStorage, name=storageName) storage = component.getUtility(IExternalStorage, name=storageName)
storage.setData(self.externalAddress, data, params=storageParams) storage.setData(self.externalAddress, data, params=storageParams)
self.context._size = len(data) self.context._size = len(data)
# remember storage settings: # remember storage settings:
self.storageParams = storageParams self.storageParams = storageParams
self.storageName = storageName self.storageName = storageName
self.externalAddress = externalAddress
def getData(self): def getData(self):
if self.storageName in ('unknown', None): # object not set up yet if self.storageName in ('unknown', None): # object not set up yet
@ -387,6 +400,13 @@ class ExternalFileAdapter(FileAdapter):
data = property(getData, setData) data = property(getData, setData)
@property
def size(self):
if self.storageName in ('unknown', None): # object not set up yet
return ''
storage = component.getUtility(IExternalStorage, name=self.storageName)
return storage.getSize(self.externalAddress, params=self.storageParams)
class AddressableExternalFileAdapter(ExternalFileAdapter): class AddressableExternalFileAdapter(ExternalFileAdapter):

View file

@ -25,7 +25,10 @@ $Id$
from zope.component import adapts from zope.component import adapts
from cybertools.composer.schema.factory import SchemaFactory from cybertools.composer.schema.factory import SchemaFactory
from loops.common import adapted
from loops.interfaces import IResourceAdapter, IFile, INote, IAddressableExternalFile from loops.interfaces import IResourceAdapter, IFile, INote, IAddressableExternalFile
from cybertools.meta.interfaces import IOptions
from cybertools.typology.interfaces import IType
class ResourceSchemaFactory(SchemaFactory): class ResourceSchemaFactory(SchemaFactory):
@ -47,10 +50,19 @@ class FileSchemaFactory(SchemaFactory):
def __call__(self, interface, **kw): def __call__(self, interface, **kw):
schema = super(FileSchemaFactory, self).__call__(interface, **kw) schema = super(FileSchemaFactory, self).__call__(interface, **kw)
if 'request' in kw: options = IOptions(self.context.type)
principal = kw['request'].principal hide = options('hide_fields') or []
if not principal or principal.id != 'rootadmin': show = options('show_fields') or []
schema.fields.remove('contentType') for f in ('contentType', 'externalAddress',):
if f in schema.fields and f not in show:
schema.fields.remove(f)
for f in hide:
if f in schema.fields:
schema.fields.remove(f)
#if 'request' in kw:
# principal = kw['request'].principal
# if not principal or principal.id != 'rootadmin':
# schema.fields.remove('contentType')
return schema return schema

View file

@ -50,7 +50,7 @@ from loops.browser.node import ViewPropertiesConfigurator
from loops.common import NameChooser from loops.common import NameChooser
from loops.concept import Concept from loops.concept import Concept
from loops.concept import IndexAttributes as ConceptIndexAttributes from loops.concept import IndexAttributes as ConceptIndexAttributes
from loops.config.base import GlobalOptions, LoopsOptions, QueryOptions from loops.config.base import GlobalOptions, LoopsOptions, QueryOptions, TypeOptions
from loops.interfaces import ILoopsObject, IIndexAttributes from loops.interfaces import ILoopsObject, IIndexAttributes
from loops.interfaces import IDocument, IFile, ITextDocument from loops.interfaces import IDocument, IFile, ITextDocument
from loops.layout.base import LayoutNode from loops.layout.base import LayoutNode
@ -132,6 +132,7 @@ class TestSite(object):
component.provideAdapter(BaseSecuritySetter) component.provideAdapter(BaseSecuritySetter)
component.provideAdapter(LoopsOptions) component.provideAdapter(LoopsOptions)
component.provideAdapter(QueryOptions) component.provideAdapter(QueryOptions)
component.provideAdapter(TypeOptions)
component.provideUtility(GlobalOptions()) component.provideUtility(GlobalOptions())
component.provideAdapter(Instance) component.provideAdapter(Instance)