Example #1
0
def migrate_versionId_storage(obj):
    """Migrate storage of versionId
    """

    old_storage = obj.__annotations__.get("versionId")
    if not old_storage:
        msg = "no versionId stored for %s, but preset in catalog" % obj.absolute_url()
        logger.warning(msg)

    if isinstance(old_storage, basestring):
        msg = "Skipping migration of versionId for %s, " "already migrated" % obj
        return

    versionId = obj.__annotations__["versionId"]["versionId"].strip()
    obj.__annotations__["versionId"] = versionId

    # has versionId set but does not provide IVersionEnhanced
    # all versioned objects should provide IVersionEnhanced
    if versionId and not IVersionEnhanced.providedBy(obj):
        logger.info("versionId assigned without IVersionEnhanced " "provided %s", obj.absolute_url())
        alsoProvides(obj, IVersionEnhanced)

    # doesn't have a good versionId (could be empty string),
    # but provides IVersionEnhanced. Will supply object with new versionId
    if not versionId and IVersionEnhanced.providedBy(obj):
        obj.__annotations__["versionId"] = _random_id(obj)

    msg = "Migrated versionId storage for %s (%s)" % (obj.absolute_url(), versionId)
    logger.info(msg)
Example #2
0
def migrate_versionId_storage(obj):
    """Migrate storage of versionId
    """

    old_storage = obj.__annotations__.get('versionId')
    if not old_storage:
        msg = ("no versionId stored for %s, but preset in catalog" %
               obj.absolute_url())
        logger.warning(msg)

    if isinstance(old_storage, basestring):
        msg = ("Skipping migration of versionId for %s, "
               "already migrated" % obj)
        return

    versionId = obj.__annotations__['versionId']['versionId'].strip()
    obj.__annotations__['versionId'] = versionId

    #has versionId set but does not provide IVersionEnhanced
    #all versioned objects should provide IVersionEnhanced
    if versionId and not IVersionEnhanced.providedBy(obj):
        logger.info(
            "versionId assigned without IVersionEnhanced "
            "provided %s", obj.absolute_url())
        alsoProvides(obj, IVersionEnhanced)

    #doesn't have a good versionId (could be empty string),
    #but provides IVersionEnhanced. Will supply object with new versionId
    if not versionId and IVersionEnhanced.providedBy(obj):
        obj.__annotations__['versionId'] = _random_id(obj)

    msg = "Migrated versionId storage for %s (%s)" % \
            (obj.absolute_url(), versionId)
    logger.info(msg)
Example #3
0
    def __call__(self):
        catalog = self.context.portal_catalog
        index = self.request.form.get('index')
        portal_type = self.request.form.get('portal_type')
        fix = self.request.form.get("fix")

        results = self.not_indexed_results(catalog, index)

        out = StringIO()
        results = [
            z for z in results
            if (z.portal_type == portal_type) and self.get_real_versionid(z)
        ]

        print >> out, "Got %s results" % len(results)
        for brain in results:
            print >> out, brain.portal_type, brain.getURL()
            if fix:
                obj = brain.getObject()
                if not IVersionEnhanced.providedBy(obj):
                    alsoProvides(obj, IVersionEnhanced)
                obj.reindexObject()

        if fix:
            print >> out, "Fixed, try calling again this page "\
                          "to see if different"

        out.seek(0)

        return out.read()
Example #4
0
    def __call__(self):
        catalog = self.context.portal_catalog
        index = self.request.form.get('index')
        portal_type = self.request.form.get('portal_type')
        fix = self.request.form.get("fix")

        results = self.not_indexed_results(catalog, index)

        out = StringIO()
        results = [z for z in results if
                (z.portal_type == portal_type) and self.get_real_versionid(z)]

        print >> out, "Got %s results" % len(results)
        for brain in results:
            print >> out, brain.portal_type, brain.getURL()
            if fix:
                obj = brain.getObject()
                if not IVersionEnhanced.providedBy(obj):
                    alsoProvides(obj, IVersionEnhanced)
                obj.reindexObject()

        if fix:
            print >> out, "Fixed, try calling again this page "\
                          "to see if different"

        out.seek(0)

        return out.read()
