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:
parent
b3962aba0e
commit
1c1147cda9
13 changed files with 332 additions and 16 deletions
|
@ -403,6 +403,10 @@ class BaseView(GenericView, I18NView):
|
|||
def globalOptions(self):
|
||||
return IOptions(self.loopsRoot)
|
||||
|
||||
@Lazy
|
||||
def typeOptions(self):
|
||||
return IOptions(adapted(self.typeProvider))
|
||||
|
||||
# versioning
|
||||
|
||||
@Lazy
|
||||
|
|
|
@ -140,9 +140,16 @@
|
|||
<containerViews
|
||||
for="loops.interfaces.IConceptManager"
|
||||
index="loops.ManageSite"
|
||||
contents="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 -->
|
||||
|
||||
<addform
|
||||
|
@ -237,15 +244,21 @@
|
|||
schema="loops.interfaces.IResourceManager"
|
||||
content_factory="loops.resource.ResourceManager"
|
||||
template="add.pt"
|
||||
permission="zope.ManageContent"
|
||||
/>
|
||||
permission="zope.ManageContent" />
|
||||
|
||||
<containerViews
|
||||
for="loops.interfaces.IResourceManager"
|
||||
index="loops.ManageSite"
|
||||
contents="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 -->
|
||||
|
||||
<page
|
||||
|
|
234
browser/contents.pt
Normal file
234
browser/contents.pt
Normal 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="">
|
||||
</span></td>
|
||||
<td><span tal:define="created item/created|default"
|
||||
tal:content="created"
|
||||
i18n:translate=""> </span></td>
|
||||
<td><span tal:define="modified item/modified|default"
|
||||
tal:content="modified"
|
||||
i18n:translate=""> </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 < 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>
|
|
@ -283,6 +283,7 @@ class CreateObjectForm(ObjectForm):
|
|||
def adapted(self):
|
||||
ad = self.typeInterface(Resource())
|
||||
ad.storageName = 'unknown' # hack for file objects: don't try to retrieve data
|
||||
ad.__type__ = adapted(self.typeConcept)
|
||||
return ad
|
||||
|
||||
@Lazy
|
||||
|
|
|
@ -58,6 +58,9 @@ from loops.versioning.interfaces import IVersionable
|
|||
from loops.util import _
|
||||
|
||||
|
||||
resource_macros = ViewPageTemplateFile('resource_macros.pt')
|
||||
|
||||
|
||||
class CustomFileWidget(FileWidget):
|
||||
|
||||
def hasInput(self):
|
||||
|
@ -103,7 +106,8 @@ class MediaAssetEditForm(EditForm):
|
|||
|
||||
class ResourceView(BaseView):
|
||||
|
||||
template = ViewPageTemplateFile('resource_macros.pt')
|
||||
#template = ViewPageTemplateFile('resource_macros.pt')
|
||||
template = resource_macros
|
||||
|
||||
@Lazy
|
||||
def icon(self):
|
||||
|
|
|
@ -97,6 +97,7 @@ class AdapterBase(object):
|
|||
_textIndexAttributes = ()
|
||||
|
||||
__is_dummy__ = False
|
||||
__type__ = None
|
||||
|
||||
languageInfo = None
|
||||
|
||||
|
@ -138,6 +139,13 @@ class AdapterBase(object):
|
|||
def name(self):
|
||||
return getName(self.context)
|
||||
|
||||
@Lazy
|
||||
def type(self):
|
||||
return self.__type__ or self.getType()
|
||||
|
||||
def getType(self):
|
||||
return adapted(self.context.getType())
|
||||
|
||||
@Lazy
|
||||
def uid(self):
|
||||
return util.getUidForObject(self.context)
|
||||
|
|
|
@ -33,7 +33,7 @@ from cybertools.meta.config import GlobalOptions as BaseGlobalOptions
|
|||
from cybertools.meta.interfaces import IOptions
|
||||
from cybertools.meta.namespace import Executor, ExecutionError
|
||||
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.expert.concept import IQueryConcept
|
||||
from loops import util
|
||||
|
@ -91,6 +91,11 @@ class LoopsOptions(Options):
|
|||
raise ExecutionError('\n' + rc)
|
||||
|
||||
|
||||
class TypeOptions(LoopsOptions):
|
||||
|
||||
adapts(ITypeConcept)
|
||||
|
||||
|
||||
class QueryOptions(LoopsOptions):
|
||||
|
||||
adapts(IQueryConcept)
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
<allow interface="cybertools.meta.interfaces.IOptions" />
|
||||
</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:class class="loops.config.base.QueryOptions">
|
||||
<allow interface="cybertools.meta.interfaces.IOptions" />
|
||||
|
|
|
@ -763,8 +763,13 @@ class IExternalFile(IFile):
|
|||
missing_value='',
|
||||
required=False)
|
||||
|
||||
externalAddress = Attribute('The full address for accessing the object '
|
||||
'on the external storage, e.g. a filename or path.')
|
||||
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 IAddressableExternalFile(IExternalFile):
|
||||
|
|
|
@ -28,7 +28,7 @@ from zope.app.pagetemplate import ViewPageTemplateFile
|
|||
from zope.cachedescriptors.property import Lazy
|
||||
|
||||
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 import util
|
||||
|
||||
|
@ -39,7 +39,11 @@ class MediaAssetView(ResourceView):
|
|||
|
||||
@Lazy
|
||||
def macro(self):
|
||||
#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):
|
||||
versionId = self.request.get('v')
|
||||
|
|
22
resource.py
22
resource.py
|
@ -224,6 +224,11 @@ class Resource(Image, Contained):
|
|||
def getSize(self):
|
||||
if 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)
|
||||
if tp is not None:
|
||||
ti = tp.typeInterface
|
||||
|
@ -357,9 +362,15 @@ class ExternalFileAdapter(FileAdapter):
|
|||
storageParams = property(getStorageParams, setStorageParams)
|
||||
|
||||
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):
|
||||
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)
|
||||
|
||||
@property
|
||||
|
@ -372,12 +383,14 @@ class ExternalFileAdapter(FileAdapter):
|
|||
def setData(self, data):
|
||||
storageParams = self.storageParams
|
||||
storageName = self.storageName
|
||||
externalAddress = self.externalAddress
|
||||
storage = component.getUtility(IExternalStorage, name=storageName)
|
||||
storage.setData(self.externalAddress, data, params=storageParams)
|
||||
self.context._size = len(data)
|
||||
# remember storage settings:
|
||||
self.storageParams = storageParams
|
||||
self.storageName = storageName
|
||||
self.externalAddress = externalAddress
|
||||
|
||||
def getData(self):
|
||||
if self.storageName in ('unknown', None): # object not set up yet
|
||||
|
@ -387,6 +400,13 @@ class ExternalFileAdapter(FileAdapter):
|
|||
|
||||
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):
|
||||
|
||||
|
|
|
@ -25,7 +25,10 @@ $Id$
|
|||
from zope.component import adapts
|
||||
|
||||
from cybertools.composer.schema.factory import SchemaFactory
|
||||
from loops.common import adapted
|
||||
from loops.interfaces import IResourceAdapter, IFile, INote, IAddressableExternalFile
|
||||
from cybertools.meta.interfaces import IOptions
|
||||
from cybertools.typology.interfaces import IType
|
||||
|
||||
|
||||
class ResourceSchemaFactory(SchemaFactory):
|
||||
|
@ -47,10 +50,19 @@ class FileSchemaFactory(SchemaFactory):
|
|||
|
||||
def __call__(self, interface, **kw):
|
||||
schema = super(FileSchemaFactory, self).__call__(interface, **kw)
|
||||
if 'request' in kw:
|
||||
principal = kw['request'].principal
|
||||
if not principal or principal.id != 'rootadmin':
|
||||
schema.fields.remove('contentType')
|
||||
options = IOptions(self.context.type)
|
||||
hide = options('hide_fields') or []
|
||||
show = options('show_fields') or []
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ from loops.browser.node import ViewPropertiesConfigurator
|
|||
from loops.common import NameChooser
|
||||
from loops.concept import Concept
|
||||
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 IDocument, IFile, ITextDocument
|
||||
from loops.layout.base import LayoutNode
|
||||
|
@ -132,6 +132,7 @@ class TestSite(object):
|
|||
component.provideAdapter(BaseSecuritySetter)
|
||||
component.provideAdapter(LoopsOptions)
|
||||
component.provideAdapter(QueryOptions)
|
||||
component.provideAdapter(TypeOptions)
|
||||
component.provideUtility(GlobalOptions())
|
||||
|
||||
component.provideAdapter(Instance)
|
||||
|
|
Loading…
Add table
Reference in a new issue