Example #1
0
 def test_addOrUpdateSeveralIndexes(self):
     """
     It is possible to pass several new indexes to addOrUpdateIndexes,
     in this case, only new indexes are added and updated.
     """
     # for now reversedUID index does not exist...
     self.assertTrue('reversedUID' not in self.catalog.indexes())
     # and add an existing index UID
     self.assertTrue(self.catalog.Indexes['UID'].getTagName() == 'UUIDIndex')
     # add a document prior to adding the index
     priorDocument = api.content.create(type='Document',
                                        id='prior-document',
                                        container=self.portal)
     addOrUpdateIndexes(
         self.portal,
         # use an ordered dict so UID, an existing index, is after the new one
         OrderedDict([
             ('reversedUID', ('FieldIndex', {})),
             ('UID', ('UUIDIndex', {}))])
     )
     self.assertTrue('reversedUID' in self.portal.portal_catalog.indexes())
     # moreover existing objects were updated
     brains = self.catalog(reversedUID=priorDocument.UID()[::-1])
     self.assertTrue(len(brains) == 1)
     self.assertTrue(brains[0].getObject().UID() == priorDocument.UID())
Example #2
0
def postInstall(context):
    """Called at the end of the setup process. """
    if isNotImioZamqpPmProfile(context):
        return
    site = context.getSite()

    addOrUpdateIndexes(site, indexInfos)
    addOrUpdateColumns(site, columnInfos)
    def run(self):
        logger.info('Migrating to collective.task 2.2')
        self.cleanRegistries()

        addOrUpdateIndexes(self.portal, indexInfos={'assigned_group': ('FieldIndex', {}), 'due_date': ('DateIndex', {})})
        addOrUpdateColumns(self.portal, columns=('assigned_group', 'due_date'))

        self.runProfileSteps('collective.task', steps=['typeinfo', 'workflow', 'cssregistry'])
        self.finish()
Example #4
0
 def test_updateIndexType(self):
     """
     If an index already exists with a given type, it can be updated
     to another given type.  Add an index of type 'FieldIndex' then
     turn it into a 'KeywordIndex'.
     """
     addOrUpdateIndexes(self.portal, {'reversedUID': ('FieldIndex', {})})
     # the added index type is 'FieldIndex'
     self.assertTrue(self.catalog._catalog.indexes['reversedUID'].meta_type == 'FieldIndex')
     # now add it as a KeyWordIndex
     addOrUpdateIndexes(self.portal, {'reversedUID': ('KeywordIndex', {})})
     self.assertTrue(self.catalog._catalog.indexes['reversedUID'].meta_type == 'KeywordIndex')
Example #5
0
def postInstall(context):
    """Called as at the end of the setup process. """
    # the right place for your custom code
    if isNotMeetingMonsProfile(context):
        return
    logStep("postInstall", context)
    site = context.getSite()
    # need to reinstall PloneMeeting after reinstalling MC workflows to re-apply wfAdaptations
    reinstallPloneMeeting(context, site)
    showHomeTab(context, site)
    reorderSkinsLayers(context, site)
    addOrUpdateIndexes(site, {'toCorrect': ('BooleanIndex', {})})
    addOrUpdateIndexes(site, {'corrected': ('BooleanIndex', {})})
Example #6
0
def postInstall(context):
    """Called as at the end of the setup process. """
    # the right place for your custom code
    if isNotMeetingCharleroiProfile(context):
        return
    logStep("postInstall", context)
    site = context.getSite()
    # need to reinstall PloneMeeting after reinstalling MC workflows to re-apply wfAdaptations
    reinstallPloneMeeting(context, site)
    showHomeTab(context, site)
    reorderSkinsLayers(context, site)
    # add the groupsOfMatter index
    addOrUpdateIndexes(site, {'financesAdviceCategory': ('FieldIndex', {})})
Example #7
0
    def run(self):
        logger.info('Migrating to collective.task 2.2')
        self.cleanRegistries()

        addOrUpdateIndexes(self.portal,
                           indexInfos={
                               'assigned_group': ('FieldIndex', {}),
                               'due_date': ('DateIndex', {})
                           })
        addOrUpdateColumns(self.portal, columns=('assigned_group', 'due_date'))

        self.runProfileSteps('collective.task',
                             steps=['typeinfo', 'workflow', 'cssregistry'])
        self.finish()
Example #8
0
 def test_updateIndexType(self):
     """
     If an index already exists with a given type, it can be updated
     to another given type.  Add an index of type 'FieldIndex' then
     turn it into a 'KeywordIndex'.
     """
     addOrUpdateIndexes(self.portal, {'reversedUID': ('FieldIndex', {})})
     # the added index type is 'FieldIndex'
     self.assertTrue(self.catalog._catalog.indexes['reversedUID'].meta_type
                     == 'FieldIndex')
     # now add it as a KeyWordIndex
     addOrUpdateIndexes(self.portal, {'reversedUID': ('KeywordIndex', {})})
     self.assertTrue(self.catalog._catalog.indexes['reversedUID'].meta_type
                     == 'KeywordIndex')
Example #9
0
 def test_addOrUpdateZCTextIndex(self):
     """
     While adding a ZCTextIndex, optional 'extra' record can be passed.
     If nothing available, default values are used.
     """
     addOrUpdateIndexes(self.portal,
                        {'sample_zctextindex': ('ZCTextIndex', {})})
     index = self.catalog._catalog.indexes['sample_zctextindex']
     # if no 'extra' record given, default values are used
     self.assertTrue(index.lexicon_id == ZCTextIndexInfo.lexicon_id)
     self.assertTrue(index._index_type == ZCTextIndexInfo.index_type)
     # we can also update an existing ZCTextIndex index
     indexInfos = ZCTextIndexInfo()
     indexInfos.lexicon_id = 'plaintext_lexicon'
     indexInfos.index_type = 'Cosine Measure'
     addOrUpdateIndexes(self.portal,
                        {'sample_zctextindex': ('ZCTextIndex', indexInfos)})
     index = self.catalog._catalog.indexes['sample_zctextindex']
     self.assertTrue(index.lexicon_id == indexInfos.lexicon_id)
     self.assertTrue(index._index_type == indexInfos.index_type)
     # we can change the indexType
     addOrUpdateIndexes(self.portal,
                        {'sample_zctextindex': ('FieldIndex', {})})
     self.assertTrue(self.catalog._catalog.indexes['sample_zctextindex'].
                     meta_type == 'FieldIndex')
     # and back to a ZCTextIndex
     addOrUpdateIndexes(self.portal,
                        {'sample_zctextindex': ('ZCTextIndex', {})})
     self.assertTrue(self.catalog._catalog.indexes['sample_zctextindex'].
                     meta_type == 'ZCTextIndex')