Example #5
0
def evolve(context):
    """ Migrate versionIds for objects that don't have them set
    """
    cat = context.portal_catalog
    brains = cat.searchResults(missing=True, Language="all")

    i = 0
    for brain in brains:
        obj = brain.getObject()
        if not IVersionEnhanced.providedBy(obj):
            continue

        # first, check the brain's versionId
        brain_version = brain.getVersionId
        if isinstance(brain_version, basestring) and brain_version:
            # everything fine
            continue

        if brain.portal_type == "Discussion Item":
            continue  # skipping Discussion Items, they can't be reindexed

        versionId = IGetVersions(obj).versionId
        if isinstance(brain_version, basestring) and not brain_version.strip():
            # an empty string, assigning new versionId
            IAnnotations(obj)[VERSION_ID] = _random_id(obj)
            #obj.reindexObject()
            msg = "Migrated versionId storage (empty string) for %s (%s)" % \
                    (obj.absolute_url(), versionId)
            logger.info(msg)
            if (i % 500) == 0:
                transaction.commit()
            i += 1
            continue

        if isinstance(versionId, basestring) and not versionId.strip():
            # an empty string, assigning new versionId
            IAnnotations(obj)[VERSION_ID] = _random_id(obj)
            #obj.reindexObject()
            msg = "Migrated versionId storage (empty string) for %s (%s)" % \
                    (obj.absolute_url(), versionId)
            logger.info(msg)
            if (i % 500) == 0:
                transaction.commit()
            i += 1
            continue

        if not brain.getVersionId:
            IAnnotations(obj)[VERSION_ID] = _random_id(obj)
            #obj.reindexObject()
            msg = "Migrated versionId storage (empty storage) for %s (%s)" % \
                    (obj.absolute_url(), versionId)
            logger.info(msg)
            if (i % 500) == 0:
                transaction.commit()
            i += 1
            continue

        migrate_versionId_storage(obj)  #this is an old storage:
Example #6
0
def evolve(context):
    """ Migrate versionIds for objects that don't have them set
    """
    cat = context.portal_catalog
    brains = cat.searchResults(missing=True, Language="all")

    i = 0
    for brain in brains:
        obj = brain.getObject()
        if not IVersionEnhanced.providedBy(obj):
            continue

        # first, check the brain's versionId
        brain_version = brain.getVersionId
        if isinstance(brain_version, basestring) and brain_version:
            # everything fine
            continue

        if brain.portal_type == "Discussion Item":
            continue    # skipping Discussion Items, they can't be reindexed

        versionId = IGetVersions(obj).versionId
        if isinstance(brain_version, basestring) and not brain_version.strip():
            # an empty string, assigning new versionId
            IAnnotations(obj)[VERSION_ID] = _random_id(obj)
            #obj.reindexObject()
            msg = "Migrated versionId storage (empty string) for %s (%s)" % \
                    (obj.absolute_url(), versionId)
            logger.info(msg)
            if (i % 500) == 0:
                transaction.commit()
            i += 1
            continue

        if isinstance(versionId, basestring) and not versionId.strip():
            # an empty string, assigning new versionId
            IAnnotations(obj)[VERSION_ID] = _random_id(obj)
            #obj.reindexObject()
            msg = "Migrated versionId storage (empty string) for %s (%s)" % \
                    (obj.absolute_url(), versionId)
            logger.info(msg)
            if (i % 500) == 0:
                transaction.commit()
            i += 1
            continue

        if not brain.getVersionId:
            IAnnotations(obj)[VERSION_ID] = _random_id(obj)
            #obj.reindexObject()
            msg = "Migrated versionId storage (empty storage) for %s (%s)" % \
                    (obj.absolute_url(), versionId)
            logger.info(msg)
            if (i % 500) == 0:
                transaction.commit()
            i += 1
            continue

        migrate_versionId_storage(obj)  #this is an old storage:
Example #7
0
def assign_version(context, new_version):
    """ Assign a specific version id to an object
    """

    # Verify if there are more objects under this version
    cat = getToolByName(context, 'portal_catalog')
    brains = cat.searchResults({'getversionid': new_version,
                                'show_inactive': True})
    if brains and not IVersionEnhanced.providedBy(context):
        alsoProvides(context, IVersionEnhanced)
    if len(brains) == 1:
        target_ob = brains[0].getObject()
        if not IVersionEnhanced.providedBy(target_ob):
            alsoProvides(target_ob, IVersionEnhanced)

    # Set new version ID
    verparent = IVersionControl(context)
    verparent.setVersionId(new_version)
    context.reindexObject()
Example #8
0
 def __init__(self, context, request):
     state = getMultiAdapter((context, request), name='plone_context_state')
     # #91514 fix for folders with a default view set, when creating a
     # version, we need the folder, not the page
     parent = state.canonical_object()
     if IVersionEnhanced.providedBy(parent):
         self.context = parent
     else:
         self.context = context
     self.url = self.context.absolute_url()
     self.request = request
