--- a/src/pyams_content/component/extfile/__init__.py Mon Sep 11 14:53:15 2017 +0200
+++ b/src/pyams_content/component/extfile/__init__.py Mon Sep 11 14:54:30 2017 +0200
@@ -16,21 +16,27 @@
# import standard library
# import interfaces
-from pyams_content.component.extfile.interfaces import IBaseExtFile, IExtFile, IExtImage, IExtVideo, IExtAudio
+from pyams_content.component.association.interfaces import IAssociationInfo
+from pyams_content.component.extfile.interfaces import IBaseExtFile, IExtFile, IExtImage, IExtVideo, IExtAudio, \
+ IExtMedia
from pyams_content.shared.common.interfaces import IWfSharedContent
+from pyams_file.interfaces import IFileInfo, IResponsiveImage, DELETED_FILE
from pyams_form.interfaces.form import IFormContextPermissionChecker
+from pyams_i18n.interfaces import II18n, INegotiator
from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent, IObjectRemovedEvent
# import packages
-from persistent import Persistent
+from pyams_content.component.association import AssociationItem
from pyams_i18n.property import I18nFileProperty
from pyams_utils.adapter import adapter_config, ContextAdapter
+from pyams_utils.registry import query_utility
+from pyams_utils.request import check_request
+from pyams_utils.size import get_human_size
from pyams_utils.traversing import get_parent
from pyams_utils.vocabulary import vocabulary_config
from pyramid.events import subscriber
from pyramid.threadlocal import get_current_registry
-from zope.container.contained import Contained
-from zope.interface import implementer
+from zope.interface import implementer, alsoProvides
from zope.lifecycleevent import ObjectModifiedEvent
from zope.schema.fieldproperty import FieldProperty
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
@@ -58,12 +64,39 @@
@implementer(IBaseExtFile)
-class BaseExtFile(Persistent, Contained):
+class BaseExtFile(AssociationItem):
"""External file persistent class"""
title = FieldProperty(IExtFile['title'])
description = FieldProperty(IExtFile['description'])
author = FieldProperty(IExtFile['author'])
+ language = FieldProperty(IExtFile['language'])
+ filename = FieldProperty(IExtFile['filename'])
+
+
+@adapter_config(context=IBaseExtFile, provides=IAssociationInfo)
+class BaseExtFileAssociationInfoAdapter(ContextAdapter):
+ """Base external file association info adapter"""
+
+ @property
+ def pictogram(self):
+ return self.context.icon_class
+
+ @property
+ def user_title(self):
+ return II18n(self.context).query_attribute('title') or self.context.filename
+
+ @property
+ def inner_title(self):
+ return self.context.filename or '--'
+
+ @property
+ def human_size(self):
+ data = II18n(self.context).query_attribute('data')
+ if data and data.data:
+ return get_human_size(data.get_size())
+ else:
+ return '--'
@adapter_config(context=IBaseExtFile, provides=IFormContextPermissionChecker)
@@ -76,10 +109,34 @@
return IFormContextPermissionChecker(content).edit_permission
+def update_properties(extfile):
+ """Update missing file properties"""
+ request = check_request()
+ i18n = query_utility(INegotiator)
+ if i18n is not None:
+ lang = i18n.server_language
+ data = II18n(extfile).get_attribute('data', lang, request)
+ if data:
+ info = IFileInfo(data)
+ info.title = II18n(extfile).get_attribute('title', lang, request)
+ info.description = II18n(extfile).get_attribute('description', lang, request)
+ if not extfile.filename:
+ extfile.filename = info.filename
+ else:
+ info.filename = extfile.filename
+ for lang, data in (extfile.data or {}).items():
+ if data is not None:
+ IFileInfo(data).language = lang
+
+
@subscriber(IObjectAddedEvent, context_selector=IBaseExtFile)
def handle_added_extfile(event):
"""Handle added external file"""
- content = get_parent(event.object, IWfSharedContent)
+ # update inner file properties
+ extfile = event.object
+ update_properties(extfile)
+ # notify content modification
+ content = get_parent(extfile, IWfSharedContent)
if content is not None:
get_current_registry().notify(ObjectModifiedEvent(content))
@@ -87,7 +144,11 @@
@subscriber(IObjectModifiedEvent, context_selector=IBaseExtFile)
def handle_modified_extfile(event):
"""Handle modified external file"""
- content = get_parent(event.object, IWfSharedContent)
+ # update inner file properties
+ extfile = event.object
+ update_properties(extfile)
+ # notify content modification
+ content = get_parent(extfile, IWfSharedContent)
if content is not None:
get_current_registry().notify(ObjectModifiedEvent(content))
@@ -104,6 +165,9 @@
class ExtFile(BaseExtFile):
"""Generic external file persistent class"""
+ icon_class = 'fa-file-o'
+ icon_hint = _("Standard file")
+
data = I18nFileProperty(IExtFile['data'])
register_file_factory('file', ExtFile, _("Standard file"))
@@ -113,7 +177,23 @@
class ExtImage(BaseExtFile):
"""External image persistent class"""
- data = I18nFileProperty(IExtImage['data'])
+ icon_class = 'fa-file-image-o'
+ icon_hint = _("Image")
+
+ title = FieldProperty(IExtMedia['title'])
+ alt_title = FieldProperty(IExtImage['alt_title'])
+ _data = I18nFileProperty(IExtImage['data'])
+
+ @property
+ def data(self):
+ return self._data
+
+ @data.setter
+ def data(self, value):
+ self._data = value
+ for data in value.values():
+ if (data is not None) and (data is not DELETED_FILE):
+ alsoProvides(data, IResponsiveImage)
register_file_factory('image', ExtImage, _("Image"))
@@ -122,6 +202,10 @@
class ExtVideo(BaseExtFile):
"""External video file persistent class"""
+ icon_class = 'fa-file-video-o'
+ icon_hint = _("Video")
+
+ title = FieldProperty(IExtMedia['title'])
data = I18nFileProperty(IExtVideo['data'])
register_file_factory('video', ExtVideo, _("Video"))
@@ -131,6 +215,10 @@
class ExtAudio(BaseExtFile):
"""External audio file persistent class"""
+ icon_class = 'fa-file-audio-o'
+ icon_hint = _("Audio file")
+
+ title = FieldProperty(IExtMedia['title'])
data = I18nFileProperty(IExtAudio['data'])
register_file_factory('audio', ExtAudio, _("Audio file"))