improvements for external collection and media asset: integration now working correctly, with generation of scal variants for media assets

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3105 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2008-12-31 13:46:18 +00:00
parent 60c7d22e61
commit be71f62a6e
9 changed files with 104 additions and 35 deletions

View file

@ -108,6 +108,7 @@ class EditForm(form.EditForm):
class BaseView(GenericView, I18NView): class BaseView(GenericView, I18NView):
actions = {} actions = {}
icon = None
def __init__(self, context, request): def __init__(self, context, request):
super(BaseView, self).__init__(context, request) super(BaseView, self).__init__(context, request)
@ -127,6 +128,8 @@ class BaseView(GenericView, I18NView):
def conceptMacros(self): def conceptMacros(self):
return concept_macros.macros return concept_macros.macros
concept_macros = conceptMacros
@Lazy @Lazy
def name(self): def name(self):
return getName(self.context) return getName(self.context)

View file

@ -3,12 +3,14 @@
<metal:data define-macro="conceptdata"> <metal:data define-macro="conceptdata">
<div tal:attributes="class string:content-$level;"> <div tal:attributes="class string:content-$level;">
<metal:fields use-macro="item/template/macros/concepttitle" /> <metal:block use-macro="view/concept_macros/concepttitle" />
<metal:fields use-macro="item/template/macros/conceptfields" /> <metal:slot define-slot="fields">
<metal:fields use-macro="item/template/macros/conceptchildren" /> <metal:block use-macro="view/concept_macros/conceptfields" />
<metal:fields use-macro="item/template/macros/conceptresources" /> </metal:slot>
<metal:fields use-macro="view/work_macros/workitems" /> <metal:block use-macro="view/concept_macros/conceptchildren" />
<metal:fields use-macro="view/comment_macros/comments" /> <metal:block use-macro="view/concept_macros/conceptresources" />
<metal:block use-macro="view/work_macros/workitems" />
<metal:block use-macro="view/comment_macros/comments" />
</div> </div>
</metal:data> </metal:data>
@ -154,7 +156,10 @@
<a href="#" <a href="#"
tal:attributes="href string:${view/url}/.target${related/uniqueId}; tal:attributes="href string:${view/url}/.target${related/uniqueId};
title description"> title description">
<span tal:replace="related/title">Resource Title</span> <img tal:define="icon related/icon"
tal:condition="icon"
tal:attributes="src icon/src" />
<div tal:content="related/title">Resource Title</div>
</a> </a>
</td> </td>
<td><span tal:replace="related/longTypeTitle">Type</span></td> <td><span tal:replace="related/longTypeTitle">Type</span></td>

View file

@ -48,7 +48,9 @@ from loops.browser.concept import ConceptRelationView, ConceptConfigureView
from loops.browser.node import NodeView, node_macros from loops.browser.node import NodeView, node_macros
from loops.common import adapted, NameChooser from loops.common import adapted, NameChooser
from loops.interfaces import IBaseResource, IDocument, IMediaAsset, ITextDocument from loops.interfaces import IBaseResource, IDocument, IMediaAsset, ITextDocument
from loops.interfaces import IMediaAsset as legacy_IMediaAsset
from loops.interfaces import ITypeConcept from loops.interfaces import ITypeConcept
from loops.media.interfaces import IMediaAsset
from loops.organize.stateful.browser import statefulActions from loops.organize.stateful.browser import statefulActions
from loops.versioning.browser import version_macros from loops.versioning.browser import version_macros
from loops.versioning.interfaces import IVersionable from loops.versioning.interfaces import IVersionable
@ -95,13 +97,19 @@ class DocumentEditForm(EditForm):
class MediaAssetEditForm(EditForm): class MediaAssetEditForm(EditForm):
form_fields = FormFields(IMediaAsset) form_fields = FormFields(legacy_IMediaAsset)
class ResourceView(BaseView): class ResourceView(BaseView):
template = ViewPageTemplateFile('resource_macros.pt') template = ViewPageTemplateFile('resource_macros.pt')
@Lazy
def icon(self):
if IMediaAsset.providedBy(self.adapted):
return dict(src='%s/mediaasset.html?v=minithumb' %
(self.nodeView.getUrlForTarget(self.context)))
@property @property
def macro(self): def macro(self):
if 'image/' in self.context.contentType: if 'image/' in self.context.contentType:

View file