Example #9
0
 def __init__(self, context, request):
     state = getMultiAdapter((context, request), name='plone_context_state')
     # #91514 fix for folders with a default view set, when creating a
     # version, we need the folder, not the page
     parent = state.canonical_object()
     if IVersionEnhanced.providedBy(parent):
         self.context = parent
     else:
         self.context = context
     self.url = self.context.absolute_url()
     self.request = request
Example #10
0
def assign_version(context, new_version):
    """ Assign a specific version id to an object
    """

    # Verify if there are more objects under this version
    cat = getToolByName(context, 'portal_catalog')
    brains = cat.searchResults({
        'getVersionId': new_version,
        'show_inactive': True
    })
    if brains and not IVersionEnhanced.providedBy(context):
        alsoProvides(context, IVersionEnhanced)
    if len(brains) == 1:
        target_ob = brains[0].getObject()
        if not IVersionEnhanced.providedBy(target_ob):
            alsoProvides(target_ob, IVersionEnhanced)

    # Set new version ID
    verparent = IVersionControl(context)
    verparent.setVersionId(new_version)
    context.reindexObject(idxs=['getVersionId'])
Example #11
0
def migrate_versionId_storage(obj):
    """Migrate storage of versionId
    """

    raw_versionId = obj.__annotations__["versionId"]["versionId"]
    logger.info("versionID: %s", raw_versionId)
    versionId = raw_versionId.strip()

    # doesn't have a good versionId (could be empty string),
    if not versionId and IVersionEnhanced.providedBy(obj):
        obj.__annotations__["versionId"] = _random_id(obj)
    else:
        obj.__annotations__["versionId"] = versionId

    msg = "Migrated versionId storage (old version) for %s (%s)" % (obj.absolute_url(), versionId)

    logger.info(msg)
Example #12
0
def migrate_versionId_storage(obj):
    """Migrate storage of versionId
    """

    raw_versionId = obj.__annotations__['versionId']['versionId']
    logger.info('versionID: %s', raw_versionId)
    versionId = raw_versionId.strip()

    #doesn't have a good versionId (could be empty string),
    if not versionId and IVersionEnhanced.providedBy(obj):
        obj.__annotations__['versionId'] = _random_id(obj)
    else:
        obj.__annotations__['versionId'] = versionId

    msg = "Migrated versionId storage (old version) for %s (%s)" % \
            (obj.absolute_url(), versionId)

    logger.info(msg)
Example #13
0
    def __init__(self, context):
        """ Constructor
        """
        request = getattr(context, 'REQUEST', None)
        state = getMultiAdapter((context, request), name='plone_context_state')
        # #91514 fix for folders with a default view set, when creating a
        # version, we need the folder, not the page
        self.context = context
        if state.is_default_page():
            parent = aq_parent(context)
            if IVersionEnhanced.providedBy(parent):
                self.context = parent

        self.versionId = IVersionControl(self.context).versionId

        failsafe = lambda obj: "Unknown"
        self.state_title_getter = queryMultiAdapter(
            (self.context, request), name=u'getWorkflowStateTitle') or failsafe
Example #14
0
    def __init__(self, context):
        """ Constructor
        """
        request = getattr(context, 'REQUEST', None)
        state = getMultiAdapter((context, request), name='plone_context_state')
        # #91514 fix for folders with a default view set, when creating a
        # version, we need the folder, not the page
        self.context = context
        if state.is_default_page():
            parent = aq_parent(context)
            if IVersionEnhanced.providedBy(parent):
                self.context = parent

        self.versionId = IVersionControl(self.context).versionId

        failsafe = lambda obj: "Unknown"
        self.state_title_getter = queryMultiAdapter(
            (self.context, request), name=u'getWorkflowStateTitle') or failsafe
