def test_cktemplate_moved(self): oemf = self.portal['templates']['oem'] srvf = self.portal['contacts']['plonegroup-organization'] org1 = srvf['direction-generale'] org2 = srvf['direction-generale']['secretariat'] self.assertIn(org1.UID(), oemf) self.assertIn(org2.UID(), oemf) mod1 = api.content.create(container=oemf, type='cktemplate', id='mod1', title='Modèle 1') annot = IAnnotations(mod1) self.assertEqual(annot['dmsmail.cke_tpl_tit'], u'') mod1 = api.content.move(mod1, oemf[org1.UID()]) annot = IAnnotations(mod1) self.assertEqual(annot['dmsmail.cke_tpl_tit'], u'Direction générale') mod2 = api.content.copy(mod1, oemf[org2.UID()], id='mod2') annot = IAnnotations(mod2) self.assertEqual(annot['dmsmail.cke_tpl_tit'], u'Direction générale - Secrétariat') folder = api.content.create(container=oemf, type='Folder', id='fold1', title='héhéhé') mod2 = api.content.move(mod2, folder) annot = IAnnotations(mod2) self.assertEqual(annot['dmsmail.cke_tpl_tit'], u'héhéhé') mod2 = api.content.rename(mod2, 'mod-nextgen') annot = IAnnotations(mod2) self.assertEqual(annot['dmsmail.cke_tpl_tit'], u'héhéhé')
def import_oggbundle(app, args): """Handler for the 'bin/instance import' zopectl command. """ setup_logging() # Discard the first three arguments, because they're not "actual" arguments # but cruft that we get because of the way bin/instance [zopectl_cmd] # scripts work. args = parse_args(sys.argv[3:]) log.info("Importing OGGBundle %s" % args.bundle_path) plone = setup_plone(get_first_plone_site(app)) # mark request with GEVER layer alsoProvides(plone.REQUEST, IOpengeverBaseLayer) # Don't use a separate ZODB connection to issue sequence numbers in # order to avoid conflict errors during OGGBundle import alsoProvides(plone.REQUEST, INoSeparateConnectionForSequenceNumbers) # Add index to track imported GUIDs (if it doesn't exist yet) add_guid_index() transmogrifier = Transmogrifier(plone) ann = IAnnotations(transmogrifier) ann[BUNDLE_PATH_KEY] = args.bundle_path ann[INTERMEDIATE_COMMITS_KEY] = not args.no_intermediate_commits solr_enabled = api.portal.get_registry_record( 'opengever.base.interfaces.ISearchSettings.use_solr', default=False) if solr_enabled: # Check if solr is running conn = getUtility(ISolrConnectionManager).connection if conn.get('/schema').status == -1: raise Exception( "Solr isn't running, but solr reindexing is enabled. " "Skipping solr reindexing via `--skip-solr`.") else: # Disable collective indexing as it can lead to too many # subtransactions unpatch_collective_indexing() with DisabledLDAP(plone): transmogrifier(u'opengever.bundle.oggbundle') bundle = IAnnotations(transmogrifier)[BUNDLE_KEY] timings = bundle.stats['timings'] if 'migration_finished' in timings: duration = timings['migration_finished'] - timings['start_loading'] log.info("Duration: %.2fs" % duration.total_seconds()) log.info("Committing transaction...") transaction.get().note("Finished import of OGGBundle %r" % args.bundle_path) transaction.commit() log.info("Done.")
def test_ParentsAreCorrectlyUpdatedOnMove(self): # first create some projects and sub-projects using the _createProjectsAndTestAnnotationsEvolution (project1, subproject1, subSubproject1, subSubproject2, project1Annotations, subproject1Annotations, subSubproject1Annotations, subSubproject2Annotations) = self._createProjectsAndTestAnnotationsEvolution() project2 = self.portal.projectspace['project-2'] project2Annotations = IAnnotations(project2) # we change initial state self.pw.doActionFor(project2, "set_to_be_scheduled") params = {'title': 'Subproject 2', 'priority': 'priority-2', } subproject2 = createContentInContainer(project2, 'project', **params) # we change initial state self.pw.doActionFor(subproject2, "set_to_be_scheduled") subproject2Annotations = IAnnotations(subproject2) # verifying content self.assertEquals(len(project1Annotations[CBIAK].keys()), 3) self.assertEquals(len(subproject1Annotations[CBIAK].keys()), 2) self.assertDictEqual(project2Annotations.get(CBIAK, {}), {}) self.assertDictEqual(subproject2Annotations.get(CBIAK, {}), {}) # we move last level api.content.move(subSubproject2, subproject2) self.assertEquals(len(project1Annotations[CBIAK].keys()), 2) self.assertEquals(len(subproject1Annotations[CBIAK].keys()), 1) self.assertEquals(len(project2Annotations[CBIAK].keys()), 1) self.assertEquals(len(subproject2Annotations[CBIAK].keys()), 1) # we move intermediate level api.content.move(subproject1, project2) self.assertEquals(len(project1Annotations[CBIAK].keys()), 0) self.assertEquals(len(subproject1Annotations[CBIAK].keys()), 1) self.assertEquals(len(project2Annotations[CBIAK].keys()), 3) self.assertEquals(len(subproject2Annotations[CBIAK].keys()), 1)
def setUp(self): super(TestReceiveDocumentPDF, self).setUp() self.document = create( Builder('document').titled( u'\xdcberpr\xfcfung XY')).as_shadow_document() IAnnotations(self.document)[PDF_SAVE_TOKEN_KEY] = self.save_token IAnnotations(self.document)[PDF_SAVE_OWNER_ID_KEY] = self.user.userid
def __iter__(self): for item in self.previous: keys = item.keys() pathkey = self.pathkey(*keys)[0] objpath = item[pathkey] obj = self.context.unrestrictedTraverse(objpath) # The contructor generated an empty object (which triggered our # stats event handler.) Let's update the stats here manually. created = IAnnotations(obj.REQUEST).get( 'org.bccvl.site.stats.created', False) if created: # our created subscriber has been invoked getUtility(IStatsUtility).count_dataset( source=obj.dataSource, portal_type=obj.portal_type) # reset the flag ... we can do that, because the pipeline runs # sequentially IAnnotations( obj.REQUEST)['org.bccvl.site.stats.created'] = False # Attach a job tracker only for species dataset from multispecies if item.get('_partof', {}): jt = IJobTracker(obj) jt.new_job('TODO: generate id', 'generate taskname: ala_import', function=obj.dataSource, type=obj.portal_type, state='COMPLETED') yield item
def count_dataset_created(obj, event): # IBLobDataset # IRemoteDataset # IDatasetCollection -> IMultiSpeciesDataset if IAnnotations(obj.REQUEST).get('org.bccvl.site.stats.delay'): # skip this event, we have been called from transmogrify chain, where # we collect stats later # tell stats collector that we really created a new object IAnnotations(obj.REQUEST)['org.bccvl.site.stats.created'] = True return dataSrc = obj.dataSource if not dataSrc: if obj.part_of: # part of multispecies file ... get dataSource from master file master = uuidToObject(obj.part_of) dataSrc = master.dataSource if not dataSrc: # find default # check whether we are inside an experiment: if defaults.EXPERIMENTS_FOLDER_ID in obj.getPhysicalPath(): dataSrc = 'experiment' else: dataSrc = 'upload' getUtility(IStatsUtility).count_dataset(source=dataSrc, portal_type=obj.portal_type)
def import_oggbundle(app, args): """Handler for the 'bin/instance import' zopectl command. """ setup_logging() bundle_path = sys.argv[3] log.info("Importing OGGBundle %s" % bundle_path) plone = setup_plone(get_first_plone_site(app)) # mark request with GEVER layer alsoProvides(plone.REQUEST, IOpengeverBaseLayer) # Don't use a separate ZODB connection to issue sequence numbers in # order to avoid conflict errors during OGGBundle import alsoProvides(plone.REQUEST, INoSeparateConnectionForSequenceNumbers) transmogrifier = Transmogrifier(plone) IAnnotations(transmogrifier)[BUNDLE_PATH_KEY] = bundle_path with DisabledLDAP(plone): transmogrifier(u'opengever.bundle.oggbundle') bundle = IAnnotations(transmogrifier)[BUNDLE_KEY] timings = bundle.stats['timings'] duration = timings['done_post_processing'] - timings['start_loading'] log.info("Duration: %.2fs" % duration.total_seconds()) log.info("Committing transaction...") transaction.get().note("Finished import of OGGBundle %r" % bundle_path) transaction.commit() log.info("Done.")
def relocate(self, sid, target_path): target_context = self.traverse(target_path) target_annotations = IAnnotations(target_context) if sid not in target_annotations: raise KeyError, 'Annotation-Key %s must exist at %s' % \ (sid, target_path) root_annotations = IAnnotations(self.root) root_annotations[sid] = target_path self._invalidate_cache(sid) target_soup = getSoup(self.context, sid)
def post(self, **kwargs): """ POST """ newids = self.request.get('new_ids') newtitles = self.request.get('new_titles', '') paths = self.request.get('paths', '') if 'form.button.Cancel' in kwargs: return self._redirect(_(u"Rename cancelled"), redirect_to='') elif 'form.button.rename' in kwargs: return self.original_action(action='rename') elif 'form.button.async_rename' in kwargs: return self.index() worker = getUtility(IAsyncService) queue = worker.getQueues()[''] email = api.user.get_current().getProperty('email') try: job = worker.queueJobInQueue(queue, (ASYNCMOVE_QUEUE, ), async_rename, self.context, new_ids=newids, new_titles=newtitles, paths=paths, success_event=AsyncRenameSuccess, fail_event=AsyncRenameFail, email=email) job_id = u64(job._p_oid) context = self.context wrapper = IContextWrapper(context)( folder_move_from=context.absolute_url(1), folder_move_to=', '.join(newids), folder_move_objects=', '.join(paths), asyncmove_email=email, async_operation_type='rename', email=email) notify(AsyncOperationAdded(wrapper)) anno = IAnnotations(self.context) anno['async_move_job'] = job_id portal = getToolByName(self, 'portal_url').getPortalObject() portal_anno = IAnnotations(portal) if not portal_anno.get('async_move_jobs'): portal_anno['async_move_jobs'] = OOBTree() message_type = 'info' message = _(u"Item added to the queue. " u"We will notify you by email at '%s' when the job is " u"completed" % email) except Exception, err: logger.exception(err) message_type = 'error' message = u"Failed to add items to the sync queue"
def set_path(self, sid, newpath): """maps path to object with soupdata annotations for given soup id. it does not check if there is already a soup before nor does it warn if there was a soup at the old location. """ self.traverse(newpath) # check if newpath is ok paths = IAnnotations(self.root).get(SOUPPATHS, None) if paths is None: paths = PersistentMapping() IAnnotations(self.root)[SOUPPATHS] = paths paths[sid] = newpath self._invalidate_cache(sid)
def beforeSaveModifier(self, obj, clone): """Removes ftw.journal keys from version's annotations. """ # The journal key in the annotations is supposed to already have been # emptied (set to None instead of a PersistentList) by the # onCloneModifier above. assert IAnnotations(clone).get(self.JOURNAL_KEY) is None # Let's now remove the key entirely from annotations if self.JOURNAL_KEY in IAnnotations(clone): del IAnnotations(clone)[self.JOURNAL_KEY] return {}, [], []
def setup_section(self, previous=None): previous = previous or [] self.transmogrifier = MockTransmogrifier() self.transmogrifier.context = api.portal.get() self.bundle_path = resource_filename('opengever.bundle.tests', 'assets/basic.oggbundle') self.bundle = BundleLoader(self.bundle_path).load() IAnnotations(self.transmogrifier)[BUNDLE_PATH_KEY] = self.bundle_path IAnnotations(self.transmogrifier)[BUNDLE_KEY] = self.bundle options = {'blueprint': 'opengever.setup.fileloader'} return FileLoaderSection(self.transmogrifier, '', options, previous)
def test_behavior_when_conversion_succeeded(self): self.assertFalse(self.document.has_file()) self.assertIn(PDF_SAVE_TOKEN_KEY, IAnnotations(self.document)) with freeze(datetime(2016, 4, 25, 10, 24)): self.prepare_request() view = ReceiveDocumentPDF(self.document, self.request) view() # File was set and document left the shadow state. self.assertTrue(self.document.has_file()) self.assertFalse(self.document.is_shadow_document()) # Annotation show successful conversion status and save token was removed. self.assertEqual('conversion-successful', IAnnotations(self.document)[PDF_SAVE_STATUS_KEY]) self.assertNotIn(PDF_SAVE_TOKEN_KEY, IAnnotations(self.document))
def assign_new_version_id_for_translation(obj, event): """Assigns a version id to newly created translations """ version_prefix = get_version_prefix(obj) if version_prefix: target = event.target canonical = obj.getCanonical() if canonical is target: return decrement_version_prefix_number(version_prefix) cvid = IAnnotations(canonical).get(VERSION_ID) if version_prefix.prefix_with_language: cvid = '-'.join(cvid.split('-')[:-1]) translation_vid = cvid + '-' + target.getLanguage() IAnnotations(target)[VERSION_ID] = translation_vid
def __call__(self): portal = api.portal.get() gsettings = GlobalSettings(portal) catalog = getToolByName(self.context, 'portal_catalog') cpt = 0 brains = catalog.searchResults(meta_type='CourrierFile') print(len(brains)) for brain in brains: object = brain.getObject() annexUID = object.UID() path = join(gsettings.storage_location, annexUID[0], annexUID[1], annexUID) if not os.path.exists(path): object.needsOcr = True object.toPrint = True annotations = IAnnotations(object) if 'collective.documentviewer' in annotations: del annotations['collective.documentviewer'] if 'Products.MeetingAndenne' in annotations: del annotations['Products.MeetingAndenne'] cpt += 1 logger.info('%d : Object flagged for OCR : %s' % (cpt, object.absolute_url())) brains = catalog.searchResults(meta_type='MeetingFile') print(len(brains)) for brain in brains: object = brain.getObject() annexUID = object.UID() path = join(gsettings.storage_location, annexUID[0], annexUID[1], annexUID) if not os.path.exists( path) and object.findRelatedTo() != 'item_pv': object.needsOcr = True object.toPrint = True annotations = IAnnotations(object) if 'collective.documentviewer' in annotations: del annotations['collective.documentviewer'] if 'Products.MeetingAndenne' in annotations: del annotations['Products.MeetingAndenne'] cpt += 1 logger.info('%d : Object flagged for OCR : %s' % (cpt, object.absolute_url())) logger.info("flagging for OCR finished")
def test_attachment_tile(self): """This persistent tile renders a link pointing to a file stored in the tile data itself. """ annotations = IAnnotations(self.page) annotations['plone.tiles.data.test'] = PersistentDict({ 'files': [ NamedFile(u'Hello World!', 'text/plain', u'hello_world.txt'), NamedFile(u'Foobar!', 'text/plain', u'foobar.txt') ] }) transaction.commit() self.browser.open(self.pageURL + '/@@plone.app.standardtiles.attachment/test') self.assertIn(u'hello_world.txt', self.browser.contents) self.assertIn(u'foobar.txt', self.browser.contents) root = fromstring(self.browser.contents) nodes = root.xpath('//body//a') self.assertEqual(len(nodes), 2) self.browser.getLink(index=1).click() self.assertEqual(self.browser.contents, u'Foobar!')
def registerPersistentConfig(site, type_): """ Try to get persistent pipeline configuration of given type (export or import) and register it for use with transmogrifier. """ global CONFIGFILE anno = IAnnotations(site) key = '%s.%s' % (ANNOKEY, type_) config = anno.has_key(key) and anno[key] or None # unregister old config name = 'persitent-%s' % type_ if name in configuration_registry._config_ids: configuration_registry._config_ids.remove(name) del configuration_registry._config_info[name] # register new if config is not None: title = description = u'Persistent %s pipeline' tf = tempfile.NamedTemporaryFile('w+t', suffix='.cfg') tf.write(config) tf.seek(0) CONFIGFILE = tf configuration_registry.registerConfiguration(name, title, description, tf.name) return name else: return None
def update_opengraphable_objects(context, new_ct): g_marker = queryUtility(IOpengraphMarkerUtility) if not g_marker: return options = IAnnotations(context) ct = getToolByName(context, 'portal_catalog') olds_pt = options.get('old_content_types', []) if new_ct == olds_pt: return adds = [] for new in new_ct: if new in olds_pt: olds_pt.remove(new) else: adds.append(new) nb_items, bad_items = g_marker.update(context, adds, olds_pt) updated = u'%d %s' % (nb_items, _(u'objects updated.')) if not bad_items: message = updated else: message = u'%s, %d %s: %s' % (updated, len(bad_items), _(u'update(s) on object(s) failed'), ','.join(bad_items), ) pu = getToolByName(context, 'plone_utils') pu.addPortalMessage(message)
def get_storage(context, default=None): annotations = IAnnotations(context) if annotation_key not in annotations: if default is not None: return default annotations[annotation_key] = PersistentDict() return annotations[annotation_key]
def create(self, context): """ Request a handle to be created for the content object passed in as context. The handle will be the configured prefix plus the objects uid. The absolut url is supplied as target url. On success the handle will be stored in the context's annotations. """ uid = context.UID() target = context.absolute_url() handle = '/'.join([self.prefix, uid]) data = [{'type': 'URL', 'parsed_data': target}] resp = self.session.post(self.baseurl + handle, json=data) if int(resp.status_code) == 405: # EPIC doesn't support POST resp = self.session.put(self.baseurl + handle, json=data) if int(resp.status_code) == 201: location = resp.headers.get('location') annotations = IAnnotations(context) annotations[KEY] = handle return location else: logger = logging.getLogger('collective.handle') message = self.baseurl + handle message += '\n' + str(resp) + '\n' for k, v in resp.headers.items(): message += "%s = %s\n" % (k, v) logger.error(message) raise HandleError(resp.status_code)
def setup_section(self, previous=None): previous = previous or [] transmogrifier = MockTransmogrifier() IAnnotations(transmogrifier)[BUNDLE_KEY] = MockBundle() options = {} return ConstructorSection(transmogrifier, '', options, previous)
def _default_stylebook(self): if not getattr(self, '_default', None): if not [o.getId() for o in self.stylebooks()]: return None anno = IAnnotations(self.context).get(ANNO_KEY, {}) self._default = anno.get('default_stylebook', None) return self._default
def test_indexation_settings(self): ''' The enable_indexation setting can be defined on the object local settings or in the global settings. Local settings are overriding global settings... ''' fi = self.createFile('test.pdf') # indexation is enabled by default in the global settings # and nothing is defined in the local settings notify(ObjectInitializedEvent(fi)) # make sure conversion was successfull self.failUnless(self._isSuccessfullyConverted(fi)) annotations = IAnnotations(fi)['collective.documentviewer'] self.failUnless(annotations['catalog'] is not None) # nothing defined on the 'fi' self.failIf('enable_indexation' in annotations) # if we disable indexation in the local settings, this will be # taken into account as it overrides global settings annotations['enable_indexation'] = False # make it convertable again by adapting last_updated and filehash annotations['last_updated'] = DateTime('1901/01/01').ISO8601() annotations['filehash'] = 'dummymd5' notify(ObjectInitializedEvent(fi)) # make sure conversion was successfull self.failUnless(self._isSuccessfullyConverted(fi)) # as indexation is disabled in local settings, the text # of the PDF is no more indexed... self.failIf(annotations['catalog'] is not None)
def disable_behaviors(obj, behaviors, ifaces): """ Disable behaviors on an object. :param obj: The Dexterity content object to disable behaviors on. :type obj: object :param behaviors: Behaviors to be disabled on the object. This is a list of dotted names of behavior schema interfaces. :type behaviors: list :param ifaces: Behavior marker interfaces belonging to the behaviors to be disabled. This is a list of interface classes. :type ifaces: class Use it like so: >>> from plone.app.event.dx.interfaces import IDXEvent >>> disable_behaviors(obj, ['plone.app.event.dx.behaviors.IEventBasic',], ... [IDXEvent,]) """ annotations = IAnnotations(obj) instance_behaviors = annotations.get(KEY, ()) instance_behaviors = filter(lambda x: x not in behaviors, instance_behaviors) annotations[KEY] = instance_behaviors for iface in ifaces: noLongerProvides(obj, iface) obj.reindexObject(idxs=('object_provides'))
def acquire(self, commit=False): """Acquire a resolve lock for a dossier. Will overwrite a possibly existing expired lock. """ self.log("Acquiring resolve lock for %s..." % self.context) if self.txn_is_dirty(): # Acquiring and committing the lock should always be the first # thing that's being done when resolving the dossier, otherwise # we would be committing unrelated, unexpected changes. # # Detect if that happens, but still proceed and log to sentry. msg = 'Dirty transaction when comitting resolve lock' self.log(msg) self.log('Registered objects: %r' % self._registered_objects()) log_msg_to_sentry( msg, level='warning', extra={'registered_objects': repr(self._registered_objects())}) ann = IAnnotations(self.context) lockinfo = PersistentMapping({ 'timestamp': datetime.now(), 'userid': api.user.get_current().id, }) ann[RESOLVE_LOCK_KEY] = lockinfo self.invalidate_cache() if commit: transaction.commit() self.log("Resolve lock acquired.")
def get_table_filters(): """get_table_filters.""" site = getSite() anno = IAnnotations(site) matrix = anno.get('matrix_1', {}) return matrix.get('select_categories', {})
def cktemplate_moved(obj, event): """Managed the annotation for the Service template. Linked to creation, move, rename, delete and copy. """ # TODO move it to ckeditortemplates if IObjectRemovedEvent.providedBy(event): return path = '/'.join(obj.getPhysicalPath()[:-1]) # skip rename or inplace copy if event.oldParent == event.newParent or \ (event.oldParent and path == '/'.join(event.oldParent.getPhysicalPath())): return if '/templates/oem' not in path: return # oem has been renamed index = path.index('/templates/oem') + 14 subpath = path[index + 1:] parts = subpath and subpath.split('/') or [] value = u'' if parts: pcat = obj.portal_catalog brains = pcat.unrestrictedSearchResults(path='{}/{}'.format(path[:index], parts[0]), sort_on='path', ) titles = {br.getPath(): br.Title for br in brains} values = [] current_path = path[:index] for part in parts: current_path += '/{}'.format(part) values.append(titles[current_path].decode('utf8')) value = u' - '.join(values) annot = IAnnotations(obj) annot['dmsmail.cke_tpl_tit'] = value
def test_oggbundle_transmogrifier(self): # this is a bit hackish, but since builders currently don't work in # layer setup/teardown and isolation of database content is ensured # on a per test level we abuse just one test to setup the pipeline and # test its data. # load pipeline # XXX move this to a layer self.grant("Manager") transmogrifier = Transmogrifier(api.portal.get()) IAnnotations(transmogrifier)[BUNDLE_PATH_KEY] = resource_filename( 'opengever.bundle.tests', 'assets/business_rule_violations.oggbundle') # We need to add documents to dossiers that have already been created # in the 'closed' state, which isn't allowed for anyone except users # inheriting from `UnrestrictedUser` -> we need elevated privileges with freeze(FROZEN_NOW), elevated_privileges(): transmogrifier(u'opengever.bundle.oggbundle') # test content creation # XXX use separate test-cases based on a layer root = self.assert_repo_root_created() self.assert_deeply_nested_repo_folder_created(root) folder = root.restrictedTraverse( 'ordnungsposition-1/ordnungsposition-1.1') self.assert_deeply_nested_subdossier_created(folder) self.assert_resolved_dossier_with_violations_created(folder)
def __call__(self): data = {'metadata': {}, 'permissions': {}} catalog = api.portal.get_tool('portal_catalog') portal_types = BUNDLE_JSON_TYPES.values() portal_types.append('ftw.mail.mail') for portal_type in portal_types: data['metadata'][portal_type] = [] data['permissions'][portal_type] = [] log.info("Collecting %s" % portal_type) brains = catalog.unrestrictedSearchResults( portal_type=portal_type, bundle_guid=tuple(self.bundle.constructed_guids)) for brain in brains: obj = brain.getObject() guid = IAnnotations(obj).get(BUNDLE_GUID_KEY) item_info = self.get_item_metadata(obj, guid) data['metadata'][portal_type].append(item_info) if portal_type not in ( 'opengever.document.document', 'ftw.mail.mail'): permission_info = self.get_permissions(obj, guid) if permission_info: data['permissions'][portal_type].extend( permission_info) return data
def bundle_guid_indexer(obj): """Indexes the GUID of an item imported from an OGGBundle. The corresponding index will only exist temporarily during migrations. See openever.bundle.console.add_guid_index() """ return IAnnotations(obj).get(BUNDLE_GUID_KEY)