Example #10
0
 def test_addOrUpdateIndexes(self):
     """
     Normal usecase of addOrUpdateIndexes, this will add a new index of required type.
     Moreover existing objects will be updated.
     """
     # for now reversedUID index does not exist...
     self.assertTrue(not 'reversedUID' in self.catalog.indexes())
     # add a document prior to adding the index
     priorDocument = api.content.create(type='Document',
                                        id='prior-document',
                                        container=self.portal)
     addOrUpdateIndexes(self.portal, {'reversedUID': ('FieldIndex', {})})
     self.assertTrue('reversedUID' in self.portal.portal_catalog.indexes())
     # moreover existing objects were updated
     brains = self.catalog(reversedUID=priorDocument.UID()[::-1])
     self.assertTrue(len(brains) == 1)
     self.assertTrue(brains[0].getObject().UID() == priorDocument.UID())
Example #11
0
 def test_addOrUpdateIndexes(self):
     """
     Normal usecase of addOrUpdateIndexes, this will add a new index of required type.
     Moreover existing objects will be updated.
     """
     # for now reversedUID index does not exist...
     self.assertTrue('reversedUID' not in self.catalog.indexes())
     # add a document prior to adding the index
     priorDocument = api.content.create(type='Document',
                                        id='prior-document',
                                        container=self.portal)
     addOrUpdateIndexes(self.portal, {'reversedUID': ('FieldIndex', {})})
     self.assertTrue('reversedUID' in self.portal.portal_catalog.indexes())
     # moreover existing objects were updated
     brains = self.catalog(reversedUID=priorDocument.UID()[::-1])
     self.assertTrue(len(brains) == 1)
     self.assertTrue(brains[0].getObject().UID() == priorDocument.UID())
Example #12
0
 def test_addOrUpdateColumnsWithExistingIndex(self):
     """
     Normal usecase of addOrUpdateColumns, this will add a new column (metadata).
     Test here when a corresponding index exists.
     Moreover existing objects will be updated.
     """
     # for now reversedUID metadata does not exist...
     self.assertTrue('reversedUID' not in self.catalog.schema())
     # add a document prior to adding the index
     api.content.create(type='Document',
                        id='prior-document',
                        container=self.portal)
     addOrUpdateIndexes(self.portal, {'reversedUID': ('FieldIndex', {})})
     addOrUpdateColumns(self.portal, ('reversedUID', ))
     # the metadata was actually added
     self.assertTrue('reversedUID' in self.catalog.schema())
     # and existing objects were updated
     brains = self.catalog()
     for brain in brains:
         obj = brain.getObject()
         self.assertTrue(obj.UID()[::-1] == brain.reversedUID)
Example #13
0
 def test_addOrUpdateColumnsWithExistingIndex(self):
     """
     Normal usecase of addOrUpdateColumns, this will add a new column (metadata).
     Test here when a corresponding index exists.
     Moreover existing objects will be updated.
     """
     # for now reversedUID metadata does not exist...
     self.assertTrue(not 'reversedUID' in self.catalog.schema())
     # add a document prior to adding the index
     api.content.create(type='Document',
                        id='prior-document',
                        container=self.portal)
     addOrUpdateIndexes(self.portal, {'reversedUID': ('FieldIndex', {})})
     addOrUpdateColumns(self.portal, ('reversedUID', ))
     # the metadata was actually added
     self.assertTrue('reversedUID' in self.catalog.schema())
     # and existing objects were updated
     brains = self.catalog()
     for brain in brains:
         obj = brain.getObject()
         self.assertTrue(obj.UID()[::-1] == brain.reversedUID)
Example #14
0
    def perform_reference_number(self):
        """
        Add or update the reference_number index
        compute the reference_number per projectspace
        store the last_reference_number in projectspace
        update catalog
        """
        logger.info('Perform reference number ...')
        addOrUpdateIndexes(self.context, {'reference_number': ('FieldIndex', {})})
        catalog = api.portal.get_tool('portal_catalog')
        projectspaces = catalog(object_provides=IProjectSpace.__identifier__)
        for projectspace in projectspaces:
            path = '/'.join(self.portal.getPhysicalPath()) + '/' + projectspace.id
            brains = catalog(object_provides=IProject.__identifier__, path={'query': path, 'depth': 3}, sort_on='created')
            for num, brain in enumerate(brains):
                obj = brain.getObject()
                if obj.reference_number == 0:
                    obj.reference_number = num + 1
                    obj.reindexObject()
                    projectspace = getProjectSpace(obj)
                    projectspace.last_reference_number = num + 1

        logger.info('Done.')
Example #15
0
 def test_addOrUpdateSeveralIndexes(self):
     """
     It is possible to pass several new indexes to addOrUpdateIndexes,
     in this case, only new indexes are added and updated.
     """
     # for now reversedUID index does not exist...
     self.assertTrue('reversedUID' not in self.catalog.indexes())
     # and add an existing index UID
     self.assertTrue(
         self.catalog.Indexes['UID'].getTagName() == 'UUIDIndex')
     # add a document prior to adding the index
     priorDocument = api.content.create(type='Document',
                                        id='prior-document',
                                        container=self.portal)
     addOrUpdateIndexes(
         self.portal,
         # use an ordered dict so UID, an existing index, is after the new one
         OrderedDict([('reversedUID', ('FieldIndex', {})),
                      ('UID', ('UUIDIndex', {}))]))
     self.assertTrue('reversedUID' in self.portal.portal_catalog.indexes())
     # moreover existing objects were updated
     brains = self.catalog(reversedUID=priorDocument.UID()[::-1])
     self.assertTrue(len(brains) == 1)
     self.assertTrue(brains[0].getObject().UID() == priorDocument.UID())