Example #15
0
    def __call__(self):
        event = self.event
        service_to_ping = self.element.service_to_ping
        obj = self.event.object
        container = obj.getParentNode()
        noasync_msg = 'No instance for async operations was defined.'

        def pingCRSDS(service_to_ping, obj_url, create):
            """ Ping the CR/SDS service
            """
            if async_service is None:
                logger.warn("Can't pingCRSDS, plone.app.async not installed!")
                return

            options = {}
            options['service_to_ping'] = service_to_ping
            options['obj_url'] = self.sanitize_url(obj_url)
            options['create'] = create
            queue = async_service.getQueues()['']
            try:
                async_service.queueJobInQueue(queue, ('rdf', ), ping_CRSDS,
                                              self.context, options)
            except ComponentLookupError:
                logger.info(noasync_msg)

        def pingCRSDS_backrel(service_to_ping, obj, create):
            """ Ping backward relations
            """
            back_relations = obj.getBRefs('relatesTo')
            for rel in back_relations:
                if rel is not None:
                    obj_url = "%s/@@rdf" % rel.absolute_url()
                    pingCRSDS(service_to_ping, obj_url, create)

        def pingCRSDS_children(service_to_ping, obj, create):
            """ Ping all sub-objects
            """
            if obj.portal_type == "Discussion Item":
                # 22047 skip object if it's of type Discussion Item
                return
            for child in obj.objectIds():
                child_obj = obj.get(child)
                if not child_obj:
                    logger.info("Couldn't retrieve child id %s for %s", child,
                                obj.absolute_url())
                    continue
                obj_url = "%s/@@rdf" % child_obj.absolute_url()
                pingCRSDS(service_to_ping, obj_url, create)
                pingCRSDS_children(service_to_ping, child_obj, create)

        # When no request the task is called from a async task, see #19830
        request = getattr(obj, 'REQUEST', None)

        # Detect special object used to force acquisition, see #18904
        if isinstance(request, str):
            request = None

        create = IObjectAddedEvent.providedBy(event)

        if service_to_ping == "":
            return

        if hasVersionsInstalled and IVersionEnhanced.providedBy(obj) \
                and request:
            obj_versions = IGetVersions(obj).versions()
        else:
            obj_versions = [obj]

        async_service = queryUtility(IAsyncService)

        # If object has translations
        if hasLinguaPloneInstalled and ITranslatable.providedBy(obj):
            if obj.isCanonical():
                # Ping all translations
                for trans in obj.getTranslations().items():
                    if trans[0] != 'en':
                        trans_obj = trans[1][0]
                        obj_url = trans_obj.absolute_url()
                        pingCRSDS(service_to_ping, obj_url, create)
            else:
                # Ping only canonical
                can_obj = obj.getCanonical()
                obj_url = can_obj.absolute_url()
                pingCRSDS(service_to_ping, obj_url, create)

        # If object was deleted
        if IObjectRemovedEvent.providedBy(event):
            # Ping backward relations
            pingCRSDS_backrel(service_to_ping, obj, create)

            # Ping all sub-objects
            pingCRSDS_children(service_to_ping, obj, create)

        # If object was moved/renamed first ping with the old object's URL
        if IObjectMovedOrRenamedEvent.providedBy(event):
            obj_url = "%s/%s/@@rdf" % (event.oldParent.absolute_url(),
                                       event.oldName)
            pingCRSDS(service_to_ping, obj_url, False)

            # then ping with the container of the old object
            obj_url = "%s/@@rdf" % event.oldParent.absolute_url()
            pingCRSDS(service_to_ping, obj_url, False)

            # Ping backward relations
            pingCRSDS_backrel(service_to_ping, obj, create)

            # Ping all sub-objects
            pingCRSDS_children(service_to_ping, obj, create)

        # Ping each version
        for obj in obj_versions:
            obj_url = "%s/@@rdf" % obj.absolute_url()
            pingCRSDS(service_to_ping, obj_url, create)

        # If no Aquisition there is no container, see #18904
        if container:
            obj_url = "%s/@@rdf" % container.absolute_url()
            pingCRSDS(service_to_ping, obj_url, False)

        return True
