From 370f0276107e717ebf8b40e70697cd508312e8a3 Mon Sep 17 00:00:00 2001 From: Sebastian Gottfried Date: Wed, 10 Aug 2016 00:43:42 +0200 Subject: [PATCH 1/8] Required Fields Are Required --- raptus/multilanguagefields/fields.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/raptus/multilanguagefields/fields.py b/raptus/multilanguagefields/fields.py index 7d2c0e4..8c2ee85 100755 --- a/raptus/multilanguagefields/fields.py +++ b/raptus/multilanguagefields/fields.py @@ -70,13 +70,6 @@ def __init__(self, name=None, **kwargs): def _set_required(self, value): self._required = value def _get_required(self): - context = getSite() - if self.haveLanguageFallback(context): - current = self._v_lang - if current is None: - current = self._getCurrentLanguage(context) - default = self.getDefaultLang(context) - return default == current and getattr(self, '_required', False) return getattr(self, '_required', False) required = property(fget=_get_required, fset=_set_required) From 44a94a3fb41eb7c32ddbd4b1a183f6455643080c Mon Sep 17 00:00:00 2001 From: Paul Grunewald Date: Wed, 10 Aug 2016 00:06:04 +0200 Subject: [PATCH 2/8] Reset language for image scales. Especially reset language before, if no specific language is requested. --- raptus/multilanguagefields/patches/imaging.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/raptus/multilanguagefields/patches/imaging.py b/raptus/multilanguagefields/patches/imaging.py index 2949f84..6782c2b 100755 --- a/raptus/multilanguagefields/patches/imaging.py +++ b/raptus/multilanguagefields/patches/imaging.py @@ -48,9 +48,17 @@ def publishTraverse(self, request, name): def scale(self, fieldname=None, scale=None, **parameters): field = self.context.getField(fieldname) + + if IMultilanguageField.providedBy(field): + if not '___' in fieldname: # no language explicitly wished. So unset language preference. + field.resetLanguage() + fieldname = '%s___%s___' % (fieldname, field._v_lang or field._getCurrentLanguage(self.context)) + + image = self.__old_scale(fieldname, scale, **parameters) + if IMultilanguageField.providedBy(field): - fieldname = '%s___%s___' % (fieldname, field._v_lang or field._getCurrentLanguage(getSite())) - return self.__old_scale(fieldname, scale, **parameters) + field.resetLanguage() + return image from plone.app.imaging.scaling import ImageScaling ImageScaling.__old_scale = ImageScaling.scale ImageScaling.scale = scale From cab94aa008da9ed2a04ae26167160aaf499a40bb Mon Sep 17 00:00:00 2001 From: Sebastian Gottfried Date: Wed, 10 Aug 2016 00:37:04 +0200 Subject: [PATCH 3/8] Error Resilient Indices Don't rely on the presence of the language tool. Unindexing can happen after the tool is deleted, e.g. if the portal is being deleted. --- raptus/multilanguagefields/indexes/UnIndex.py | 19 +++++++++++-------- .../indexes/ZCTextIndex.py | 11 +++++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/raptus/multilanguagefields/indexes/UnIndex.py b/raptus/multilanguagefields/indexes/UnIndex.py index 20bbf97..f93fe56 100644 --- a/raptus/multilanguagefields/indexes/UnIndex.py +++ b/raptus/multilanguagefields/indexes/UnIndex.py @@ -19,15 +19,18 @@ class MultilanguageUnIndex(UnIndex): """Multilanguage aware forward and reverse index. """ - + _v_lang = None _d_length = PersistentDict() _d_index = PersistentDict() _d_unindex = PersistentDict() - + def _getCurrentLanguage(self): - return getToolByName(getSite(), 'portal_languages').getPreferredLanguage() - + try: + return getToolByName(getSite(), 'portal_languages').getPreferredLanguage() + except AttributeError: + return 'en' + def _get_lang_length(self, lang): if not self._d_length.has_key(lang): self._d_length[lang] = BTrees.Length.Length() @@ -53,7 +56,7 @@ def _del_length(self): _length = property(fget=_get_length, fset=_set_length, fdel=_del_length) - + def _get_lang_index(self, lang): if not self._d_index.has_key(lang): self._d_index[lang] = OOBTree() @@ -78,7 +81,7 @@ def _del_index(self): _index = property(fget=_get_index, fset=_set_index, fdel=_del_index) - + def _get_lang_unindex(self, lang): if not self._d_unindex.has_key(lang): self._d_unindex[lang] = IOBTree() @@ -103,7 +106,7 @@ def _del_unindex(self): _unindex = property(fget=_get_unindex, fset=_set_unindex, fdel=_del_unindex) - + def clear(self): self._v_lang = None self._d_length = PersistentDict() @@ -136,7 +139,7 @@ def unindex_object(self, documentId): UnIndex.unindex_object(self, documentId) finally: self._v_lang = None - + def _get_object_datum(self, obj, attr): # self.id is the name of the index, which is also the name of the # attribute we're interested in. If the attribute is callable, diff --git a/raptus/multilanguagefields/indexes/ZCTextIndex.py b/raptus/multilanguagefields/indexes/ZCTextIndex.py index 53460b3..44abee6 100644 --- a/raptus/multilanguagefields/indexes/ZCTextIndex.py +++ b/raptus/multilanguagefields/indexes/ZCTextIndex.py @@ -24,7 +24,10 @@ class MultilanguageZCTextIndex(ZCTextIndex): _v_lang = None def _getCurrentLanguage(self): - return getToolByName(getSite(), 'portal_languages').getPreferredLanguage() + try: + return getToolByName(getSite(), 'portal_languages').getPreferredLanguage() + except AttributeError: + return 'en' @property def languages(self): @@ -32,7 +35,7 @@ def languages(self): if ltool is None: return [] return ltool.getSupportedLanguages() - + def _get_lang_index(self, lang): if not hasattr(self, '_index_%s' % lang): setattr(self, '_index_%s' % lang, self._index_factory(aq_base(self.getLexicon()))) @@ -79,7 +82,7 @@ def index_object(self, documentId, obj, threshold=None): try: fields = self._indexed_attrs except: fields = [ self._fieldname ] res = 0 - + for lang in self.languages: all_texts = [] for attr in fields: @@ -96,7 +99,7 @@ def index_object(self, documentId, obj, threshold=None): all_texts.extend(text) else: all_texts.append(text) - + # Check that we're sending only strings all_texts = filter(lambda text: isinstance(text, basestring), \ all_texts) From 9ff55c9b788c59465979793cb95466381e71ae43 Mon Sep 17 00:00:00 2001 From: Sebastian Gottfried Date: Wed, 10 Aug 2016 00:41:28 +0200 Subject: [PATCH 4/8] Image Bobo Traverse Fixes the image fullscreen view --- .../multilanguagefields/patches/traverse.py | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/raptus/multilanguagefields/patches/traverse.py b/raptus/multilanguagefields/patches/traverse.py index 7728ed5..c4cd9a4 100755 --- a/raptus/multilanguagefields/patches/traverse.py +++ b/raptus/multilanguagefields/patches/traverse.py @@ -4,16 +4,16 @@ from raptus.multilanguagefields import LOG from raptus.multilanguagefields.interfaces import IMultilanguageField from Products.Archetypes.BaseObject import BaseObject + def __bobo_traverse__(self, REQUEST, name): - """Transparent access to multilanguage image scales for - content types holding an multilanguage ImageField named - 'image' + """ helper to access multilanguage image scales the old way during + `unrestrictedTraverse` calls - NO BLOBS + the method to be patched is '__bobo_traverse__' """ if name.startswith('image_') or name == 'image': - field = self.getField('image') - if not IMultilanguageField.providedBy(field): + field = self.getField(name.split('_')[0]) + if not IMultilanguageField.providedBy(field) or not hasattr(REQUEST, 'get'): return BaseObject.__bobo_traverse__(self, REQUEST, name) last = REQUEST.get('ACTUAL_URL', '').endswith(name) fieldname, scale = name, None @@ -25,31 +25,32 @@ def __bobo_traverse__(self, REQUEST, name): if '_' in name: fieldname, scale = name.split('_', 1) if last and REQUEST.get('HTTP_USER_AGENT', False): - _scale = scale - if _scale is not None: - _scale = '_'+str(_scale) - else: - _scale = '' - REQUEST.RESPONSE.redirect(self.absolute_url()+'/'+fieldname+'___'+field._getCurrentLanguage(self)+'___'+_scale) + # begin own code + if scale in field.getAvailableSizes(self): + # end own code + _scale = scale + if _scale is not None: + _scale = '_'+str(_scale) + else: + _scale = '' + REQUEST.RESPONSE.redirect(self.absolute_url()+'/'+fieldname+'___'+field._getCurrentLanguage(self)+'___'+_scale) lang = field._getCurrentLanguage(self) lang_before = field._v_lang try: field.setLanguage(lang) + handler = IImageScaleHandler(field, None) image = None - if scale: - if scale in field.getAvailableSizes(self): - image = field.getScale(self, scale=scale) - else: - image = field.getScale(self) + if handler is not None: + try: + image = handler.getScale(self, scale) + except AttributeError: # no image available, do not raise as there might be one available as a fallback + pass if not image: # language fallback defaultLang = field.getDefaultLang(self) if defaultLang and not defaultLang == lang: field.setLanguage(defaultLang) - if scale: - if scale in field.getAvailableSizes(self): - image = field.getScale(self, scale=scale) - else: - image = field.getScale(self) + if handler is not None: + image = handler.getScale(self, scale) if image is not None: if last and REQUEST.get('HTTP_USER_AGENT', False): _scale = scale @@ -60,8 +61,7 @@ def __bobo_traverse__(self, REQUEST, name): REQUEST.RESPONSE.redirect(self.absolute_url()+'/'+fieldname+'___'+defaultLang+'___'+_scale) finally: field.setLanguage(lang_before) - if image is not None and not isinstance(image, basestring): - # image might be None or '' for empty images + if image is not None: return image return BaseObject.__bobo_traverse__(self, REQUEST, name) From a2edd98b6718d539a62ab1d8ce409290940d351b Mon Sep 17 00:00:00 2001 From: Paul Grunewald Date: Tue, 14 Mar 2017 14:08:28 +0100 Subject: [PATCH 5/8] Allow language fallback for brains. --- raptus/multilanguagefields/patches/catalog.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/raptus/multilanguagefields/patches/catalog.py b/raptus/multilanguagefields/patches/catalog.py index 297f351..b5ce438 100644 --- a/raptus/multilanguagefields/patches/catalog.py +++ b/raptus/multilanguagefields/patches/catalog.py @@ -25,7 +25,9 @@ # CatalogBrain monkey patch def __new_init__(self, data): ndata = [] - lang = getToolByName(getSite(), 'portal_languages').getPreferredLanguage() + portal_languages = getToolByName(getSite(), 'portal_languages') + lang = portal_languages.getPreferredLanguage() + default_lang = portal_languages.getDefaultLanguage() if portal_languages.allow_content_language_fallback else 'en' try: encoding = getToolByName(self, "portal_properties").site_properties.default_charset except AttributeError: @@ -34,7 +36,10 @@ def __new_init__(self, data): try: value = json.loads(v) value = value['___multilanguage___'] - v = value.get(lang, '') + if portal_languages.allow_content_language_fallback: + v = value.get(lang, value.get(default_lang, '')) + else: + v = value.get(lang, '') if isinstance(v, basestring): v = v.encode(encoding) except: From cc9c88e5e8fe379f21b7ed1889aa4fede5afdc31 Mon Sep 17 00:00:00 2001 From: Paul Grunewald Date: Fri, 23 Sep 2016 15:09:37 +0200 Subject: [PATCH 6/8] Update the calls of the method `scale` to the latest signature. Otherwise other monkey patches will fail due to the signature mismatch. --- raptus/multilanguagefields/patches/imaging.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/raptus/multilanguagefields/patches/imaging.py b/raptus/multilanguagefields/patches/imaging.py index 6782c2b..7122e21 100755 --- a/raptus/multilanguagefields/patches/imaging.py +++ b/raptus/multilanguagefields/patches/imaging.py @@ -46,7 +46,7 @@ def publishTraverse(self, request, name): ImageTraverser.publishTraverse = publishTraverse LOG.info("plone.app.imaging.traverse.ImageTraverser.publishTraverse patched") - def scale(self, fieldname=None, scale=None, **parameters): + def scale(self, fieldname=None, scale=None, height=None, width=None, **parameters): field = self.context.getField(fieldname) if IMultilanguageField.providedBy(field): @@ -54,7 +54,7 @@ def scale(self, fieldname=None, scale=None, **parameters): field.resetLanguage() fieldname = '%s___%s___' % (fieldname, field._v_lang or field._getCurrentLanguage(self.context)) - image = self.__old_scale(fieldname, scale, **parameters) + image = self.__old_scale(fieldname, scale, height, width, **parameters) if IMultilanguageField.providedBy(field): field.resetLanguage() From 5c4d20d11184679b1870ae9910ae5f2315b38829 Mon Sep 17 00:00:00 2001 From: Sebastian Gottfried Date: Fri, 10 Feb 2017 10:40:16 +0100 Subject: [PATCH 7/8] Fix Lazy Initialization Wrt plone.protect The multilanguage indexes create their per-language subindexes lazely. This has to be marked as a safe write if one is using the automatic CSRF protection of plone.protect. --- raptus/multilanguagefields/indexes/UnIndex.py | 13 +++++++++++++ raptus/multilanguagefields/indexes/ZCTextIndex.py | 11 +++++++++++ 2 files changed, 24 insertions(+) diff --git a/raptus/multilanguagefields/indexes/UnIndex.py b/raptus/multilanguagefields/indexes/UnIndex.py index f93fe56..cbc1753 100644 --- a/raptus/multilanguagefields/indexes/UnIndex.py +++ b/raptus/multilanguagefields/indexes/UnIndex.py @@ -16,6 +16,13 @@ from Products.PluginIndexes.common import safe_callable from Products.PluginIndexes.common.UnIndex import UnIndex, _marker +try: + from plone.protect.utils import safeWrite +except ImportError: + def safeWrite(obj, request=None): + pass + + class MultilanguageUnIndex(UnIndex): """Multilanguage aware forward and reverse index. """ @@ -60,6 +67,9 @@ def _del_length(self): def _get_lang_index(self, lang): if not self._d_index.has_key(lang): self._d_index[lang] = OOBTree() + safeWrite(self) + safeWrite(self._d_index) + safeWrite(self._d_index[lang]) return self._d_index[lang] def _set_index(self, value): @@ -85,6 +95,9 @@ def _del_index(self): def _get_lang_unindex(self, lang): if not self._d_unindex.has_key(lang): self._d_unindex[lang] = IOBTree() + safeWrite(self) + safeWrite(self._d_unindex) + safeWrite(self._d_unindex[lang]) return self._d_unindex[lang] def _set_unindex(self, value): diff --git a/raptus/multilanguagefields/indexes/ZCTextIndex.py b/raptus/multilanguagefields/indexes/ZCTextIndex.py index 44abee6..261d8d6 100644 --- a/raptus/multilanguagefields/indexes/ZCTextIndex.py +++ b/raptus/multilanguagefields/indexes/ZCTextIndex.py @@ -15,6 +15,13 @@ from Products.PluginIndexes.common import safe_callable from Products.CMFCore.utils import getToolByName +try: + from plone.protect.utils import safeWrite +except ImportError: + def safeWrite(obj, request=None): + pass + + class MultilanguageZCTextIndex(ZCTextIndex): """Multilanguage Persistent text index. """ @@ -39,6 +46,8 @@ def languages(self): def _get_lang_index(self, lang): if not hasattr(self, '_index_%s' % lang): setattr(self, '_index_%s' % lang, self._index_factory(aq_base(self.getLexicon()))) + safeWrite(self) + safeWrite(self, getattr(self, '_index_%s' % lang)) return getattr(self, '_index_%s' % lang) def _set_index(self, value): @@ -74,6 +83,8 @@ def getLexicon(self): raise TypeError('Object "%s" is not a ZCTextIndex Lexicon' % repr(lexicon)) self._v_lexicon = lexicon + safeWrite(self) + safeWrite(lexicon) return lexicon ## Pluggable Index APIs ## From aa8d3703f7309a4d5c3b5187fd152f7ef68d4a7b Mon Sep 17 00:00:00 2001 From: Paul Grunewald Date: Tue, 14 Mar 2017 14:21:56 +0100 Subject: [PATCH 8/8] Update HISTORY.txt --- docs/HISTORY.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/HISTORY.txt b/docs/HISTORY.txt index ba7bdcc..6839a9c 100644 --- a/docs/HISTORY.txt +++ b/docs/HISTORY.txt @@ -4,8 +4,12 @@ Changelog 1.1b12 (unreleased) ------------------- -- Nothing changed yet. - +- Required fields are not dependent from language fallback anymore [sebasgo] +- Reset language after scaling images [pgrunewald] +- Make indices resilient [sebasgo] +- Fix Image Bobo traversing for fullscreen view [sebasgo] +- Allow language fallback for brains [pgrunewald] +- Fix lazy initialization with respect to plone.protect [sebasgo] 1.1b11 (2017-01-09) ------------------- @@ -16,7 +20,7 @@ Changelog 1.1b10 (2014-12-05) ------------------- -* Renamed protected TAL keyword 'translate' to 'multilanguage' +* Renamed protected TAL keyword 'translate' to 'multilanguage' [pgrunewald] 1.1b9 (2014-06-24)