@ -59,9 +59,15 @@ class ExternalCollectionAdapter(AdapterBase):
implements(IExternalCollection) implements(IExternalCollection)
adapts(IConcept) adapts(IConcept)
_adapterAttributes = ('context', '__parent__',) _adapterAttributes = ('context', '__parent__', 'exclude')
_contextAttributes = list(IExternalCollection) + list(IConcept) _contextAttributes = list(IExternalCollection) + list(IConcept)
def getExclude(self):
return getattr(self.context, '_exclude', None) or []
def setExclude(self, value):
self.context._exclude = value
exclude = property(getExclude, setExclude)
def update(self): def update(self):
existing = self.context.getResources() existing = self.context.getResources()
#old = dict((adapted(obj).uniqueAddress, obj) for obj in existing) #old = dict((adapted(obj).uniqueAddress, obj) for obj in existing)
@ -109,26 +115,43 @@ class DirectoryCollectionProvider(object):
implements(IExternalCollectionProvider) implements(IExternalCollectionProvider)
extFileTypeMapping = {
'image/*': 'media_asset',
'*/*': 'extfile',
}
def collect(self, client): def collect(self, client):
directory = self.getDirectory(client) directory = self.getDirectory(client)
pattern = re.compile(client.pattern or '.*') pattern = re.compile(client.pattern or '.*')
for path, dirs, files in os.walk(directory): for path, dirs, files in os.walk(directory):
if '.svn' in dirs: if '.svn' in dirs:
del dirs[dirs.index('.svn')] del dirs[dirs.index('.svn')]
for ex in client.exclude:
if ex in dirs:
del dirs[dirs.index(ex)]
for f in files: for f in files:
if pattern.match(f): if pattern.match(f):
mtime = os.stat(os.path.join(path, f))[stat.ST_MTIME] mtime = os.stat(os.path.join(path, f))[stat.ST_MTIME]
yield (os.path.join(path[len(directory)+1:], f), yield (os.path.join(path[len(directory)+1:], f),
datetime.fromtimestamp(mtime)) datetime.fromtimestamp(mtime))
def createExtFileObjects(self, client, addresses, extFileType=None): def createExtFileObjects(self, client, addresses, extFileTypes=None):
if extFileType is None: if extFileTypes is None:
extFileType = client.context.getLoopsRoot().getConceptManager()['extfile'] cm = client.context.getLoopsRoot().getConceptManager()
extFileTypes = dict((k, cm.get(v))
for k, v in self.extFileTypeMapping.items())
container = client.context.getLoopsRoot().getResourceManager() container = client.context.getLoopsRoot().getResourceManager()
directory = self.getDirectory(client) directory = self.getDirectory(client)
for addr in addresses: for addr in addresses:
name = self.generateName(container, addr) name = self.generateName(container, addr)
title = self.generateTitle(addr) title = self.generateTitle(addr)
contentType = guess_content_type(addr,
default='application/octet-stream')[0]
extFileType = extFileTypes.get(contentType)
if extFileType is None:
extFileType = extFileTypes.get(contentType.split('/')[0] + '/*')
if extFileType is None:
extFileType = extFileTypes['*/*']
obj = addAndConfigureObject( obj = addAndConfigureObject(
container, Resource, name, container, Resource, name,
title=title, title=title,
@ -136,9 +159,8 @@ class DirectoryCollectionProvider(object):
externalAddress=addr, externalAddress=addr,
storageName='fullpath', storageName='fullpath',
storageParams=dict(subdirectory=directory), storageParams=dict(subdirectory=directory),
contentType = guess_content_type(addr, contentType=contentType,
default='application/octet-stream')[0] )
)
yield obj yield obj
def getDirectory(self, client): def getDirectory(self, client):

View file

@ -1,11 +1,19 @@
<metal:resources define-macro="render_collection" <html i18n:domain="loops">
tal:define="dummy item/update">
<metal:concept use-macro="item/template/macros/conceptdata" />
<form action="." method="post"> <metal:block define-macro="render_collection"
<input type="submit" name="update" value="Update Collection" /> tal:define="dummy item/update">
</form>
</metal:resources> <metal:block use-macro="view/concept_macros/conceptdata">
<metal:fill fill-slot="fields">
<metal:block use-macro="view/concept_macros/conceptfields" />
<form action="." method="post">
<input type="submit" name="update" value="Update Collection" />
</form>
</metal:fill>
</metal:block>
</metal:block>
</html>

View file