Example #16
0
 def test_addOrUpdateZCTextIndex(self):
     """
     While adding a ZCTextIndex, optional 'extra' record can be passed.
     If nothing available, default values are used.
     """
     addOrUpdateIndexes(self.portal, {'sample_zctextindex': ('ZCTextIndex', {})})
     index = self.catalog._catalog.indexes['sample_zctextindex']
     # if no 'extra' record given, default values are used
     self.assertTrue(index.lexicon_id == ZCTextIndexInfo.lexicon_id)
     self.assertTrue(index._index_type == ZCTextIndexInfo.index_type)
     # we can also update an existing ZCTextIndex index
     indexInfos = ZCTextIndexInfo()
     indexInfos.lexicon_id = 'plaintext_lexicon'
     indexInfos.index_type = 'Cosine Measure'
     addOrUpdateIndexes(self.portal, {'sample_zctextindex': ('ZCTextIndex', indexInfos)})
     index = self.catalog._catalog.indexes['sample_zctextindex']
     self.assertTrue(index.lexicon_id == indexInfos.lexicon_id)
     self.assertTrue(index._index_type == indexInfos.index_type)
     # we can change the indexType
     addOrUpdateIndexes(self.portal, {'sample_zctextindex': ('FieldIndex', {})})
     self.assertTrue(self.catalog._catalog.indexes['sample_zctextindex'].meta_type == 'FieldIndex')
     # and back to a ZCTextIndex
     addOrUpdateIndexes(self.portal, {'sample_zctextindex': ('ZCTextIndex', {})})
     self.assertTrue(self.catalog._catalog.indexes['sample_zctextindex'].meta_type == 'ZCTextIndex')
Example #17
0
    def run(self):
        logger.info('Migrating to imio.dms.mail 1.0...')
        self.cleanRegistries()
        self.upgradeProfile('collective.dms.mailcontent:default')
        # We have to reapply type info before doing other subproducts migration
        self.runProfileSteps('imio.dms.mail', steps=['typeinfo'])
        # We have to update type schema because plone.dexterity doesn't detect schema_policy modification. BUG #44
        for portal_type in ['dmsincomingmail', 'dmsoutgoingmail']:  # i_e ok
            schemaName = dxutils.portalTypeToSchemaName(portal_type)
            schema = getattr(plone.dexterity.schema.generated, schemaName)
            fti = getUtility(IDexterityFTI, name=portal_type)
            model = fti.lookupModel()
            syncSchema(model.schema, schema, overwrite=True, sync_bases=True)
            notify(plone.dexterity.schema.SchemaInvalidatedEvent(portal_type))

        self.upgradeProfile('collective.task:default')
        self.upgradeProfile('dexterity.localroles:default')
        self.upgradeProfile('dexterity.localrolesfield:default')
        self.upgradeProfile('collective.contact.plonegroup:default')
        self.runProfileSteps('imio.dms.mail',
                             steps=[
                                 'actions', 'componentregistry',
                                 'controlpanel', 'plone.app.registry',
                                 'portlets', 'repositorytool', 'rolemap',
                                 'sharing', 'workflow'
                             ])
        self.portal.portal_workflow.updateRoleMappings()
        self.runProfileSteps('collective.dms.mailcontent',
                             steps=['controlpanel'])
        self.runProfileSteps('collective.contact.plonegroup',
                             steps=['controlpanel'])
        self.reinstall([
            'collective.messagesviewlet:messages',
            'collective.querynextprev:default',
            'imio.dashboard:default',
        ])

        # set jqueryui autocomplete to False. If not, contact autocomplete doesn't work
        self.registry[
            'collective.js.jqueryui.controlpanel.IJQueryUIPlugins.ui_autocomplete'] = False

        # delete old dmsmail portlet
        self.delete_portlet(self.portal, 'portlet_maindmsmail')

        # remove deprecated interfaces
        self.remove_contact_interfaces()

        # moved notes content to task_description
        catalog = api.portal.get_tool('portal_catalog')
        brains = catalog.searchResults(portal_type='dmsincomingmail')  # i_e ok
        for brain in brains:
            obj = brain.getObject()
            if not base_hasattr(obj, 'notes') or not obj.notes:
                continue
            text = u'<p>%s</p>\r\n' % obj.notes.replace('\r\n', '<br />\r\n')
            obj.task_description = richtextval(text)
            delattr(obj, 'notes')
        #    obj.reindexObject()

        # replace collections by Dashboard collections
        im_folder = self.portal['incoming-mail']
        alsoProvides(im_folder, INextPrevNotNavigable)
        alsoProvides(im_folder, IIMDashboard)
        self.replaceCollections(im_folder)

        # apply contact faceted config
        reimport_faceted_config(self.portal['contacts'],
                                'contacts-faceted.xml')

        # add new indexes for dashboard
        addOrUpdateIndexes(self.portal,
                           indexInfos={
                               'mail_type': ('FieldIndex', {}),
                               'mail_date': ('DateIndex', {}),
                               'in_out_date': ('DateIndex', {}),
                           })

        # set dashboard on incoming mail
        configure_faceted_folder(
            im_folder,
            xml='default_dashboard_widgets.xml',
            default_UID=im_folder['mail-searches']['all_mails'].UID())

        # set task local roles configuration
        configure_task_rolefields(self.portal)

        # update dexterity local roles configuration
        self.update_local_roles()

        # add task actionspanel config
        if not self.registry[
                'imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions']:
            self.registry['imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions'] = []
        self.registry['imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions'] += \
            ['task.back_in_created|', 'task.back_in_to_assign|', 'task.back_in_to_do|',
             'task.back_in_progress|', 'task.back_in_realized|']

        # activate ckeditor
        configure_ckeditor(self.portal, custom='ged')

        # Set markup allowed types
        adapter = MarkupControlPanelAdapter(self.portal)
        adapter.set_allowed_types(['text/html'])

        # update searchabletext
        self.update_dmsmainfile()

        self.upgradeAll()
        for prod in [
                'plone.formwidget.autocomplete', 'collective.documentviewer',
                'plone.formwidget.masterselect', 'collective.contact.core',
                'collective.contact.duplicated', 'collective.dms.basecontent',
                'collective.dms.scanbehavior', 'collective.externaleditor',
                'plone.app.collection', 'plone.app.intid',
                'collective.contact.facetednav', 'plonetheme.imioapps',
                'PasswordStrength', 'imio.dms.mail'
        ]:
            mark_last_version(self.portal, product=prod)

        self.portal.manage_permission(
            'CMFEditions: Revert to previous versions',
            ('Manager', 'Site Administrator'),
            acquire=0)

        #self.refreshDatabase()
        self.finish()