Example #16
0
    def versions(self):
        """ Return a list of sorted version objects
        """
        # Avoid making a catalog call if versionId is empty
        if not self.versionId:
            return [self.context]

        if not isinstance(self.versionId, basestring):
            return [self.context]  # this is an old, unmigrated storage
        cat = getToolByName(self.context, 'portal_catalog', None)
        if not cat:
            return []
        query = {'getVersionId': self.versionId}

        mtool = getToolByName(self.context, 'portal_membership')
        if mtool.isAnonymousUser():
            query['review_state'] = 'published'
            brains = cat.unrestrictedSearchResults(**query)
        else:
            brains = cat(**query)
        objects = []
        for b in brains:
            try:
                obj = b.getObject()
            except Exception as err:
                # Because of the unrestricted search done above, this
                # might happen, and we don't need a crash. Also do not
                # crash if the object is missing/not re-indexed yet.
                logger.warn(err)
                continue
            else:
                # #93975: before #91514 versions were sometimes incorrectly
                # created in that pages set as default view were assigned as
                # versions for folders. For such cases we need to replace the
                # page with the 'canonical_object'
                state = getMultiAdapter((obj, self.context.REQUEST),
                                        name='plone_context_state')
                canonical_obj = state.canonical_object()
                if IVersionEnhanced.providedBy(
                        canonical_obj) and canonical_obj != obj:
                    canonical_obj_version = IAnnotations(canonical_obj)[
                        VERSION_ID]
                    if canonical_obj_version != self.versionId:
                        query['getVersionId'] = canonical_obj_version
                        o_brains = cat.unrestrictedSearchResults(**query)
                        if len(o_brains) > 1:
                            logger.warn(
                                'DefaultView: Object %s has different '
                                'version id than its default view' %
                                canonical_obj.absolute_url())
                        else:
                            assign_version(canonical_obj, self.versionId)
                            RevokeVersion(obj, self.context.REQUEST).__call__()
                            logger.warn(
                                'DefaultView: Version id moved from default '
                                'view to canonical object for %s' %
                                canonical_obj.absolute_url())
                    else:
                        # the default view had the same version id as
                        # the canonical object, thre is no need for that
                        RevokeVersion(obj, self.context.REQUEST).__call__()
                    if canonical_obj not in objects:
                        objects.append(canonical_obj)
                else:
                    if obj not in objects:
                        objects.append(obj)

        # Some objects don't have EffectiveDate so we have to sort
        # them using CreationDate. This has the side effect that
        # in certain conditions the list of versions is reordered
        # For the anonymous users this is never a problem because
        # they only see published (and with effective_date) objects

        # during creation self.context has not been indexed
        if not self.context.UID() in [o.UID() for o in objects if o]:
            objects.append(self.context)

        # Store versions as ordered list, with the oldest item first
        # #20827 check if creation_date isn't bigger than the effective
        # date of the object as there are situation where the effective_date
        # is smaller such as for object without an workflow like FigureFile
        _versions = sorted(
            objects, key=lambda ob: ob.effective_date if ob.effective_date
            else ob.creation_date)

        return _versions
Example #17
0
    def __call__(self):
        event = self.event
        service_to_ping = self.element.service_to_ping
        obj = self.event.object
        container = obj.getParentNode()
        noasync_msg = 'No instance for async operations was defined.'

        def pingCRSDS(service_to_ping, obj_url, create):
            """ Ping the CR/SDS service
            """
            options = {}
            options['service_to_ping'] = service_to_ping
            options['obj_url'] = self.sanitize_url(obj_url)
            options['create'] = create

            # Use RabbitMQ if available
            if self.rabbit_config:
                options['create'] = 'create' if options.get(
                    'create', False) else 'update'
                return ping_RabbitMQ(options)

            # Use zc.async if available
            if async_service is None:
                logger.warn("Can't pingCRSDS, plone.app.async not installed!")
                return

            queue = async_service.getQueues()['']
            try:
                async_service.queueJobInQueue(
                    queue, ('rdf',),
                    ping_CRSDS, self.context, options
                )
            except ComponentLookupError:
                logger.info(noasync_msg)

        def pingCRSDS_backrel(service_to_ping, obj, create):
            """ Ping backward relations
            """
            if hasattr(obj, 'getBRefs'):
                back_relations = obj.getBRefs('relatesTo')
            else:
                back_relations = [o.to_object
                    for o in getattr(obj, 'relatedItems')
                ]

            for rel in back_relations:
                if rel is not None:
                    obj_url = "%s/@@rdf" % rel.absolute_url()
                    pingCRSDS(service_to_ping, obj_url, create)

        def pingCRSDS_children(service_to_ping, obj, create):
            """ Ping all sub-objects
            """
            if obj.portal_type == "Discussion Item":
                # 22047 skip object if it's of type Discussion Item
                return
            for child in obj.objectIds():
                child_obj = obj.get(child)
                if not child_obj:
                    logger.info(
                        "Couldn't retrieve child id %s for %s",
                        child, obj.absolute_url())
                    continue
                obj_url = "%s/@@rdf" % child_obj.absolute_url()
                pingCRSDS(service_to_ping, obj_url, create)
                pingCRSDS_children(service_to_ping, child_obj, create)

        # When no request the task is called from a async task, see #19830
        request = getattr(obj, 'REQUEST', None)

        # Detect special object used to force acquisition, see #18904
        if isinstance(request, str):
            request = None

        create = IObjectAddedEvent.providedBy(event)

        if service_to_ping == "":
            return

        if hasVersionsInstalled and IVersionEnhanced.providedBy(obj) \
                and request:
            obj_versions = IGetVersions(obj).versions()
        else:
            obj_versions = [obj]

        async_service = queryUtility(IAsyncService)

        # If object has translations
        if hasLinguaPloneInstalled and ITranslatable.providedBy(obj):
            if obj.isCanonical():
                # Ping all translations
                for trans in obj.getTranslations().items():
                    if trans[0] != 'en':
                        trans_obj = trans[1][0]
                        obj_url = trans_obj.absolute_url()
                        pingCRSDS(service_to_ping, obj_url, create)
            else:
                # Ping only canonical
                can_obj = obj.getCanonical()
                obj_url = can_obj.absolute_url()
                pingCRSDS(service_to_ping, obj_url, create)

        # If object was deleted
        if IObjectRemovedEvent.providedBy(event):
            # Ping backward relations
            pingCRSDS_backrel(service_to_ping, obj, create)

            # Ping all sub-objects
            pingCRSDS_children(service_to_ping, obj, create)

        # If object was moved/renamed first ping with the old object's URL
        if IObjectMovedOrRenamedEvent.providedBy(event):
            obj_url = "%s/%s/@@rdf" % (event.oldParent.absolute_url(),
                                       event.oldName)
            pingCRSDS(service_to_ping, obj_url, False)

            # then ping with the container of the old object
            obj_url = "%s/@@rdf" % event.oldParent.absolute_url()
            pingCRSDS(service_to_ping, obj_url, False)

            # Ping backward relations
            pingCRSDS_backrel(service_to_ping, obj, create)

            # Ping all sub-objects
            pingCRSDS_children(service_to_ping, obj, create)

        # Ping each version
        for obj in obj_versions:
            obj_url = "%s/@@rdf" % obj.absolute_url()
            pingCRSDS(service_to_ping, obj_url, create)

        # If no Aquisition there is no container, see #18904
        if container:
            obj_url = "%s/@@rdf" % container.absolute_url()
            pingCRSDS(service_to_ping, obj_url, False)

        return True
