def getWrappedOwner(self): """Get the owner, modestly wrapped in the user folder. o If the object is not owned, return None. o If the owner's user database doesn't exist, return Nobody. o If the owner ID does not exist in the user database, return Nobody. """ owner = self.getOwnerTuple() if owner is None or owner is UnownableOwner: return None udb_path, oid = owner cache_key = ('getWrappedOwner', ) + ( (tuple(udb_path), oid) if isinstance(udb_path, list) else owner ) try: return getTransactionalVariable()[cache_key] except KeyError: pass root = self.getPhysicalRoot() udb = root.unrestrictedTraverse(udb_path, None) if udb is None: result = SU.nobody else: user = udb.getUserById(oid, None) if user is None: result = SU.nobody else: result = user.__of__(udb) getTransactionalVariable()[cache_key] = result return result
def test_a_person(self): self.tic() person = self.portal.person_module.newContent() self.assertEqual(person, self.portal.SubscriptionRequest_saveTransactionalUser(person)) self.assertEqual(person, getTransactionalVariable()["transactional_user"]) self.tic() try: self.assertEqual(None, getTransactionalVariable()["transactional_user"]) except KeyError: pass
def test_03_Durability(self): """Check if a transaction variable does not disappear within the same transaction. """ tv = getTransactionalVariable() self.failIfEqual(tv, None) tv.clear() self.failUnlessEqual(len(tv), 0) # Set both a transaction variable and a volatile attribute, # in order to detect the difference between their behaviors. tv['toto'] = 'titi' self.failUnlessEqual(tv['toto'], 'titi') portal = self.getPortal() vattr = '_v_erp5type_test_durability' setattr(portal, vattr, 'dummy') self.failUnlessEqual(getattr(portal, vattr), 'dummy') # Force to minimize the connection cache so that volatile attributes # and unghostified objects are discarded. portal._p_jar.cacheMinimize() self.failUnless('toto' in tv) self.failUnlessEqual(tv['toto'], 'titi') self.failUnlessEqual(getattr(portal, vattr, None), None)
def test_03_Durability(self): """Check if a transaction variable does not disappear within the same transaction. """ tv = getTransactionalVariable() self.assertNotEqual(tv, None) tv.clear() self.assertEqual(len(tv), 0) # Set both a transaction variable and a volatile attribute, # in order to detect the difference between their behaviors. tv["toto"] = "titi" self.assertEqual(tv["toto"], "titi") portal = self.portal vattr = "_v_erp5type_test_durability" setattr(portal, vattr, "dummy") self.assertEqual(getattr(portal, vattr), "dummy") # Force to minimize the connection cache so that volatile attributes # and unghostified objects are discarded. portal._p_jar.cacheMinimize() self.assertTrue("toto" in tv) self.assertEqual(tv["toto"], "titi") self.assertEqual(getattr(portal, vattr, None), None)
def _isTreeDelivered(self): """ checks if subapplied rules of this movement (going down the complete simulation tree) have a child with a delivery relation. Returns True if at least one is delivered, False if none of them are. see AppliedRule._isTreeDelivered """ def getTreeDelivered(): if self.getDeliveryList(): return True for applied_rule in self.objectValues(): if applied_rule._isTreeDelivered(): return True return False try: cache = getTransactionalVariable()[TREE_DELIVERED_CACHE_KEY] except KeyError: return getTreeDelivered() rule_key = self.getRelativeUrl() try: return cache[rule_key] except KeyError: cache[rule_key] = result = getTreeDelivered() return result
def expand(self, **kw): """ Expands the current movement downward. -> new status -> expanded An applied rule can be expanded only if its parent movement is expanded. """ tv = getTransactionalVariable() cache = tv.setdefault(TREE_DELIVERED_CACHE_KEY, {}) cache_enabled = cache.get(TREE_DELIVERED_CACHE_ENABLED, 0) # enable cache if not cache_enabled: cache[TREE_DELIVERED_CACHE_ENABLED] = 1 rule = self.getSpecialiseValue() if rule is not None: rule.expand(self,**kw) # disable and clear cache if not cache_enabled: try: del tv[TREE_DELIVERED_CACHE_KEY] except KeyError: pass
def _checkConversionFormatPermission(self, format, lock_checking=False, **kw): """Private method to check permission when access specified format. This method raises """ transaction_variable = getTransactionalVariable() if transaction_variable.get(LOCK_PERMISSION_KEY, False): # Permission already checked in convert with final format, # do not check permission for intermediate formats return True # XXX cache result in TV method = self._getTypeBasedMethod( 'checkConversionFormatPermission', fallback_script_id='Document_checkConversionFormatPermission') if '**' not in method.params(): # Backward compatibility code: # Existing Type Based Method doesn't support new **kw argument # in their signature. is_allowed = method(format=format) else: is_allowed = method(format=format, **kw) if not is_allowed: raise Unauthorized('Document: user does not have enough permission'\ ' to access document in %s format' %\ (format or 'original')) transaction_variable[LOCK_PERMISSION_KEY] = lock_checking
def test_01_DictInterface(self): """Check if a transaction variable behaves in the same way as a dict. """ tv = getTransactionalVariable() self.assertNotEqual(tv, None) # Test frequently used dict methods. This does not cover everything, # but should be enough. tv.clear() self.assertEqual(len(tv), 0) self.assertRaises(KeyError, tv.__getitem__, "toto") tv["toto"] = "titi" self.assertEqual(len(tv), 1) self.assertEqual(tv["toto"], "titi") self.assertEqual(tv.get("foo"), None) tv.setdefault("foo", "bar") self.assertEqual(len(tv), 2) self.assertEqual(tv["foo"], "bar") self.assertTrue("foo" in tv) del tv["foo"] self.assertFalse("foo" in tv) self.assertEqual(len(tv), 1)
def _getTemplateFieldCache(self): parent = self.aq_parent if parent is not None: cache = getTransactionalVariable()[self._getCacheId()] if cache is not None: return cache.__of__(parent) raise KeyError
def getMappingFromProperty(self, base_mapping, property_name): """ This method allows to retrieve throuhh the mapping in the integration site the corresponding value in the external site. args: base_mapping = the base property mapping property = string of the property we want the mapping """ tv = getTransactionalVariable() key = "%s-%s" % (base_mapping.getPath(), property_name) try: mapping_line = tv[key] except KeyError: tv[key] = mapping_line = base_mapping.searchFolder( portal_type='Integration Property Mapping', path="%s%%" % (base_mapping.getPath()), destination_reference=property_name, ) if len(mapping_line) > 1: raise IndexError( 'The integration property mapping %s must be mapped with only one category' % property_name) elif len(mapping_line) == 0: return property_name else: return mapping_line[0].getObject().getSourceReference()
def calculate(self): """Move related delivery in 'calculating' state by activity Activity to update causality state is delayed until all related simulation movement are reindexed. This method should be only called by simulation_movement_causality_interaction_workflow. """ delivery = self.getDeliveryValue() if delivery is not None: delivery = delivery.getRootDeliveryValue() tv = getTransactionalVariable() path = self.getPath() delivery_path = delivery.getPath() key = 'SimulationMovement.calculate', delivery_path try: tv[key].append(path) except KeyError: tv[key] = [path] def before_commit(): method_id_list = ('immediateReindexObject', 'recursiveImmediateReindexObject') tag = delivery_path + '_calculate' delivery.activate(tag=tag).Delivery_calculate(activate_kw= {'after_path_and_method_id': (tv[key], method_id_list)}) tv[key] = None # disallow further calls to 'calculate' transaction.get().addBeforeCommitHook(before_commit)
def test_01_DictInterface(self): """Check if a transaction variable behaves in the same way as a dict. """ tv = getTransactionalVariable() # Test frequently used dict methods. This does not cover everything, # but should be enough. tv.clear() self.assertEqual(len(tv), 0) with self.assertRaises(KeyError): tv['toto'] tv['toto'] = 'titi' self.assertEqual(len(tv), 1) self.assertEqual(tv['toto'], 'titi') self.assertIsNone(tv.get('foo')) tv.setdefault('foo', 'bar') self.assertEqual(len(tv), 2) self.assertEqual(tv['foo'], 'bar') self.assertIn('foo', tv) del tv['foo'] self.assertNotIn('foo', tv) self.assertEqual(len(tv), 1)
def isAuthenticationPolicyEnabled(self): """ Return True if authentication policy is enabled. This method exists here due to bootstrap issues. It should work even if erp5_authentication_policy bt5 is not installed. """ # XXX: define an interface def _isAuthenticationPolicyEnabled(): portal_preferences = self.getPortalObject().portal_preferences method_id = 'isPreferredAuthenticationPolicyEnabled' method = getattr(self, method_id, None) if method is not None and method(): return True return False tv = getTransactionalVariable() tv_key = 'PreferenceTool._isAuthenticationPolicyEnabled.%s' % getSecurityManager( ).getUser() if tv.get(tv_key, None) is None: _isAuthenticationPolicyEnabled = CachingMethod( _isAuthenticationPolicyEnabled, id='PortalPreferences_isAuthenticationPolicyEnabled', cache_factory='erp5_content_short') tv[tv_key] = _isAuthenticationPolicyEnabled() return tv[tv_key]
def testTransformationSourcing(self, context): if context.getReference().split('/', 1)[0] == 'pr': return False # context consumes a resource: maybe sourcing is required. # Let's see if the business process defines any trade phase that: # - is not yet expanded (well, we only checks parents and siblings) # - and precedes a phase of the current transformation phase = context.getTradePhase() parent = context.getParentValue() tv = getTransactionalVariable() key = 'isSourcingNeeded', parent.getUid() try: needed_set = tv[key] except KeyError: phase_set = set(x.getTradePhase() for x in parent.objectValues()) phase_list = phase_set.copy() movement = parent.getParentValue() while movement.getPortalType() == 'Simulation Movement': phase_set.add(movement.getTradePhase()) movement = movement.getParentValue().getParentValue() previous_dict = context.asComposedDocument( ).getPreviousTradePhaseDict() needed_set = tv[key] = frozenset(x for x in phase_list if previous_dict[x] - phase_set) return phase in needed_set
def testTransformationSourcing(self, context): # make sure to ignore produced resources to keep consumed resources if context.getReference().split('/', 1)[0] == 'pr': return False # context consumes a resource: maybe sourcing is required. # Let's see if the business process defines any trade phase that: # - is not yet expanded (well, we only checks parents and siblings) # - and precedes a phase of the current transformation phase = context.getTradePhase() parent = context.getParentValue() tv = getTransactionalVariable() key = 'isSourcingNeeded', parent.getUid() try: needed_set = tv[key] except KeyError: phase_set = set(x.getTradePhase() for x in parent.objectValues()) phase_list = phase_set.copy() movement = parent.getParentValue() while movement.getPortalType() == 'Simulation Movement': phase_set.add(movement.getTradePhase()) movement = movement.getParentValue().getParentValue() previous_dict = context.asComposedDocument().getPreviousTradePhaseDict() needed_set = tv[key] = frozenset(x for x in phase_list if previous_dict[x] - phase_set) return phase in needed_set
def _isTreeDelivered(self): """ checks if subapplied rules of this movement (going down the complete simulation tree) have a child with a delivery relation. Returns True if at least one is delivered, False if none of them are. see AppliedRule._isTreeDelivered """ def getTreeDelivered(): if self.getDeliveryList(): return True for applied_rule in self.objectValues(): if applied_rule._isTreeDelivered(): return True return False try: cache = getTransactionalVariable()[TREE_DELIVERED_CACHE_KEY] except KeyError: return getTreeDelivered() rule_key = self.getRelativeUrl() try: return cache[rule_key] except KeyError: cache[rule_key] = result = getTreeDelivered() return result
def _getConversionDataDict(self, **kw): """ """ cache_id = self._getCacheKey(**kw) cache_factory = self._getCacheFactory() if cache_factory is None: return getattr(aq_base(self), 'temp_conversion_data', {})[cache_id] # The purpose of this cache is to help calls to the same cache value # in the same transaction. tv = getTransactionalVariable() try: return tv[cache_id] except KeyError: pass for cache_plugin in cache_factory.getCachePluginList(): cache_entry = cache_plugin.get(cache_id, DEFAULT_CACHE_SCOPE) if cache_entry is not None: data_dict = cache_entry.getValue() if data_dict: if isinstance(data_dict, tuple): # Backward compatibility: if cached value is a tuple # as it was before refactoring # http://svn.erp5.org?rev=35216&view=rev # raise a KeyError to invalidate this cache entry and force # calculation of a new conversion raise KeyError('Old cache conversion format,'\ 'cache entry invalidated for key:%r' % cache_id) content_md5 = data_dict['content_md5'] if content_md5 != self.getContentMd5(): raise KeyError, 'Conversion cache key is compromised for %r' % cache_id # Fill transactional cache in order to help # querying real cache during same transaction tv[cache_id] = data_dict return data_dict raise KeyError, 'Conversion cache key does not exists for %r' % cache_id
def _isTreeDelivered(self, ignore_first=0): """ checks if subapplied rules of this movement (going down the complete simulation tree) have a child with a delivery relation. Returns True if at least one is delivered, False if none of them are. see AppliedRule._isTreeDelivered """ tv = getTransactionalVariable() cache = tv.setdefault(TREE_DELIVERED_CACHE_KEY, {}) cache_enabled = cache.get(TREE_DELIVERED_CACHE_ENABLED, 0) def getTreeDelivered(movement, ignore_first=0): if not ignore_first: if len(movement.getDeliveryList()) > 0: return True for applied_rule in movement.objectValues(): if applied_rule._isTreeDelivered(): return True return False if ignore_first: rule_key = (self.getRelativeUrl(), 1) else: rule_key = self.getRelativeUrl() if cache_enabled: try: return cache[rule_key] except KeyError: result = getTreeDelivered(self, ignore_first=ignore_first) cache[rule_key] = result return result else: return getTreeDelivered(self, ignore_first=ignore_first)
def _getTemplateFieldCache(self): parent = self.aq_parent if parent is not None: cache = getTransactionalVariable()[self._getCacheId()] if cache is not None: return cache.__of__(parent) raise KeyError
def _isTreeDelivered(self): """ Checks if submovements of this applied rule (going down the complete simulation tree) have a delivery relation. Returns True if at least one is delivered, False if none of them are. see SimulationMovement._isTreeDelivered """ tv = getTransactionalVariable() cache = tv.setdefault(TREE_DELIVERED_CACHE_KEY, {}) cache_enabled = cache.get(TREE_DELIVERED_CACHE_ENABLED, 0) def getTreeDelivered(applied_rule): for movement in applied_rule.objectValues(): if movement._isTreeDelivered(): return True return False rule_key = self.getRelativeUrl() if cache_enabled: try: return cache[rule_key] except: result = getTreeDelivered(self) cache[rule_key] = result return result else: return getTreeDelivered(self)
def test_01_DictInterface(self): """Check if a transaction variable behaves in the same way as a dict. """ tv = getTransactionalVariable() self.failIfEqual(tv, None) # Test frequently used dict methods. This does not cover everything, # but should be enough. tv.clear() self.failUnlessEqual(len(tv), 0) self.failUnlessRaises(KeyError, tv.__getitem__, 'toto') tv['toto'] = 'titi' self.failUnlessEqual(len(tv), 1) self.failUnlessEqual(tv['toto'], 'titi') self.failUnlessEqual(tv.get('foo'), None) tv.setdefault('foo', 'bar') self.failUnlessEqual(len(tv), 2) self.failUnlessEqual(tv['foo'], 'bar') self.failUnless('foo' in tv) del tv['foo'] self.failIf('foo' in tv) self.failUnlessEqual(len(tv), 1)
def convert(self, format, **kw): """ Main content conversion function, returns result which should be returned and stored in cache. If format is not allowed for download, Unauthorized exception is raised. format - the format specied in the form of an extension string (ex. jpeg, html, text, txt, etc.) **kw can be various things - e.g. resolution """ transaction_variable = getTransactionalVariable() if LOCK_PERMISSION_KEY in transaction_variable: # in convert we want always to check conversion format permission # to bypass such check one should use _convert directly del transaction_variable[LOCK_PERMISSION_KEY] self._checkConversionFormatPermission(format, lock_checking=True, **kw) pre_converted_only = kw.pop('pre_converted_only', False) if pre_converted_only: # we will use ONLY cache to return converted content # if respective document is not in cache we will return a good default content try: kw['format'] = format result = self.getConversion(**kw) except KeyError: # respective document is not cached yet and we should return a failure safe content instead result = self.getFailsafeConversion(**kw) else: # generate conversion on the fly or get it from cache (if already stored) result = self._convert(format, **kw) if LOCK_PERMISSION_KEY in transaction_variable: del transaction_variable[LOCK_PERMISSION_KEY] return result
def convert(self, format, **kw): """ Main content conversion function, returns result which should be returned and stored in cache. If format is not allowed for download, Unauthorized exception is raised. format - the format specied in the form of an extension string (ex. jpeg, html, text, txt, etc.) **kw can be various things - e.g. resolution """ transaction_variable = getTransactionalVariable() if LOCK_PERMISSION_KEY in transaction_variable: # in convert we want always to check conversion format permission # to bypass such check one should use _convert directly del transaction_variable[LOCK_PERMISSION_KEY] self._checkConversionFormatPermission(format, lock_checking=True, **kw) pre_converted_only = kw.pop('pre_converted_only', False) if pre_converted_only: # we will use ONLY cache to return converted content # if respective document is not in cache we will return a good default content try: kw['format'] = format result = self.getConversion(**kw) except KeyError: # respective document is not cached yet and we should return a failure safe content instead result = self.getFailsafeConversion(**kw) else: # generate conversion on the fly or get it from cache (if already stored) result = self._convert(format, **kw) if LOCK_PERMISSION_KEY in transaction_variable: del transaction_variable[LOCK_PERMISSION_KEY] return result
def wrapper(*args, **kw): cache = getTransactionalVariable().setdefault(key, {}) subkey = key_method(*args, **kw) try: return cache[subkey] except KeyError: cache[subkey] = result = function(*args, **kw) return result
def __new__(cls, tv_key): tv = getTransactionalVariable() try: return str(tv[tv_key]) except KeyError: path = mkdtemp() tv[tv_key] = str.__new__(cls, path) return path
def __new__(cls, tv_key): tv = getTransactionalVariable() try: return str(tv[tv_key]) except KeyError: path = mkdtemp() tv[tv_key] = str.__new__(cls, path) return path
def wrapper(*args, **kw): cache = getTransactionalVariable().setdefault(key, {}) subkey = key_method(*args, **kw) try: return cache[subkey] except KeyError: cache[subkey] = result = function(*args, **kw) return result
def getRemainingTradePhaseList(self, business_link): """Returns the list of remaining trade phases which to be achieved as part of a business process. This list is calculated by analysing the graph of business link and trade states, starting from a given business link. The result if filtered by a list of trade phases. This method is useful mostly for production and MRP to manage a distributed supply and production chain. explanation -- an Order, Order Line, Delivery or Delivery Line or Applied Rule which implicitely defines a simulation subtree business_link -- a Business Link document NOTE: explanation is not involved here because we consider here that self is the result of asUnionBusinessProcess and thus only contains applicable Business Link to a given simulation subtree. Since the list of remaining trade phases does not depend on exact values in the simulation, we did not include the explanation. However, this makes the API less uniform. """ remaining_trade_phase_list = [] trade_state = business_link.getSuccessor() tv = getTransactionalVariable() # We might need a key which depends on the explanation key = 'BusinessProcess_predecessor_successor_%s' % self.getRelativeUrl( ) predecessor_successor_dict = tv.get(key, None) if predecessor_successor_dict is None: predecessor_successor_dict = {'predecessor': {}, 'successor': {}} for business_link in self.objectValues( portal_type="Business Link"): for property_name in ('predecessor', 'successor'): property_value = business_link.getProperty(property_name) if property_value: business_link_list = predecessor_successor_dict[property_name].\ setdefault(property_value, []) business_link_list.append(business_link) tv[key] = predecessor_successor_dict business_link_list = predecessor_successor_dict['predecessor'].\ get(trade_state, []) assert len(business_link_list) <= 1, \ "code is not able yet to manage this case" for link in business_link_list: remaining_trade_phase_list += link.getTradePhaseValueList() # collect to successor direction recursively state = link.getSuccessor() if state is not None: next_business_link_list = predecessor_successor_dict['successor'].\ get(state, []) assert len(next_business_link_list) == 1, \ "code is not able yet to manage this case" remaining_trade_phase_list.extend( self.getRemainingTradePhaseList( next_business_link_list[0])) return remaining_trade_phase_list
def setConversion(self, data, mime=None, date=None, **kw): """ """ cache_id = self._getCacheKey(**kw) if data is None: cached_value = None conversion_md5 = None size = 0 elif isinstance(data, Pdata): cached_value = aq_base(data) size = str(cached_value) # not a size but avoids a 'del' statement conversion_md5 = md5(size).hexdigest() size = len(size) elif isinstance(data, OFSImage): warn('Passing an OFS.Image to setConversion is deprecated', stacklevel=1) cached_value = data conversion_md5 = md5(str(data.data)).hexdigest() size = len(data.data) elif isinstance(data, ( str, unicode, )): cached_value = data conversion_md5 = md5(cached_value).hexdigest() size = len(cached_value) elif isinstance(data, dict): # Dict instance are used to store computed metadata # from actual content. # So this value is intimely related to cache of conversion. # As it should be cleared each time the document is edited. # Also may be a proper API should be used cached_value = data conversion_md5 = None size = len(cached_value) else: raise NotImplementedError, 'Not able to store type:%r' % type(data) if date is None: date = DateTime() stored_data_dict = { 'content_md5': self.getContentMd5(), 'conversion_md5': conversion_md5, 'mime': mime, 'data': cached_value, 'date': date, 'size': size } cache_factory = self._getCacheFactory() if cache_factory is None: if getattr(aq_base(self), 'temp_conversion_data', None) is None: self.temp_conversion_data = {} self.temp_conversion_data[cache_id] = stored_data_dict return # The purpose of this transaction cache is to help calls # to the same cache value in the same transaction. tv = getTransactionalVariable() tv[cache_id] = stored_data_dict cache_factory.set(cache_id, stored_data_dict)
def getRemainingTradePhaseList(self, business_link): """Returns the list of remaining trade phases which to be achieved as part of a business process. This list is calculated by analysing the graph of business link and trade states, starting from a given business link. The result if filtered by a list of trade phases. This method is useful mostly for production and MRP to manage a distributed supply and production chain. explanation -- an Order, Order Line, Delivery or Delivery Line or Applied Rule which implicitely defines a simulation subtree business_link -- a Business Link document NOTE: explanation is not involved here because we consider here that self is the result of asUnionBusinessProcess and thus only contains applicable Business Link to a given simulation subtree. Since the list of remaining trade phases does not depend on exact values in the simulation, we did not include the explanation. However, this makes the API less uniform. """ remaining_trade_phase_list = [] trade_state = business_link.getSuccessor() tv = getTransactionalVariable() # We might need a key which depends on the explanation key = 'BusinessProcess_predecessor_successor_%s' % self.getRelativeUrl() predecessor_successor_dict = tv.get(key, None) if predecessor_successor_dict is None: predecessor_successor_dict = {'predecessor':{}, 'successor':{}} for business_link in self.objectValues(portal_type="Business Link"): for property_name in ('predecessor', 'successor'): property_value = business_link.getProperty(property_name) if property_value: business_link_list = predecessor_successor_dict[property_name].\ setdefault(property_value, []) business_link_list.append(business_link) tv[key] = predecessor_successor_dict business_link_list = predecessor_successor_dict['predecessor'].\ get(trade_state, []) assert len(business_link_list) <= 1, \ "code is not able yet to manage this case" for link in business_link_list: remaining_trade_phase_list += link.getTradePhaseValueList() # collect to successor direction recursively state = link.getSuccessor() if state is not None: next_business_link_list = predecessor_successor_dict['successor'].\ get(state, []) assert len(next_business_link_list) == 1, \ "code is not able yet to manage this case" remaining_trade_phase_list.extend( self.getRemainingTradePhaseList( next_business_link_list[0])) return remaining_trade_phase_list
def getSecurityUidDictAndRoleColumnDict(self, sql_catalog_id=None, local_roles=None): """ Return a dict of local_roles_group_id -> security Uids and a dictionnary containing available role columns. XXX: This method always uses default catalog. This should not break a site as long as security uids are considered consistent among all catalogs. """ allowedRolesAndUsers, role_column_dict, local_role_column_dict = \ self.getAllowedRolesAndUsers( sql_catalog_id=sql_catalog_id, local_roles=local_roles, ) catalog = self.getSQLCatalog(sql_catalog_id) method = getattr(catalog, catalog.sql_search_security, None) if allowedRolesAndUsers: allowedRolesAndUsers.sort() cache_key = tuple(allowedRolesAndUsers) tv = getTransactionalVariable() try: security_uid_cache = tv['getSecurityUidDictAndRoleColumnDict'] except KeyError: security_uid_cache = tv[ 'getSecurityUidDictAndRoleColumnDict'] = {} try: security_uid_dict = security_uid_cache[cache_key] except KeyError: if method is None: warnings.warn("The usage of allowedRolesAndUsers is "\ "deprecated. Please update your catalog "\ "business template.", DeprecationWarning) security_uid_dict = {None: [x.security_uid for x in \ self.unrestrictedSearchResults( allowedRolesAndUsers=allowedRolesAndUsers, select_expression="security_uid", group_by_expression="security_uid")] } else: # XXX: What with this string transformation ?! Souldn't it be done in # dtml instead ? ... yes, but how to be bw compatible ? allowedRolesAndUsers = [ sqlquote(role) for role in allowedRolesAndUsers ] security_uid_dict = defaultdict(list) for brain in method( security_roles_list=allowedRolesAndUsers): security_uid_dict[getattr(brain, 'local_roles_group_id', '')].append(brain.uid) security_uid_cache[cache_key] = security_uid_dict else: security_uid_dict = [] return security_uid_dict, role_column_dict, local_role_column_dict
def __checkUserIdAvailability(self, pas_plugin_class, user_id=None, login=None, check_concurrent_execution=True): # Encode reference to hex to prevent uppercase/lowercase conflict in # activity table (when calling countMessageWithTag) if user_id: tag = 'set_userid_' + user_id.encode('hex') else: tag = 'set_login_' + login.encode('hex') # Check that there no existing user acl_users = getattr(self, 'acl_users', None) if PluggableAuthService is not None and isinstance( acl_users, PluggableAuthService.PluggableAuthService. PluggableAuthService): plugin_name_set = { plugin_name for plugin_name, plugin_value in acl_users.plugins.listPlugins( PluggableAuthService.interfaces.plugins. IUserEnumerationPlugin, ) if isinstance(plugin_value, pas_plugin_class) } if plugin_name_set: if any(user['pluginid'] in plugin_name_set for user in acl_users.searchUsers( id=user_id, login=login, exact_match=True, )): raise UserExistsError(user_id or login) else: # PAS is used, without expected enumeration plugin: property has no # effect on user enumeration, skip checks. # XXX: what if desired plugin becomes active later ? return if not check_concurrent_execution: return # Check that there is no reindexation related to reference indexation if self.getPortalObject().portal_activities.countMessageWithTag(tag): raise UserExistsError(user_id) # Prevent concurrent transaction to set the same reference on 2 # different persons # XXX: person_module is rather large because of all permission # declarations, it would be better to find a smaller document to use # here. self.getParentValue().serialize() # Prevent to set the same reference on 2 different persons during the # same transaction transactional_variable = getTransactionalVariable() if tag in transactional_variable: raise UserExistsError(user_id) else: transactional_variable[tag] = None self.reindexObject(activate_kw={'tag': tag})
def expand(self, **kw): """ Checks all existing applied rules and make sure they still apply. Checks for other possible rules and starts expansion process (instanciates applied rules and calls expand on them). First get all applicable rules, then, delete all applied rules that no longer match and are not linked to a delivery, finally, apply new rules if no rule with the same type is already applied. """ tv = getTransactionalVariable() cache = tv.setdefault(TREE_DELIVERED_CACHE_KEY, {}) cache_enabled = cache.get(TREE_DELIVERED_CACHE_ENABLED, 0) # enable cache if not cache_enabled: cache[TREE_DELIVERED_CACHE_ENABLED] = 1 applied_rule_dict = {} applicable_rule_dict = {} successor_self = self._asSuccessorContext() for rule in successor_self._getApplicableRuleList(): reference = rule.getReference() if reference: # XXX-Leo: We should complain loudly if there is more than one # applicable rule per reference. It indicates a configuration error. applicable_rule_dict.setdefault(reference, rule) for applied_rule in list(self.objectValues()): rule = applied_rule.getSpecialiseValue() # check if applied rule is already expanded, or if its portal # rule is still applicable to this Simulation Movement with # successor trade_phases if (successor_self._isRuleStillApplicable(rule) or applied_rule._isTreeDelivered()): applied_rule_dict[rule.getReference()] = applied_rule else: self._delObject(applied_rule.getId()) for reference, rule in applicable_rule_dict.iteritems(): if reference not in applied_rule_dict: applied_rule = rule.constructNewAppliedRule(self, **kw) applied_rule_dict[reference] = applied_rule self.setCausalityState('expanded') # expand for applied_rule in applied_rule_dict.itervalues(): applied_rule.expand(**kw) # disable and clear cache if not cache_enabled: try: del tv[TREE_DELIVERED_CACHE_KEY] except KeyError: pass
def _getOb(self, id, default=_marker, **kw): """ XXX """ tv = getTransactionalVariable() document_url = tv.get((id,), None) if document_url is not None: return self.getPortalObject().unrestrictedTraverse(document_url) return Folder._getOb(self, id, **kw)
def setDefaultActivateParameterDict(self, parameter_dict, placeless=False): # This method sets the default keyword parameters to activate. This is # useful when you need to specify special parameters implicitly (e.g. to # reindexObject). tv = getTransactionalVariable() if placeless: key = (_DEFAULT_ACTIVATE_PARAMETER_KEY,) else: key = (_DEFAULT_ACTIVATE_PARAMETER_KEY, id(aq_base(self))) tv[key] = parameter_dict.copy()
def _getOb(self, id, default=_marker, **kw): """ XXX """ tv = getTransactionalVariable() document_url = tv.get((id, ), None) if document_url is not None: return self.getPortalObject().unrestrictedTraverse(document_url) return Folder._getOb(self, id, **kw)
def setDefaultActivateParameterDict(self, parameter_dict, placeless=False): # This method sets the default keyword parameters to activate. This is # useful when you need to specify special parameters implicitly (e.g. to # reindexObject). tv = getTransactionalVariable() if placeless: key = (_DEFAULT_ACTIVATE_PARAMETER_KEY, ) else: key = (_DEFAULT_ACTIVATE_PARAMETER_KEY, id(aq_base(self))) tv[key] = parameter_dict.copy()
def readOnlyTransactionCache(): tv = getTransactionalVariable() if 'read_only_transaction_cache' in tv: yield else: tv['read_only_transaction_cache'] = {} try: yield finally: del tv['read_only_transaction_cache']
def readOnlyTransactionCache(): tv = getTransactionalVariable() if 'read_only_transaction_cache' in tv: yield else: tv['read_only_transaction_cache'] = {} try: yield finally: del tv['read_only_transaction_cache']
def expand(self, **kw): """ Checks all existing applied rules and make sure they still apply. Checks for other possible rules and starts expansion process (instanciates applied rules and calls expand on them). First get all applicable rules, then, delete all applied rules that no longer match and are not linked to a delivery, finally, apply new rules if no rule with the same type is already applied. """ tv = getTransactionalVariable() cache = tv.setdefault(TREE_DELIVERED_CACHE_KEY, {}) cache_enabled = cache.get(TREE_DELIVERED_CACHE_ENABLED, 0) # enable cache if not cache_enabled: cache[TREE_DELIVERED_CACHE_ENABLED] = 1 applicable_rule_dict = {} for rule in self._getApplicableRuleList(): reference = rule.getReference() if reference: # XXX-Leo: We should complain loudly if there is more than one # applicable rule per reference. It indicates a configuration error. applicable_rule_dict.setdefault(reference, rule) applicable_rule_list = applicable_rule_dict.values() for applied_rule in list(self.objectValues()): rule = applied_rule.getSpecialiseValue() try: applicable_rule_list.remove(rule) except ValueError: if applied_rule._isTreeDelivered(): reference = rule.getReference() try: applicable_rule_list.remove(applicable_rule_dict.pop(reference)) except KeyError: pass else: self._delObject(applied_rule.getId()) else: applied_rule.expand(**kw) for rule in applicable_rule_list: rule.constructNewAppliedRule(self, **kw).expand(**kw) self.setCausalityState('expanded') # disable and clear cache if not cache_enabled: try: del tv[TREE_DELIVERED_CACHE_KEY] except KeyError: pass
def test_not_a_person(self): self.tic() self.assertEqual(self.portal.subscription_request_module, self.portal.SubscriptionRequest_saveTransactionalUser(self.portal.subscription_request_module)) try: self.assertEqual(None, getTransactionalVariable()["transactional_user"]) except KeyError: pass self.tic()
def expand(self, *args): """Initialize context, and really start to expand""" tv = getTransactionalVariable() assert TREE_DELIVERED_CACHE_KEY not in tv, "already expanding" self.context = args[-1] with self.context.defaultActivateParameterDict(self.activate_kw, True): tv[TREE_DELIVERED_CACHE_KEY] = {} try: self(*args) finally: del tv[TREE_DELIVERED_CACHE_KEY]
def setConversion(self, data, mime=None, date=None, **kw): """ """ cache_id = self._getCacheKey(**kw) if data is None: cached_value = None conversion_md5 = None size = 0 elif isinstance(data, Pdata): cached_value = aq_base(data) size = str(cached_value) # not a size but avoids a 'del' statement conversion_md5 = md5(size).hexdigest() size = len(size) elif isinstance(data, OFSImage): cached_value = data conversion_md5 = md5(str(data.data)).hexdigest() size = len(data.data) elif isinstance(data, (str, unicode,)): cached_value = data conversion_md5 = md5(cached_value).hexdigest() size = len(cached_value) elif isinstance(data, dict): # Dict instance are used to store computed metadata # from actual content. # So this value is intimely related to cache of conversion. # As it should be cleared each time the document is edited. # Also may be a proper API should be used cached_value = data conversion_md5 = None size = len(cached_value) else: raise NotImplementedError, 'Not able to store type:%r' % type(data) if date is None: date = DateTime() stored_data_dict = {'content_md5': self.getContentMd5(), 'conversion_md5': conversion_md5, 'mime': mime, 'data': cached_value, 'date': date, 'size': size} cache_factory = self._getCacheFactory() if cache_factory is None: if getattr(aq_base(self), 'temp_conversion_data', None) is None: self.temp_conversion_data = {} self.temp_conversion_data[cache_id] = stored_data_dict return cache_duration = cache_factory.cache_duration # The purpose of this transaction cache is to help calls # to the same cache value in the same transaction. tv = getTransactionalVariable() tv[cache_id] = stored_data_dict for cache_plugin in cache_factory.getCachePluginList(): cache_plugin.set(cache_id, DEFAULT_CACHE_SCOPE, stored_data_dict, cache_duration=cache_duration)
def expand(self, *args): """Initialize context, and really start to expand""" tv = getTransactionalVariable() assert TREE_DELIVERED_CACHE_KEY not in tv, "already expanding" self.context = args[-1] with self.context.defaultActivateParameterDict(self.activate_kw, True): tv[TREE_DELIVERED_CACHE_KEY] = {} try: self(*args) finally: del tv[TREE_DELIVERED_CACHE_KEY]
def setConversion(self, data, mime=None, date=None, **kw): """ """ cache_id = self._getCacheKey(**kw) if data is None: cached_value = None conversion_md5 = None size = 0 elif isinstance(data, Pdata): cached_value = aq_base(data) size = str(cached_value) # not a size but avoids a 'del' statement conversion_md5 = md5(size).hexdigest() size = len(size) elif isinstance(data, OFSImage): warn("Passing an OFS.Image to setConversion is deprecated", stacklevel=1) cached_value = data conversion_md5 = md5(str(data.data)).hexdigest() size = len(data.data) elif isinstance(data, (str, unicode)): cached_value = data conversion_md5 = md5(cached_value).hexdigest() size = len(cached_value) elif isinstance(data, dict): # Dict instance are used to store computed metadata # from actual content. # So this value is intimely related to cache of conversion. # As it should be cleared each time the document is edited. # Also may be a proper API should be used cached_value = data conversion_md5 = None size = len(cached_value) else: raise NotImplementedError, "Not able to store type:%r" % type(data) if date is None: date = DateTime() stored_data_dict = { "content_md5": self.getContentMd5(), "conversion_md5": conversion_md5, "mime": mime, "data": cached_value, "date": date, "size": size, } cache_factory = self._getCacheFactory() if cache_factory is None: if getattr(aq_base(self), "temp_conversion_data", None) is None: self.temp_conversion_data = {} self.temp_conversion_data[cache_id] = stored_data_dict return # The purpose of this transaction cache is to help calls # to the same cache value in the same transaction. tv = getTransactionalVariable() tv[cache_id] = stored_data_dict cache_factory.set(cache_id, stored_data_dict)
def getSecurityUidDictAndRoleColumnDict(self, sql_catalog_id=None, **kw): """ Return a dict of local_roles_group_id -> security Uids and a dictionnary containing available role columns. XXX: This method always uses default catalog. This should not break a site as long as security uids are considered consistent among all catalogs. """ allowedRolesAndUsers, role_column_dict, local_role_column_dict = self.getAllowedRolesAndUsers(**kw) catalog = self.getSQLCatalog(sql_catalog_id) method = getattr(catalog, catalog.sql_search_security, None) if allowedRolesAndUsers: allowedRolesAndUsers.sort() cache_key = tuple(allowedRolesAndUsers) tv = getTransactionalVariable() try: security_uid_cache = tv["getSecurityUidDictAndRoleColumnDict"] except KeyError: security_uid_cache = tv["getSecurityUidDictAndRoleColumnDict"] = {} try: security_uid_dict = security_uid_cache[cache_key] except KeyError: if method is None: warnings.warn( "The usage of allowedRolesAndUsers is " "deprecated. Please update your catalog " "business template.", DeprecationWarning, ) security_uid_dict = { None: [ x.security_uid for x in self.unrestrictedSearchResults( allowedRolesAndUsers=allowedRolesAndUsers, select_expression="security_uid", group_by_expression="security_uid", ) ] } else: # XXX: What with this string transformation ?! Souldn't it be done in # dtml instead ? ... yes, but how to be bw compatible ? allowedRolesAndUsers = [sqlquote(role) for role in allowedRolesAndUsers] security_uid_dict = defaultdict(list) for brain in method(security_roles_list=allowedRolesAndUsers): security_uid_dict[getattr(brain, "local_roles_group_id", "")].append(brain.uid) security_uid_cache[cache_key] = security_uid_dict else: security_uid_dict = [] return security_uid_dict, role_column_dict, local_role_column_dict
def _setReference(self, value): """ Set the user id. This method is defined explicitly, because: - we want to apply a different permission - we want to prevent duplicated user ids, but only when PAS _AND_ ERP5UserManager are used """ activate_kw = {} portal = self.getPortalObject() if value: # Encode reference to hex to prevent uppercase/lowercase conflict in # activity table (when calling countMessageWithTag) activate_kw['tag'] = tag = 'Person_setReference_' + value.encode( 'hex') # Check that there no existing user acl_users = portal.acl_users if PluggableAuthService is not None and isinstance( acl_users, PluggableAuthService.PluggableAuthService. PluggableAuthService): plugin_list = acl_users.plugins.listPlugins( PluggableAuthService.interfaces.plugins. IUserEnumerationPlugin) for plugin_name, plugin_value in plugin_list: if isinstance(plugin_value, ERP5UserManager): user_list = acl_users.searchUsers(id=value, exact_match=True) if len(user_list) > 0: raise RuntimeError, 'user id %s already exist' % ( value, ) break # Check that there is no reindexation related to reference indexation if portal.portal_activities.countMessageWithTag(tag): raise RuntimeError, 'user id %s already exist' % (value, ) # Prevent concurrent transaction to set the same reference on 2 # different persons self.getParentValue().serialize() # Prevent to set the same reference on 2 different persons during the # same transaction transactional_variable = getTransactionalVariable() if tag in transactional_variable: raise RuntimeError, 'user id %s already exist' % (value, ) else: transactional_variable[tag] = None self._baseSetReference(value) self.reindexObject(activate_kw=activate_kw) # invalid the cache for ERP5Security portal_caches = portal.portal_caches portal_caches.clearCache(cache_factory_list=('erp5_content_short', ))
def asPredicate(self): """ This method tries to convert the current Document into a predicate looking up methods named Class_asPredicate, MetaType_asPredicate, PortalType_asPredicate """ cache = getTransactionalVariable() key = 'asPredicate', self try: return cache[key] except KeyError: self = unrestricted_apply(self._getTypeBasedMethod("asPredicate", "_asPredicate")) cache[key] = self return self
def _getObjectByUid(self, uid): uid_cache = getTransactionalVariable().setdefault( 'InventoryBrain.uid_cache', {None: None}) try: return uid_cache[uid] except KeyError: result_list = self.portal_catalog(uid=uid, limit=1, select_dict=dict(title=None, relative_url=None)) result = None if result_list: result = result_list[0] uid_cache[uid] = result return result
def _setObject(self, id, ob, **kw): """ XXX """ tv = getTransactionalVariable() key = (id, ) tv[key] = ob.__of__(self).getRelativeUrl() method = getattr(self, 'Base_setObject', None) if method is not None: return method(id, ob, **kw) return Folder._setObject(self, id, ob, **kw)
def asPredicate(self): """ This method tries to convert the current Document into a predicate looking up methods named Class_asPredicate, MetaType_asPredicate, PortalType_asPredicate """ cache = getTransactionalVariable() key = "asPredicate", self try: return cache[key] except KeyError: self = unrestricted_apply(self._getTypeBasedMethod("asPredicate", "_asPredicate")) cache[key] = self return self
def _setObject(self, id, ob, **kw): """ XXX """ tv = getTransactionalVariable() key = (id, ) tv[key] = ob.__of__(self).getRelativeUrl() method = getattr(self, 'Base_setObject', None) if method is not None: return method(id, ob, **kw) return Folder._setObject(self, id, ob, **kw)
def _getObjectByUid(self, uid): uid_cache = getTransactionalVariable().setdefault( 'InventoryBrain.uid_cache', {None: None}) try: return uid_cache[uid] except KeyError: result_list = self.portal_catalog.unrestrictedSearchResults(uid=uid, limit=1, select_dict=dict(title=None, relative_url=None)) result = None if result_list: result = result_list[0] uid_cache[uid] = result return result
def _setObject(self, id, ob, **kw): """ XXX """ tv = getTransactionalVariable() key = 'VirtualFolderMixin', self.getPhysicalPath(), id tv[key] = ob.__of__(self).getRelativeUrl() method = getattr(self, 'Base_setObject', None) if method is not None: return method(id, ob, **kw) return Folder._setObject(self, id, ob, **kw)
def resetOnceAtTransactionBoundary(self): """ Schedule a single reset at the end of the transaction. The idea behind this is that a reset is (very) costly and that we want to do it as little often as possible. Moreover, doing it twice in a transaction is useless (but still twice as costly). """ tv = getTransactionalVariable() key = 'ComponentTool.resetOnceAtTransactionBoundary' if key not in tv: tv[key] = None transaction.get().addBeforeCommitHook(self.reset, args=(True, True))
def updateSimulation(self, **kw): """Create/update related simulation trees by activity This method is used to maintain related objects in simulation trees: - hiding complexity of activity dependencies - avoiding duplicate work Repeated calls of this method for the same delivery will result in a single call to _updateSimulation. Grouping may happen at the end of the transaction or by the grouping method. See _updateSimulation for accepted parameters. """ tv = getTransactionalVariable() key = 'SimulableMixin.updateSimulation', self.getUid() item_list = kw.items() try: kw, ignore = tv[key] kw.update(item_list) except KeyError: ignore_key = key + ('ignore', ) ignore = tv.pop(ignore_key, set()) tv[key] = kw, ignore def before_commit(): if kw: path = self.getPath() if aq_base(self.unrestrictedTraverse( path, None)) is aq_base(self): self.activate( activity='SQLQueue', group_method_id='portal_rules/updateSimulation', tag='expand:' + path, # Now that we don't rely on catalog anymore, this after_tag could # moved to _localBuild, which currently only depends on 'expand:'. after_tag='built:' + path, priority=3, )._updateSimulation(**kw) del tv[key] ignore.update(kw) tv[ignore_key] = ignore transaction.get().addBeforeCommitHook(before_commit) for k, v in item_list: if not v: ignore.add(k) elif k not in ignore: continue del kw[k]
def _getOb(self, id, default=_marker, **kw): """ XXX """ tv = getTransactionalVariable() document_url = tv.get((id, ), None) if document_url is not None: return self.getPortalObject().unrestrictedTraverse(document_url) try: return Folder._getOb(self, id, default=default, **kw) except KeyError: if default is _marker: raise return default
def getDefaultActivateParameterDict(self, inherit_placeless=True): # This method returns default activate parameters to self. # The result is a dict object. default = {} tv = getTransactionalVariable() if inherit_placeless: placeless = tv.get((_DEFAULT_ACTIVATE_PARAMETER_KEY,), default) else: placeless = default local = tv.get((_DEFAULT_ACTIVATE_PARAMETER_KEY, id(aq_base(self))), default) result = placeless.copy() # local defaults takes precedence over placeless defaults. result.update(local) return result