Example #18
0
    def run(self):
        logger.info('Migrating to imio.dms.mail 1.1...')
        self.cleanRegistries()
        self.runProfileSteps('imio.dms.mail', steps=['actions', 'cssregistry', 'jsregistry', 'workflow'])
        self.runProfileSteps('collective.messagesviewlet', steps=['collective-messagesviewlet-messages'],
                             profile='messages')
        self.upgradeProfile('collective.dms.mailcontent:default')
        self.upgradeProfile('collective.task:default')
        self.upgradeProfile('eea.facetednavigation:default')
        self.upgradeProfile('collective.querynextprev:default')
        im_folder = self.portal['incoming-mail']

        # set mail-searches folder as not next/prev navigable
        if not INextPrevNotNavigable.providedBy(im_folder['task-searches']):
            alsoProvides(im_folder['task-searches'], INextPrevNotNavigable)

        # activate field on DashboardCollection
        self.add_view_field('mail_type', im_folder['mail-searches'], before='CreationDate')
        self.add_view_field('sender', im_folder['mail-searches'], before='CreationDate')
        self.add_view_field('task_parent', im_folder['task-searches'], before='review_state')

        # set showNumberOfItems on some collections
        self.update_count(im_folder['mail-searches'], ids=['to_validate', 'to_treat', 'im_treating', 'created'])
        self.update_count(im_folder['task-searches'], ids=['to_validate', 'to_treat', 'im_treating'])

        # update criterion on validation collections
        self.update_validation_collections()

        # Activate browser message
        msg = self.portal['messages-config']['browser-warning']
        api.content.transition(obj=msg, to_state='activated')

        # update searchabletext
        self.update_dmsmainfile()
        self.update_dmsincomingmail()

        # add new indexes
        addOrUpdateIndexes(self.portal, indexInfos={'state_group': ('FieldIndex', {})})

        # add metadata in portal_catalog
        addOrUpdateColumns(self.portal, columns=('mail_type',))

        # block parent portlets on contacts
        blacklistPortletCategory(self.portal, self.portal['contacts'])

        # add local roles
        self.portal['contacts'].manage_addLocalRoles('dir_general', ['Contributor', 'Editor', 'Reader'])

        # configure autocomplete widget
        self.configure_autocomplete_widget(im_folder['mail-searches'])

        # configure task batch actions
        alsoProvides(im_folder['task-searches'], IIMTaskDashboard)

        # reimport contact faceted config
        reimport_faceted_config(self.portal['contacts'], xml='contacts-faceted.xml')

        # remove tinymce resources
        configure_ckeditor(self.portal, default=0, allusers=0, forceTextPaste=0, scayt=0)

        self.upgradeAll()

        self.runProfileSteps('imio.dms.mail', steps=['cssregistry', 'jsregistry'])

        # set jqueryui autocomplete to False. If not, contact autocomplete doesn't work
        self.registry['collective.js.jqueryui.controlpanel.IJQueryUIPlugins.ui_autocomplete'] = False

        for prod in ['plone.formwidget.autocomplete', 'collective.plonefinder', 'plone.formwidget.contenttree',
                     'plone.app.dexterity', 'plone.formwidget.masterselect', 'collective.behavior.talcondition',
                     'collective.contact.facetednav', 'collective.contact.plonegroup', 'collective.contact.widget',
                     'collective.dms.batchimport', 'collective.dms.scanbehavior', 'collective.documentgenerator',
                     'collective.eeafaceted.collectionwidget', 'collective.eeafaceted.z3ctable',
                     'collective.messagesviewlet', 'collective.querynextprev', 'dexterity.localroles',
                     'dexterity.localrolesfield', 'imio.actionspanel', 'imio.dashboard', 'imio.dms.mail',
                     'plone.formwidget.datetime', 'plonetheme.imioapps']:
            mark_last_version(self.portal, product=prod)

        #self.refreshDatabase()
        self.finish()
    def setUp(self):
        """Custom shared utility setup for tests."""
        super(TestCombinedIndex, self).setUp()
        # add the 'contained_types_and_states' to portal_catalog
        addOrUpdateIndexes(self.portal, {'contained_types_and_states': ('KeywordIndex', {})})
        # make sure we have a default workflow
        self.portal.portal_workflow.setDefaultChain('simple_publication_workflow')
        self.dashboardcollection = api.content.create(
            id='dc1',
            type='DashboardCollection',
            title='Dashboard collection 1',
            container=self.portal,
            sort_on='',
            sort_reversed=''
        )
        # this will by default query Folders
        self.dashboardcollection.query = [
            {'i': 'portal_type',
             'o': 'plone.app.querystring.operation.selection.is',
             'v': ['Folder', ]},
        ]
        # create 3 folders :
        # - first is empty;
        # - second contains one private Document and one published Document;
        # - third contains a private Folder.

        # folder1
        self.folder1 = api.content.create(
            id='folder1',
            type='Folder',
            title='Folder 1',
            container=self.portal
        )
        self.privatedoc = api.content.create(
            id='privatedoc',
            type='Document',
            title='Private document',
            container=self.portal.folder1
        )
        self.publicdoc = api.content.create(
            id='publicdoc',
            type='Document',
            title='Published document',
            container=self.portal.folder1
        )
        api.content.transition(self.publicdoc, 'publish')
        # folder2
        self.folder2 = api.content.create(
            id='folder2',
            type='Folder',
            title='Folder 2',
            container=self.portal
        )
        # folder3
        self.folder3 = api.content.create(
            id='folder3',
            type='Folder',
            title='Folder 3',
            container=self.portal
        )
        self.privatefolder = api.content.create(
            id='privatefolder',
            type='Folder',
            title='Private folder',
            container=self.portal.folder3
        )
        self.privatedoc2 = api.content.create(
            id='privatedoc2',
            type='Document',
            title='Private document 2',
            container=self.portal.folder3
        )
        # first check that contained_types_and_states index is correct
        self.folder1.reindexObject(idxs=['contained_types_and_states'])
        self.folder2.reindexObject(idxs=['contained_types_and_states'])
        self.folder3.reindexObject(idxs=['contained_types_and_states'])
        self.assertEquals(contained_types_and_states(self.folder1)(),
                          ['Document', 'Document__private', 'Document__published',
                           'private', 'published'])
        self.assertEquals(contained_types_and_states(self.folder2)(), [])
        self.assertEquals(contained_types_and_states(self.folder3)(),
                          ['Document', 'Document__private',
                           'Folder', 'Folder__private', 'private'])