Example #18
0
 def __call__(self):
     if not IVersionEnhanced.providedBy(self.context):
         return False
     return IVersionControl(self.context).can_version()
Example #19
0
def create_version(context, reindex=True):
    """ Create a new version of an object

    This is done by copy&pasting the object, then assigning, as
    versionId, the one from the original object.

    Additionally, we rename the object using a number based scheme and
    then clean it up to avoid various problems.
    """
    logger.info("Started creating version of %s", context.absolute_url())

    obj_id = context.getId()
    parent = utils.parent(context)

    # Adapt version parent (if case)
    if not IVersionEnhanced.providedBy(context):
        alsoProvides(context, IVersionEnhanced)

    # _ = IVersionControl(context).getVersionId()

    # Create version object
    # 1. copy object
    clipb = parent.manage_copyObjects(ids=[obj_id])

    # 2. pregenerate new id for the copy
    new_id = generateNewId(parent, obj_id)
    # 3. alter the clipboard data and inject the desired new id
    clipb_decoded = _cb_decode(clipb)
    clipb = _cb_encode((clipb_decoded[0], clipb_decoded[1], [new_id]))
    # 4. call paste operation
    manage_pasteObjects_Version(parent, clipb)
    # 5. get the version object - no need for a rename anymore
    ver = parent[new_id]

    # #31440 apply related items from original object to the new version
    ver.setRelatedItems(context.getRelatedItems())

    # Set effective date today
    ver.setCreationDate(DateTime())
    ver.setEffectiveDate(None)
    ver.setExpirationDate(None)

    mtool = getToolByName(context, 'portal_membership')
    auth_user = mtool.getAuthenticatedMember()
    auth_username = auth_user.getUserName()
    auth_username_list = [auth_username]
    current_creators = ver.Creators()
    auth_username_list.extend(current_creators)
    username_list = []
    for name in auth_username_list:
        if name == auth_username and name in username_list:
            continue
        else:
            username_list.append(name)
    new_creators = tuple(username_list)
    ver.setCreators(new_creators)

    # Remove comments
    if hasNewDiscussion:
        conversation = IConversation(ver)
        while conversation.keys():
            conversation.__delitem__(conversation.keys()[0])
    else:
        if hasattr(aq_base(ver), 'talkback'):
            tb = ver.talkback
            if tb is not None:
                for obj in tb.objectValues():
                    obj.__of__(tb).unindexObject()
                tb._container = PersistentMapping()

    notify(VersionCreatedEvent(ver, context))

    if reindex:
        ver.reindexObject()
        # some catalogued values of the context may depend on versions
        _reindex(context)

    logger.info("Created version at %s", ver.absolute_url())

    return ver
