from AccessControl import getSecurityManager
from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.SecurityManagement import setSecurityManager
from AccessControl.User import UnrestrictedUser
from Acquisition import aq_parent
from Products.CMFCore.utils import getToolByName
from import IDexterityTranslatable
from import ILanguage
from import ILanguageIndependentFieldsManager
from import IMultiLanguageExtraOptionsSchema
from import ITranslationManager
from plone.dexterity.interfaces import IDexterityFTI
from plone.registry.interfaces import IRegistry
from zope.component import getUtility
from zope.component import queryAdapter
from zope.component.hooks import getSite
from zope.event import notify
from zope.lifecycleevent import Attributes
from zope.lifecycleevent import ObjectModifiedEvent
from zope.lifecycleevent.interfaces import IObjectModifiedEvent
class LanguageIndependentModifier(object):
    """Class to handle dexterity editions."""
    def __call__(self, content, event):
        """Called by the event system."""
        if aq_parent(content) is None:
            # The event is thrown on a non acquired object
            # so we can't get the session_data_manager
            sdm = getSite().session_data_manager
            sdm = getToolByName(content, 'session_data_manager')
        session = sdm.getSessionData()
        if 'tg' in session.keys():
            # In case it's a on the fly translation avoid 
        if IDexterityTranslatable.providedBy(content):
            self.canonical = ITranslationManager(content).query_canonical()
            if event.descriptions \
               and len(event.descriptions) > 1 \
               and event.descriptions[1] == self.canonical:
            if IObjectModifiedEvent.providedBy(event):
    def bypass_security_checks(self):
        registry = getUtility(IRegistry)
        # BBB for lrf-branch
        field = registry.records.get(
            IMultiLanguageExtraOptionsSchema.__identifier__ +
        return field and field.value or False
    def handle_modified(self, content):
        fieldmanager = ILanguageIndependentFieldsManager(content)
        if not fieldmanager.has_independent_fields():
        sm = getSecurityManager()
            # Do we have permission to sync language independent fields?
            if self.bypass_security_checks():
                # Clone the current user and assign a new editor role to
                # allow edition of all translated objects even if the
                # current user whould not have permission to do that.
                tmp_user = UnrestrictedUser(
                    sm.getUser().getId(), '', ['Editor', ], '')
                # Wrap the user in the acquisition context of the portal
                # and finally switch the user to our new editor
                acl_users = getToolByName(content, 'acl_users')
                tmp_user = tmp_user.__of__(acl_users)
                newSecurityManager(None, tmp_user)
            # Copy over all language independent fields
            transmanager = ITranslationManager(content)
            for translation in self.get_all_translations(content):
                trans_obj = transmanager.get_translation(translation)
                if fieldmanager.copy_fields(trans_obj):
            # Restore the old security manager
    def reindex_translation(self, translation):
        """Once the modification is done, reindex translation"""
        fti = getUtility(IDexterityFTI, name=translation.portal_type)
        schema = fti.lookupSchema()
        descriptions = Attributes(schema)
        # Pass the canonical object as a event description
        notify(ObjectModifiedEvent(translation, descriptions, self.canonical))
    def get_all_translations(self, content):
        """Return all translations excluding the just modified content"""
        content_lang = queryAdapter(content, ILanguage).get_language()
        translations = ITranslationManager(content).get_translated_languages()
        return translations
handler = LanguageIndependentModifier()