Example #20
0
    def run(self):
        # Removed old import step
        setup = api.portal.get_tool('portal_setup')
        ir = setup.getImportStepRegistry()
        # /cputils_removeStep?step=imioprojectpst-adaptDefaultPortal
        if 'imioprojectpst-adaptDefaultPortal' in ir._registered:
            del ir._registered['imioprojectpst-adaptDefaultPortal']
        self.upgradeProfile('collective.contact.core:default')
        self.upgradeProfile('collective.contact.plonegroup:default')
        self.upgradeProfile('plone.formwidget.masterselect:default')
        self.reinstall(['dexterity.localrolesfield:default'])
        self.runProfileSteps('imio.project.pst',
                             steps=[
                                 'actions', 'catalog', 'componentregistry',
                                 'jsregistry', 'portlets', 'propertiestool',
                                 'plone.app.registry', 'typeinfo', 'workflow'
                             ])
        # update security settings
        self.portal.portal_workflow.updateRoleMappings()

        self.reinstall([
            'collective.documentgenerator:default',
            'collective.externaleditor:default',
            'collective.messagesviewlet:messages',
            'collective.task:default',
            'imio.dashboard:default',
            'plonetheme.imioapps:pstskin',
        ])

        self.various_update()

        indexes_to_add = {
            'categories': ('KeywordIndex', {}),
            'priority': ('FieldIndex', {}),
            'representative_responsible': ('KeywordIndex', {}),
            'administrative_responsible': ('KeywordIndex', {}),
            'manager': ('KeywordIndex', {}),
            'planned_begin_date': ('DateIndex', {}),
            'planned_end_date': ('DateIndex', {}),
            'effective_begin_date': ('DateIndex', {}),
            'effective_end_date': ('DateIndex', {}),
            'health_indicator': ('FieldIndex', {}),
            'progress': ('FieldIndex', {}),
            'extra_concerned_people': ('ZCTextIndex', {}),
        }
        addOrUpdateIndexes(self.context, indexes_to_add)

        # remove the old collections and configure the dashboard
        if 'collections' in self.portal.pst:
            api.content.delete(obj=self.portal.pst['collections'])
        for brain in self.pc(portal_type='Collection',
                             path='/'.join(self.portal.pst.getPhysicalPath())):
            api.content.delete(obj=brain.getObject())

        configureDashboard(self.portal.pst)
        self.portal.pst.setLayout('view')

        self.runProfileSteps('imio.project.pst',
                             steps=['portlets'],
                             profile='demo')

        # migrate oo fields
        brains = self.pc(portal_type="operationalobjective")
        for brain in brains:
            oo = brain.getObject()
            oo.administrative_responsible = [
                r[:-13] for r in oo.administrative_responsible
                if r.endswith('_actioneditor')
            ]
            oo.manager = [
                m[:-13] for m in oo.manager if m.endswith('_actioneditor')
            ]

        self.migrate_pst_action_fields()

        # update faceted navigation configs
        mapping = {
            'strategicobjectives': 'strategicobjective',
            'operationalobjectives': 'operationalobjective',
            'pstactions': 'pstaction',
        }
        for col_folder_id, content_type in mapping.iteritems():
            col_folder = self.portal.pst[col_folder_id]
            reimport_faceted_config(col_folder,
                                    xml='{}.xml'.format(content_type),
                                    default_UID=col_folder['all'].UID())

        add_plonegroups_to_registry()
        configure_actions_panel(self.portal)
        configure_rolefields(self.portal)

        # migrate to documentgenerator
        self.migrate_templates()

        self.upgradeAll()

        # add documentation message
        add_message(
            'doc1-0',
            'Documentation 1.0',
            u'<p>Vous pouvez consulter la <a href="http://www.imio.be/support'
            '/documentation/manual/gestion-de-projet-1.0" target="_blank">documentation en ligne de la '
            'nouvelle version</a>.</p>',
            msg_type='significant',
            can_hide=True,
            req_roles=['Authenticated'],
            activate=True)

        # update portal_catalog
        self.refreshDatabase()

        for prod in [
                'collective.ckeditor', 'collective.contact.core',
                'collective.contact.plonegroup', 'collective.plonefinder',
                'collective.quickupload', 'collective.z3cform.datagridfield',
                'imio.project.core', 'imio.project.pst', 'plonetheme.classic',
                'plone.app.collection', 'plone.app.dexterity',
                'plone.app.intid', 'plone.app.relationfield',
                'plone.formwidget.masterselect',
                'plone.formwidget.autocomplete', 'plone.formwidget.contenttree'
        ]:
            mark_last_version(self.portal, product=prod)

        # Reorder css and js
        self.runProfileSteps('imio.project.pst',
                             steps=['cssregistry', 'jsregistry'])

        # Display duration
        self.finish()