@ -50,13 +50,13 @@ class IExternalCollection(IConceptSchema):
providerName = schema.TextLine( providerName = schema.TextLine(
title=_(u'Provider name'), title=_(u'Provider name'),
description=_(u'The name of a utility that provides the ' description=_(u'The name of a utility that provides the '
'external objects; default is a directory ' u'external objects; default is a directory '
'collection provider'), u'collection provider'),
required=False) required=False)
baseAddress = schema.TextLine( baseAddress = schema.TextLine(
title=_(u'Base address'), title=_(u'Base address'),
description=_(u'A base path or URL for accessing this collection ' description=_(u'A base path or URL for accessing this collection '
'on the external system'), u'on the external system'),
required=True) required=True)
address = schema.TextLine( address = schema.TextLine(
title=_(u'Relative address'), title=_(u'Relative address'),
@ -66,7 +66,13 @@ class IExternalCollection(IConceptSchema):
pattern = schema.TextLine( pattern = schema.TextLine(
title=_(u'Selection pattern'), title=_(u'Selection pattern'),
description=_(u'A regular expression for selecting external objects ' description=_(u'A regular expression for selecting external objects '
'that should belong to this collection'), u'that should belong to this collection'),
required=False)
exclude = schema.List(
title=_(u'Exclude'),
description=_(u'Names of directories and files that should not '
u'be included.'),
value_type=schema.TextLine(),
required=False) required=False)
lastUpdated = Attribute('Date and time of last update.') lastUpdated = Attribute('Date and time of last update.')
@ -93,9 +99,12 @@ class IExternalCollectionProvider(Interface):
IExternalCollection interface. IExternalCollection interface.
""" """
def createExtFileObjects(clientCollection, addresses, extFileType=None): def createExtFileObjects(clientCollection, addresses, extFileTypes=None):
""" Create a resource of type 'extFileType' (default is the """ Create a resource for each of the addresses provided.
type with the name 'extfile') for each of the addresses Return the list of objects created.
provided. Return the list of objects created.
The ``extFileTypes`` argument is a mapping of MIME types to
names of concept types. The MIME types may contain wildcards,
e.g. 'image/*', '*/*'.
""" """

View file

@ -69,13 +69,22 @@ class MediaAsset(MediaAssetFile, ExternalFileAdapter):
self.transform(self.rules) self.transform(self.rules)
data = property(ExternalFileAdapter.getData, setData) data = property(ExternalFileAdapter.getData, setData)
def setExternalAddress(self, addr):
ExternalFileAdapter.setExternalAddress(self, addr)
if addr and self.getMimeType().startswith('image/'):
self.transform(self.rules)
externalAddress = property(ExternalFileAdapter.getExternalAddress,
setExternalAddress)
def getMimeType(self): def getMimeType(self):
return self.context.contentType or '' return self.context.contentType or ''
def getDataPath(self): def getDataPath(self):
storage = component.getUtility(IExternalStorage, name=self.storageName) storage = component.getUtility(IExternalStorage, name=self.storageName)
#print '***', self.storageName, self.storageParams, self.options
return storage.getDir(self.externalAddress, return storage.getDir(self.externalAddress,
self.options['storage_parameters']) #self.options['storage_parameters'])
self.storageParams['subdirectory'])
def getOriginalData(self): def getOriginalData(self):
return ExternalFileAdapter.getData(self) return ExternalFileAdapter.getData(self)

View file

@ -275,7 +275,8 @@ class Resource(Image, Contained):
oldAdapted.data = '' # clear old storage oldAdapted.data = '' # clear old storage
context._storageName = None # let's take storage from new type options context._storageName = None # let's take storage from new type options
context._storageParams = None # " context._storageParams = None # "
newAdapted.data = data if data: # do not write empty files
newAdapted.data = data
# Document and MediaAsset are legacy classes, will become obsolete # Document and MediaAsset are legacy classes, will become obsolete

View file

@ -72,9 +72,13 @@
description row/description"> description row/description">
<tr tal:attributes="class class"> <tr tal:attributes="class class">
<td> <td>
<a tal:attributes="href string:${view/url}/.target${row/uniqueId}?version=this; <a tal:attributes="href
title description" string:${view/url}/.target${row/uniqueId}?version=this;
tal:content="row/title" /> title description">
<img tal:define="icon row/icon"
tal:condition="icon"
tal:attributes="src icon/src" />
<div tal:content="row/title" /></a>
</td> </td>
<td i18n:translate="" <td i18n:translate=""
tal:content="row/longTypeTitle|row/typeTitle">Type</td> tal:content="row/longTypeTitle|row/typeTitle">Type</td>