Example #20
0
def create_version(context, reindex=True):
    """ Create a new version of an object

    This is done by copy&pasting the object, then assigning, as
    versionId, the one from the original object.

    Additionally, we rename the object using a number based scheme and
    then clean it up to avoid various problems.
    """
    logger.info("Started creating version of %s", context.absolute_url())

    obj_id = context.getId()
    parent = utils.parent(context)

    # Adapt version parent (if case)
    if not IVersionEnhanced.providedBy(context):
        alsoProvides(context, IVersionEnhanced)

    # _ = IVersionControl(context).getVersionId()

    # Create version object
    clipb = parent.manage_copyObjects(ids=[obj_id])
    res = parent.manage_pasteObjects(clipb)

    new_id = res[0]['new_id']

    ver = getattr(parent, new_id)

    # Fixes the generated id: remove copy_of from ID
    # ZZZ: add -vX sufix to the ids
    vid = ver.getId()
    new_id = vid.replace('copy_of_', '')
    new_id = generateNewId(parent, new_id)
    parent.manage_renameObject(id=vid, new_id=new_id)
    ver = parent[new_id]

    # Set effective date today
    ver.setCreationDate(DateTime())
    ver.setEffectiveDate(None)
    ver.setExpirationDate(None)

    mtool = getToolByName(context, 'portal_membership')
    auth_user = mtool.getAuthenticatedMember()
    auth_username = auth_user.getUserName()
    auth_username_list = [auth_username]
    current_creators = ver.Creators()
    auth_username_list.extend(current_creators)
    username_list = []
    for name in auth_username_list:
        if name == auth_username and name in username_list:
            continue
        else:
            username_list.append(name)
    new_creators = tuple(username_list)
    ver.setCreators(new_creators)

    # Remove comments
    if hasNewDiscussion:
        conversation = IConversation(ver)
        while conversation.keys():
            conversation.__delitem__(conversation.keys()[0])
    else:
        if hasattr(aq_base(ver), 'talkback'):
            tb = ver.talkback
            if tb is not None:
                for obj in tb.objectValues():
                    obj.__of__(tb).unindexObject()
                tb._container = PersistentMapping()

    notify(VersionCreatedEvent(ver, context))

    if reindex:
        ver.reindexObject()
        # some catalogued values of the context may depend on versions
        _reindex(context)

    logger.info("Created version at %s", ver.absolute_url())

    return ver
Example #21
0
def isVersionEnhanced(context):
    """ Returns bool if context implements IVersionEnhanced
    """

    return bool(IVersionEnhanced.providedBy(context))
Example #22
0
 def __call__(self):
     if not IVersionEnhanced.providedBy(self.context):
         return False
     return IVersionControl(self.context).can_version()
Example #23
0
def create_version(context, reindex=True):
    """ Create a new version of an object

    This is done by copy&pasting the object, then assigning, as
    versionId, the one from the original object.

    Additionally, we rename the object using a number based scheme and
    then clean it up to avoid various problems.
    """
    logger.info("Started creating version of %s", context.absolute_url())

    obj_id = context.getId()
    parent = utils.parent(context)

    # Adapt version parent (if case)
    if not IVersionEnhanced.providedBy(context):
        alsoProvides(context, IVersionEnhanced)

    # _ = IVersionControl(context).getVersionId()

    # Create version object
    # 1. copy object
    clipb = parent.manage_copyObjects(ids=[obj_id])

    # 2. pregenerate new id for the copy
    new_id = generateNewId(parent, obj_id)
    # 3. alter the clipboard data and inject the desired new id
    clipb_decoded = _cb_decode(clipb)
    clipb = _cb_encode((clipb_decoded[0], clipb_decoded[1], [new_id]))
    # 4. call paste operation
    manage_pasteObjects_Version(parent, clipb)
    # 5. get the version object - no need for a rename anymore
    ver = parent[new_id]

    # #31440 apply related items from original object to the new version
    ver.setRelatedItems(context.getRelatedItems())

    # Set effective date today
    ver.setCreationDate(DateTime())
    ver.setEffectiveDate(None)
    ver.setExpirationDate(None)

    mtool = getToolByName(context, 'portal_membership')
    auth_user = mtool.getAuthenticatedMember()
    auth_username = auth_user.getUserName()
    auth_username_list = [auth_username]
    current_creators = ver.Creators()
    auth_username_list.extend(current_creators)
    username_list = []
    for name in auth_username_list:
        if name == auth_username and name in username_list:
            continue
        else:
            username_list.append(name)
    new_creators = tuple(username_list)
    ver.setCreators(new_creators)

    # Remove comments
    if hasNewDiscussion:
        conversation = IConversation(ver)
        while conversation.keys():
            conversation.__delitem__(conversation.keys()[0])
    else:
        if hasattr(aq_base(ver), 'talkback'):
            tb = ver.talkback
            if tb is not None:
                for obj in tb.objectValues():
                    obj.__of__(tb).unindexObject()
                tb._container = PersistentMapping()

    notify(VersionCreatedEvent(ver, context))

    if reindex:
        ver.reindexObject()
        # some catalogued values of the context may depend on versions
        _reindex(context)

    logger.info("Created version at %s", ver.absolute_url())

    return ver