Example #21
0
    def run(self):
        logger.info('Migrating to imio.dms.mail 0.3.1...')
        self.reinstall(['collective.task:uninstall_1.0'])
        self.cleanRegistries()
        self.reinstall([
            'imio.actionspanel:default',
            'imio.history:default',
            'collective.task:default',
            'collective.compoundcriterion:default',
            'collective.behavior.talcondition:default',
            'collective.contact.facetednav:default',
            'collective.contact.duplicated:default',
            'plone.app.versioningbehavior:default',
        ])
        self.runProfileSteps('imio.dms.mail', ['actions', 'catalog', 'componentregistry', 'jsregistry',
                                               'plone.app.registry', 'rolemap', 'typeinfo',
                                               'update-workflow-rolemap', 'viewlets', 'workflow'])
        self.runProfileSteps('collective.dms.basecontent', ['atcttool', 'catalog'])
        self.runProfileSteps('collective.dms.scanbehavior', ['catalog'])

        api.portal.get_tool('portal_diff').setDiffForPortalType(
            'dmsincomingmail', {'any': "Compound Diff for Dexterity types"})
        self.createNotEncodedPerson()
        self.changeTopicsFolder()
        self.replaceRoleByGroup()
        self.portal.portal_workflow.updateRoleMappings()

        catalog = api.portal.get_tool('portal_catalog')
        brains = catalog.searchResults(portal_type='dmsincomingmail')
        if brains:
            factory = getUtility(IVocabularyFactory, 'collective.dms.basecontent.treating_groups')
            voc = factory(brains[0].getObject())
            good_values = voc.by_token
        for brain in brains:
            im = brain.getObject()
            new_incomingmail(im, None)
            if isinstance(im.treating_groups, list):
                if len(im.treating_groups) > 1:
                    logger.error("More than one treating_groups %s for %s object" % (im.treating_groups, im))
                    keep = None
                    for tg in im.treating_groups:
                        if tg in good_values:
                            keep = tg
                            break
                    logger.warn("Kept %s" % keep)
                    im.treating_groups = keep
                elif not im.treating_groups:
                    logger.warn("Replaced old value %s by first good value %s for %s object" % (im.treating_groups[0],
                                good_values.keys()[0], im))
                    im.treating_groups = good_values.keys()[0]
                elif im.treating_groups[0] in good_values:
                #elif catalog(UID=im.treating_groups[0]):
                    im.treating_groups = im.treating_groups[0]
                else:
                    logger.warn("Replaced old value %s by first good value %s for %s object" % (im.treating_groups[0],
                                good_values.keys()[0], im))
                    im.treating_groups = good_values.keys()[0]

        addOrUpdateIndexes(self.portal, indexInfos={'treating_groups': ('KeywordIndex', {}),
                                                    'recipient_groups': ('KeywordIndex', {}),
                                                    'organization_type': ('FieldIndex', {}),
                                                    })
        addOrUpdateColumns(self.portal, columns=('treating_groups', 'recipient_groups'))
        # a global recatalog is made after
        #brains = catalog.searchResults(portal_type='organization')
        #for brain in brains:
        #    brain.getObject().reindexObject(idxs=['organization_type'])

        setupFacetedContacts(self.portal)

        changeSearchedTypes(self.portal)

        configure_actions_panel(self.portal)

        self.upgradeAll()
        self.refreshDatabase()
        self.finish()
Example #22
0
    def run(self):
        logger.info('Migrating to imio.dms.mail 1.1...')
        self.cleanRegistries()
        self.runProfileSteps(
            'imio.dms.mail',
            steps=['actions', 'cssregistry', 'jsregistry', 'workflow'])
        self.runProfileSteps('collective.messagesviewlet',
                             steps=['collective-messagesviewlet-messages'],
                             profile='messages')
        self.upgradeProfile('collective.dms.mailcontent:default')
        self.upgradeProfile('collective.task:default')
        self.upgradeProfile('eea.facetednavigation:default')
        self.upgradeProfile('collective.querynextprev:default')
        im_folder = self.portal['incoming-mail']

        # set mail-searches folder as not next/prev navigable
        if not INextPrevNotNavigable.providedBy(im_folder['task-searches']):
            alsoProvides(im_folder['task-searches'], INextPrevNotNavigable)

        # activate field on DashboardCollection
        self.add_view_field('mail_type',
                            im_folder['mail-searches'],
                            before='CreationDate')
        self.add_view_field('sender',
                            im_folder['mail-searches'],
                            before='CreationDate')
        self.add_view_field('task_parent',
                            im_folder['task-searches'],
                            before='review_state')

        # set showNumberOfItems on some collections
        self.update_count(im_folder['mail-searches'],
                          ids=[
                              'to_validate', 'to_treat', 'im_treating',
                              'searchfor_created'
                          ])
        self.update_count(im_folder['task-searches'],
                          ids=['to_validate', 'to_treat', 'im_treating'])

        # update criterion on validation collections
        self.update_validation_collections()

        # Activate browser message
        msg = self.portal['messages-config']['browser-warning']
        api.content.transition(obj=msg, to_state='activated')

        # update searchabletext
        self.update_dmsmainfile()
        self.update_dmsincomingmail()

        # add new indexes
        addOrUpdateIndexes(self.portal,
                           indexInfos={'state_group': ('FieldIndex', {})})

        # add metadata in portal_catalog
        addOrUpdateColumns(self.portal, columns=('mail_type', ))

        # block parent portlets on contacts
        blacklistPortletCategory(self.portal['contacts'])

        # add local roles
        self.portal['contacts'].manage_addLocalRoles(
            'dir_general', ['Contributor', 'Editor', 'Reader'])

        # configure autocomplete widget
        self.configure_autocomplete_widget(im_folder['mail-searches'])

        # configure task batch actions
        alsoProvides(im_folder['task-searches'], ITaskDashboard)

        # reimport contact faceted config
        reimport_faceted_config(self.portal['contacts'],
                                xml='contacts-faceted.xml')

        # remove tinymce resources
        configure_ckeditor(self.portal,
                           default=0,
                           allusers=0,
                           forceTextPaste=0,
                           scayt=0)

        self.upgradeAll()

        self.runProfileSteps('imio.dms.mail',
                             steps=['cssregistry', 'jsregistry'])

        # set jqueryui autocomplete to False. If not, contact autocomplete doesn't work
        self.registry[
            'collective.js.jqueryui.controlpanel.IJQueryUIPlugins.ui_autocomplete'] = False

        for prod in [
                'plone.formwidget.autocomplete', 'collective.plonefinder',
                'plone.formwidget.contenttree', 'plone.app.dexterity',
                'plone.formwidget.masterselect',
                'collective.behavior.talcondition',
                'collective.contact.facetednav',
                'collective.contact.plonegroup', 'collective.contact.widget',
                'collective.dms.batchimport', 'collective.dms.scanbehavior',
                'collective.documentgenerator',
                'collective.eeafaceted.collectionwidget',
                'collective.eeafaceted.z3ctable', 'collective.messagesviewlet',
                'collective.querynextprev', 'dexterity.localroles',
                'dexterity.localrolesfield', 'imio.actionspanel',
                'imio.dashboard', 'imio.dms.mail', 'plone.formwidget.datetime',
                'plonetheme.imioapps'
        ]:
            mark_last_version(self.portal, product=prod)

        #self.refreshDatabase()
        self.finish()
    def setUp(self):
        """Custom shared utility setup for tests."""
        super(TestCombinedIndex, self).setUp()
        # add the 'contained_types_and_states' to portal_catalog
        addOrUpdateIndexes(
            self.portal, {'contained_types_and_states': ('KeywordIndex', {})})
        # make sure we have a default workflow
        self.portal.portal_workflow.setDefaultChain(
            'simple_publication_workflow')
        self.dashboardcollection = api.content.create(
            id='dc1',
            type='DashboardCollection',
            title='Dashboard collection 1',
            container=self.portal,
            sort_on='',
            sort_reversed='')
        # this will by default query Folders
        self.dashboardcollection.query = [
            {
                'i': 'portal_type',
                'o': 'plone.app.querystring.operation.selection.is',
                'v': [
                    'Folder',
                ]
            },
        ]
        # create 3 folders :
        # - first is empty;
        # - second contains one private Document and one published Document;
        # - third contains a private Folder.

        # folder1
        self.folder1 = api.content.create(id='folder1',
                                          type='Folder',
                                          title='Folder 1',
                                          container=self.portal)
        self.privatedoc = api.content.create(id='privatedoc',
                                             type='Document',
                                             title='Private document',
                                             container=self.portal.folder1)
        self.publicdoc = api.content.create(id='publicdoc',
                                            type='Document',
                                            title='Published document',
                                            container=self.portal.folder1)
        api.content.transition(self.publicdoc, 'publish')
        # folder2
        self.folder2 = api.content.create(id='folder2',
                                          type='Folder',
                                          title='Folder 2',
                                          container=self.portal)
        # folder3
        self.folder3 = api.content.create(id='folder3',
                                          type='Folder',
                                          title='Folder 3',
                                          container=self.portal)
        self.privatefolder = api.content.create(id='privatefolder',
                                                type='Folder',
                                                title='Private folder',
                                                container=self.portal.folder3)
        self.privatedoc2 = api.content.create(id='privatedoc2',
                                              type='Document',
                                              title='Private document 2',
                                              container=self.portal.folder3)
        # first check that contained_types_and_states index is correct
        self.folder1.reindexObject(idxs=['contained_types_and_states'])
        self.folder2.reindexObject(idxs=['contained_types_and_states'])
        self.folder3.reindexObject(idxs=['contained_types_and_states'])
        self.assertEquals(
            contained_types_and_states(self.folder1)(), [
                'Document', 'Document__private', 'Document__published',
                'private', 'published'
            ])
        self.assertEquals(contained_types_and_states(self.folder2)(), [])
        self.assertEquals(
            contained_types_and_states(self.folder3)(), [
                'Document', 'Document__private', 'Folder', 'Folder__private',
                'private'
            ])
Example #24
0
    def run(self):
        logger.info('Migrating to imio.dms.mail 1.0...')
        self.cleanRegistries()
        self.upgradeProfile('collective.dms.mailcontent:default')
        # We have to reapply type info before doing other subproducts migration
        self.runProfileSteps('imio.dms.mail', steps=['typeinfo'])
        # We have to update type schema because plone.dexterity doesn't detect schema_policy modification. BUG #44
        for portal_type in ['dmsincomingmail', 'dmsoutgoingmail']:
            schemaName = dxutils.portalTypeToSchemaName(portal_type)
            schema = getattr(plone.dexterity.schema.generated, schemaName)
            fti = getUtility(IDexterityFTI, name=portal_type)
            model = fti.lookupModel()
            syncSchema(model.schema, schema, overwrite=True, sync_bases=True)
            notify(plone.dexterity.schema.SchemaInvalidatedEvent(portal_type))

        self.upgradeProfile('collective.task:default')
        self.upgradeProfile('dexterity.localroles:default')
        self.upgradeProfile('dexterity.localrolesfield:default')
        self.upgradeProfile('collective.contact.plonegroup:default')
        self.runProfileSteps('imio.dms.mail', steps=['actions', 'componentregistry', 'controlpanel',
                                                     'plone.app.registry', 'portlets', 'repositorytool',
                                                     'rolemap', 'sharing', 'workflow'])
        self.portal.portal_workflow.updateRoleMappings()
        self.runProfileSteps('collective.dms.mailcontent', steps=['controlpanel'])
        self.runProfileSteps('collective.contact.plonegroup', steps=['controlpanel'])
        self.reinstall([
            'collective.messagesviewlet:messages',
            'collective.querynextprev:default',
            'imio.dashboard:default',
        ])

        # set jqueryui autocomplete to False. If not, contact autocomplete doesn't work
        self.registry['collective.js.jqueryui.controlpanel.IJQueryUIPlugins.ui_autocomplete'] = False

        # delete old dmsmail portlet
        self.delete_portlet(self.portal, 'portlet_maindmsmail')

        # remove deprecated interfaces
        self.remove_contact_interfaces()

        # moved notes content to task_description
        catalog = api.portal.get_tool('portal_catalog')
        brains = catalog.searchResults(portal_type='dmsincomingmail')
        for brain in brains:
            obj = brain.getObject()
            if not base_hasattr(obj, 'notes') or not obj.notes:
                continue
            text = u'<p>%s</p>\r\n' % obj.notes.replace('\r\n', '<br />\r\n')
            obj.task_description = create_richtextval(text)
            delattr(obj, 'notes')
        #    obj.reindexObject()

        # replace collections by Dashboard collections
        im_folder = self.portal['incoming-mail']
        alsoProvides(im_folder, INextPrevNotNavigable)
        alsoProvides(im_folder, IIMDashboard)
        self.replaceCollections(im_folder)

        # apply contact faceted config
        reimport_faceted_config(self.portal['contacts'], 'contacts-faceted.xml')

        # add new indexes for dashboard
        addOrUpdateIndexes(self.portal, indexInfos={'mail_type': ('FieldIndex', {}),
                                                    'mail_date': ('DateIndex', {}),
                                                    'in_out_date': ('DateIndex', {}),
                                                    })

        # set dashboard on incoming mail
        configure_faceted_folder(im_folder, xml='default_dashboard_widgets.xml',
                                 default_UID=im_folder['mail-searches']['all_mails'].UID())

        # set task local roles configuration
        configure_task_rolefields(self.portal)

        # update dexterity local roles configuration
        self.update_local_roles()

        # add task actionspanel config
        if not self.registry['imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions']:
            self.registry['imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions'] = []
        self.registry['imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions'] += \
            ['task.back_in_created|', 'task.back_in_to_assign|', 'task.back_in_to_do|',
             'task.back_in_progress|', 'task.back_in_realized|']

        # activate ckeditor
        configure_ckeditor(self.portal, custom='ged')

        # Set markup allowed types
        adapter = MarkupControlPanelAdapter(self.portal)
        adapter.set_allowed_types(['text/html'])

        # update searchabletext
        self.update_dmsmainfile()

        self.upgradeAll()
        for prod in ['plone.formwidget.autocomplete', 'collective.documentviewer', 'plone.formwidget.masterselect',
                     'collective.contact.core', 'collective.contact.duplicated', 'collective.dms.basecontent',
                     'collective.dms.scanbehavior', 'collective.externaleditor', 'plone.app.collection',
                     'plone.app.intid', 'collective.contact.facetednav', 'plonetheme.imioapps', 'PasswordStrength',
                     'imio.dms.mail']:
            mark_last_version(self.portal, product=prod)

        self.portal.manage_permission('CMFEditions: Revert to previous versions', ('Manager', 'Site Administrator'),
                                      acquire=0)

        #self.refreshDatabase()
        self.finish()