Example #24
0
def isVersionEnhanced(context):
    """ Returns bool if context implements IVersionEnhanced
    """

    return bool(IVersionEnhanced.providedBy(context))
Example #25
0
    def versions(self):
        """ Return a list of sorted version objects
        """
        # Avoid making a catalog call if versionId is empty
        if not self.versionId:
            return [self.context]

        if not isinstance(self.versionId, basestring):
            return [self.context]  # this is an old, unmigrated storage
        cat = getToolByName(self.context, 'portal_catalog', None)
        if not cat:
            return []
        query = {'getVersionId': self.versionId}

        mtool = getToolByName(self.context, 'portal_membership')
        if mtool.isAnonymousUser():
            query['review_state'] = 'published'
            brains = cat.unrestrictedSearchResults(**query)
        else:
            brains = cat(**query)
        objects = []
        for b in brains:
            try:
                obj = b.getObject()
            except Exception as err:
                # Because of the unrestricted search done above, this
                # might happen, and we don't need a crash. Also do not
                # crash if the object is missing/not re-indexed yet.
                logger.warn(err)
                continue
            else:
                # #93975: before #91514 versions were sometimes incorrectly
                # created in that pages set as default view were assigned as
                # versions for folders. For such cases we need to replace the
                # page with the 'canonical_object'
                state = getMultiAdapter((obj, self.context.REQUEST),
                                        name='plone_context_state')
                canonical_obj = state.canonical_object()
                if IVersionEnhanced.providedBy(
                        canonical_obj) and canonical_obj != obj:
                    canonical_obj_version = IAnnotations(
                        canonical_obj)[VERSION_ID]
                    if canonical_obj_version != self.versionId:
                        query['getVersionId'] = canonical_obj_version
                        o_brains = cat.unrestrictedSearchResults(**query)
                        if len(o_brains) > 1:
                            logger.warn('DefaultView: Object %s has different '
                                        'version id than its default view' %
                                        canonical_obj.absolute_url())
                        else:
                            assign_version(canonical_obj, self.versionId)
                            RevokeVersion(obj, self.context.REQUEST).__call__()
                            logger.warn(
                                'DefaultView: Version id moved from default '
                                'view to canonical object for %s' %
                                canonical_obj.absolute_url())
                    else:
                        # the default view had the same version id as
                        # the canonical object, thre is no need for that
                        RevokeVersion(obj, self.context.REQUEST).__call__()
                    if canonical_obj not in objects:
                        objects.append(canonical_obj)
                else:
                    if obj not in objects:
                        objects.append(obj)

        # Some objects don't have EffectiveDate so we have to sort
        # them using CreationDate. This has the side effect that
        # in certain conditions the list of versions is reordered
        # For the anonymous users this is never a problem because
        # they only see published (and with effective_date) objects

        # during creation self.context has not been indexed
        if not self.context.UID() in [o.UID() for o in objects if o]:
            objects.append(self.context)

        # Store versions as ordered list, with the oldest item first
        # #20827 check if creation_date isn't bigger than the effective
        # date of the object as there are situation where the effective_date
        # is smaller such as for object without an workflow like FigureFile
        _versions = sorted(objects,
                           key=lambda ob: ob.effective_date
                           if ob.effective_date else ob.creation_date)

        return _versions