Example #25
0
    def run(self):
        logger.info('Migrating to imio.dms.mail 0.3.1...')
        self.reinstall(['collective.task:uninstall_1.0'])
        self.cleanRegistries()
        self.reinstall([
            'imio.actionspanel:default',
            'imio.history:default',
            'collective.task:default',
            'collective.compoundcriterion:default',
            'collective.behavior.talcondition:default',
            'collective.contact.facetednav:default',
            'collective.contact.duplicated:default',
            'plone.app.versioningbehavior:default',
        ])
        self.runProfileSteps('imio.dms.mail', [
            'actions', 'catalog', 'componentregistry', 'jsregistry',
            'plone.app.registry', 'rolemap', 'typeinfo',
            'update-workflow-rolemap', 'viewlets', 'workflow'
        ])
        self.runProfileSteps('collective.dms.basecontent',
                             ['atcttool', 'catalog'])
        self.runProfileSteps('collective.dms.scanbehavior', ['catalog'])

        api.portal.get_tool('portal_diff').setDiffForPortalType(
            'dmsincomingmail',
            {'any': "Compound Diff for Dexterity types"})  # i_e ok
        self.createNotEncodedPerson()
        self.changeTopicsFolder()
        self.replaceRoleByGroup()
        self.portal.portal_workflow.updateRoleMappings()

        catalog = api.portal.get_tool('portal_catalog')
        brains = catalog.searchResults(portal_type='dmsincomingmail')  # i_e ok
        if brains:
            factory = getUtility(IVocabularyFactory,
                                 'collective.dms.basecontent.treating_groups')
            voc = factory(brains[0].getObject())
            good_values = voc.by_token
        for brain in brains:
            im = brain.getObject()
            #new_incomingmail(im, None)
            if isinstance(im.treating_groups, list):
                if len(im.treating_groups) > 1:
                    logger.error(
                        "More than one treating_groups %s for %s object" %
                        (im.treating_groups, im))
                    keep = None
                    for tg in im.treating_groups:
                        if tg in good_values:
                            keep = tg
                            break
                    logger.warn("Kept %s" % keep)
                    im.treating_groups = keep
                elif not im.treating_groups:
                    logger.warn(
                        "Replaced old value %s by first good value %s for %s object"
                        % (im.treating_groups[0], good_values.keys()[0], im))
                    im.treating_groups = good_values.keys()[0]
                elif im.treating_groups[0] in good_values:
                    #elif catalog(UID=im.treating_groups[0]):
                    im.treating_groups = im.treating_groups[0]
                else:
                    logger.warn(
                        "Replaced old value %s by first good value %s for %s object"
                        % (im.treating_groups[0], good_values.keys()[0], im))
                    im.treating_groups = good_values.keys()[0]

        addOrUpdateIndexes(self.portal,
                           indexInfos={
                               'treating_groups': ('KeywordIndex', {}),
                               'recipient_groups': ('KeywordIndex', {}),
                               'organization_type': ('FieldIndex', {}),
                           })
        addOrUpdateColumns(self.portal,
                           columns=('treating_groups', 'recipient_groups'))
        # a global recatalog is made after
        #brains = catalog.searchResults(portal_type='organization')
        #for brain in brains:
        #    brain.getObject().reindexObject(idxs=['organization_type'])

        setupFacetedContacts(self.portal)

        changeSearchedTypes(self.portal)

        configure_actions_panel(self.portal)

        self.upgradeAll()
        self.refreshDatabase()
        self.finish()
Example #26
0
def postInstall(context):
    """Called as at the end of the setup process. """
    # the right place for your custom code
    if isNotMeetingAndenneProfile(context):
        return

    logStep("postInstall", context)
    site = context.getSite()

    # Create or update indexes
    addOrUpdateIndexes(site, indexInfos)
    addOrUpdateColumns(site, columnInfos)

    # Need to reinstall PloneMeeting after reinstalling MA workflows to re-apply wfAdaptations
    reinstallPloneMeeting(context, site)

    # Make sure the 'home' tab is shown
    showHomeTab(context, site)

    # reorder skins so we are sure that the meetingAndenne_xxx skins are just under custom
    reorderSkinsLayers(context, site)

    # reimport actions provider so that useless portal_tabs are not shown anymore
    reorderPortalTabs(context, site)

    # reimport plone.app.search javascript registry as some scripts are missing
    reorderScriptsRegistry(context, site)

    # Remove some types from the standard Plone search (live and advanced)
    props = site.portal_properties.site_properties
    nsTypes = props.getProperty('types_not_searched')
    if not nsTypes:
        nsTypes = []
    else:
        nsTypes = list(nsTypes)
    for t in noSearchTypes:
        if t not in nsTypes:
            nsTypes.append(t)
    props.manage_changeProperties(types_not_searched=tuple(nsTypes))

    # configure CKEditor
    configureCKEditor(context, site)

    # configure safe_html portal transform
    configureSafeHtml(context, site)

    # adapt gestion-courrier directory
    configureMailDirectory(context, site)

    # configure Products.cron4plone
    # add a call to @@run-docsplit-on-blobs that will run docsplit on a batch of
    # CourrierFile and MeetingFile objects until all migrated content is converted.
    # add a call to @@parse-converted-files that will monthly check that all convertable
    # objects are converted and that all conversion results are still linked to existing
    # objects.
    cron_configlet = queryUtility(ICronConfiguration, 'cron4plone_config')
    if not cron_configlet.cronjobs:
        cron_configlet.cronjobs = CRON_TASKS
    else:
        addCron = True
        cronView = CRON_TASKS[0].split(' ')[-1]
        for cron in cron_configlet.cronjobs:
            cron = cron.split(' ')
            if cron[-1] == cronView:
                addCron = False
                break
        if addCron:
            for task in CRON_TASKS:
                cron_configlet.cronjobs.append(task)