[gen] Ref.linkObject and unlinkObject (and caller methods like wrapper.create) can now be called with attr 'executeMethods' being False: in this case, all methods defined in attrs like 'insert', 'beforelink', 'afterLink' will not be called. Can be useful while migrating data or duplicating objects.
This commit is contained in:
		
							parent
							
								
									1d81dc768b
								
							
						
					
					
						commit
						abe56a5add
					
				
					 4 changed files with 72 additions and 50 deletions
				
			
		|  | @ -982,15 +982,25 @@ class Ref(Field): | ||||||
|         elif nbOfRefs > maxRef: |         elif nbOfRefs > maxRef: | ||||||
|             return obj.translate('max_ref_violated') |             return obj.translate('max_ref_violated') | ||||||
| 
 | 
 | ||||||
|     def linkObject(self, obj, value, back=False, noSecurity=True): |     def linkObject(self, obj, value, back=False, noSecurity=True, | ||||||
|  |                    executeMethods=True): | ||||||
|         '''This method links p_value (which can be a list of objects) to p_obj |         '''This method links p_value (which can be a list of objects) to p_obj | ||||||
|            through this Ref field.''' |            through this Ref field. When linking 2 objects via a Ref, | ||||||
|  |            p_linkObject must be called twice: once on the forward Ref and once | ||||||
|  |            on the backward ref. p_back indicates if we are calling it on the | ||||||
|  |            forward or backward Ref. If p_noSecurity is True, we bypass security | ||||||
|  |            checks (has the logged user the right to modify this Ref field?). | ||||||
|  |            If p_executeMethods is False, we do not execute methods that | ||||||
|  |            customize the object insertion (parameters insert, beforeLink, | ||||||
|  |            afterLink...). This can be useful while migrating data or duplicating | ||||||
|  |            an object.''' | ||||||
|         zobj = obj.o |         zobj = obj.o | ||||||
|         # Security check |         # Security check | ||||||
|         if not noSecurity: zobj.mayEdit(self.writePermission, raiseError=True) |         if not noSecurity: zobj.mayEdit(self.writePermission, raiseError=True) | ||||||
|         # p_value can be a list of objects |         # p_value can be a list of objects | ||||||
|         if type(value) in sutils.sequenceTypes: |         if type(value) in sutils.sequenceTypes: | ||||||
|             for v in value: self.linkObject(obj, v, back=back) |             for v in value: | ||||||
|  |                 self.linkObject(obj, v, back, noSecurity, executeMethods) | ||||||
|             return |             return | ||||||
|         # Gets the list of referred objects (=list of uids), or create it. |         # Gets the list of referred objects (=list of uids), or create it. | ||||||
|         refs = getattr(zobj.aq_base, self.name, None) |         refs = getattr(zobj.aq_base, self.name, None) | ||||||
|  | @ -1001,9 +1011,9 @@ class Ref(Field): | ||||||
|         uid = value.o.id |         uid = value.o.id | ||||||
|         if uid in refs: return |         if uid in refs: return | ||||||
|         # Execute self.beforeLink if present |         # Execute self.beforeLink if present | ||||||
|         if self.beforeLink: self.beforeLink(obj, value) |         if executeMethods and self.beforeLink: self.beforeLink(obj, value) | ||||||
|         # Where must we insert the object? |         # Where must we insert the object? | ||||||
|         if not self.insert: |         if not self.insert or not executeMethods: | ||||||
|             refs.append(uid) |             refs.append(uid) | ||||||
|         elif self.insert == 'start': |         elif self.insert == 'start': | ||||||
|             refs.insert(0, uid) |             refs.insert(0, uid) | ||||||
|  | @ -1032,21 +1042,27 @@ class Ref(Field): | ||||||
|                                                 tool.getObject(uid, appy=True))) |                                                 tool.getObject(uid, appy=True))) | ||||||
|             refs._p_changed = 1 |             refs._p_changed = 1 | ||||||
|         # Execute self.afterLink if present |         # Execute self.afterLink if present | ||||||
|         if self.afterLink: self.afterLink(obj, value) |         if executeMethods and self.afterLink: self.afterLink(obj, value) | ||||||
|         # Update the back reference |         # Update the back reference | ||||||
|         if not back: self.back.linkObject(value, obj, back=True) |         if not back: | ||||||
|  |             self.back.linkObject(value, obj, True, noSecurity, executeMethods) | ||||||
| 
 | 
 | ||||||
|     def unlinkObject(self, obj, value, back=False, noSecurity=True): |     def unlinkObject(self, obj, value, back=False, noSecurity=True, | ||||||
|  |                      executeMethods=True): | ||||||
|         '''This method unlinks p_value (which can be a list of objects) from |         '''This method unlinks p_value (which can be a list of objects) from | ||||||
|            p_obj through this Ref field.''' |            p_obj through this Ref field. For an explanation about parameters | ||||||
|  |            p_back, p_noSecurity and p_executeMethods, check m_linkObject's doc | ||||||
|  |            above.''' | ||||||
|         zobj = obj.o |         zobj = obj.o | ||||||
|         # Security check |         # Security check | ||||||
|         if not noSecurity: |         if not noSecurity: | ||||||
|             zobj.mayEdit(self.writePermission, raiseError=True) |             zobj.mayEdit(self.writePermission, raiseError=True) | ||||||
|  |             if executeMethods: | ||||||
|                 self.mayUnlinkElement(obj, value, raiseError=True) |                 self.mayUnlinkElement(obj, value, raiseError=True) | ||||||
|         # p_value can be a list of objects |         # p_value can be a list of objects | ||||||
|         if type(value) in sutils.sequenceTypes: |         if type(value) in sutils.sequenceTypes: | ||||||
|             for v in value: self.unlinkObject(obj, v, back=back) |             for v in value: | ||||||
|  |                 self.unlinkObject(obj, v, back, noSecurity, executeMethods) | ||||||
|             return |             return | ||||||
|         refs = getattr(zobj.aq_base, self.name, None) |         refs = getattr(zobj.aq_base, self.name, None) | ||||||
|         if not refs: return |         if not refs: return | ||||||
|  | @ -1055,9 +1071,10 @@ class Ref(Field): | ||||||
|         if uid in refs: |         if uid in refs: | ||||||
|             refs.remove(uid) |             refs.remove(uid) | ||||||
|             # Execute self.afterUnlink if present |             # Execute self.afterUnlink if present | ||||||
|             if self.afterUnlink: self.afterUnlink(obj, value) |             if executeMethods and self.afterUnlink: self.afterUnlink(obj, value) | ||||||
|             # Update the back reference |             # Update the back reference | ||||||
|             if not back: self.back.unlinkObject(value, obj, back=True) |             if not back: | ||||||
|  |                 self.back.unlinkObject(value,obj,True,noSecurity,executeMethods) | ||||||
| 
 | 
 | ||||||
|     def store(self, obj, value): |     def store(self, obj, value): | ||||||
|         '''Stores on p_obj, the p_value, which can be: |         '''Stores on p_obj, the p_value, which can be: | ||||||
|  |  | ||||||
|  | @ -1199,27 +1199,11 @@ class ToolMixin(BaseMixin): | ||||||
|            anymore. If p_normalized is True, special chars in the first and last |            anymore. If p_normalized is True, special chars in the first and last | ||||||
|            names are normalized.''' |            names are normalized.''' | ||||||
|         tool = self.appy() |         tool = self.appy() | ||||||
|         if not login: login = tool.user.login |         if not login: | ||||||
|         # Manage the special case of an anonymous user. |             user = tool.user | ||||||
|         if login == 'anon': |         else: | ||||||
|             name = self.translate('anonymous') |  | ||||||
|             if normalized: name = sutils.normalizeString(name) |  | ||||||
|             return name |  | ||||||
|         # Manage the case of any other user. |  | ||||||
|             user = tool.search1('User', noSecurity=True, login=login) |             user = tool.search1('User', noSecurity=True, login=login) | ||||||
|         if not user: return login |         return user.getTitle(normalized=normalized) | ||||||
|         firstName = user.firstName |  | ||||||
|         name = user.name |  | ||||||
|         res = '' |  | ||||||
|         if firstName: |  | ||||||
|             if normalized: firstName = sutils.normalizeString(firstName) |  | ||||||
|             res += firstName |  | ||||||
|         if name: |  | ||||||
|             if normalized: name = sutils.normalizeString(name) |  | ||||||
|             if res: res += ' ' + name |  | ||||||
|             else: res = name |  | ||||||
|         if not res: res = login |  | ||||||
|         return res |  | ||||||
| 
 | 
 | ||||||
|     def tempFile(self): |     def tempFile(self): | ||||||
|         '''A temp file has been created in a temp folder. This method returns |         '''A temp file has been created in a temp folder. This method returns | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ from appy.gen import WorkflowOwner | ||||||
| from appy.gen.layout import summaryPageLayouts | from appy.gen.layout import summaryPageLayouts | ||||||
| from appy.gen.wrappers import AbstractWrapper | from appy.gen.wrappers import AbstractWrapper | ||||||
| from appy.gen import utils as gutils | from appy.gen import utils as gutils | ||||||
|  | from appy.shared import utils as sutils | ||||||
| 
 | 
 | ||||||
| # ------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------ | ||||||
| class UserWrapper(AbstractWrapper): | class UserWrapper(AbstractWrapper): | ||||||
|  | @ -11,6 +12,19 @@ class UserWrapper(AbstractWrapper): | ||||||
|     specialUsers = ('system', 'anon', 'admin') |     specialUsers = ('system', 'anon', 'admin') | ||||||
|     layouts = summaryPageLayouts |     layouts = summaryPageLayouts | ||||||
| 
 | 
 | ||||||
|  |     def getTitle(self, normalized=False): | ||||||
|  |         '''Returns a nice name for this user, based on available information: | ||||||
|  |            name/first name or title or login. If p_normalized is True, special | ||||||
|  |            chars (like accents) are converted to ascii chars.''' | ||||||
|  |         # Manage the special case of an anonymous user. | ||||||
|  |         login = self.login | ||||||
|  |         if login == 'anon': | ||||||
|  |             res = self.translate('anonymous') | ||||||
|  |         else: | ||||||
|  |             res = self.title or login | ||||||
|  |         if not normalized: return res | ||||||
|  |         return sutils.normalizeString(name) | ||||||
|  | 
 | ||||||
|     def showLogin(self): |     def showLogin(self): | ||||||
|         '''When must we show the login field?''' |         '''When must we show the login field?''' | ||||||
|         if self.o.isTemporary(): return 'edit' |         if self.o.isTemporary(): return 'edit' | ||||||
|  |  | ||||||
|  | @ -818,15 +818,21 @@ class AbstractWrapper(object): | ||||||
|         '''Is this object a temporary object being created?''' |         '''Is this object a temporary object being created?''' | ||||||
|         return self.o.isTemporary() |         return self.o.isTemporary() | ||||||
| 
 | 
 | ||||||
|     def link(self, fieldName, obj): |     def link(self, fieldName, obj, noSecurity=True, executeMethods=True): | ||||||
|         '''This method links p_obj (which can be a list of objects) to this one |         '''This method links p_obj (which can be a list of objects) to this one | ||||||
|            through reference field p_fieldName.''' |            through reference field p_fieldName. For understanding the 2 last | ||||||
|         return self.getField(fieldName).linkObject(self, obj) |            params, check Ref's m_linkObject's doc.''' | ||||||
|  |         field = self.getField(fieldName)  | ||||||
|  |         return field.linkObject(self, obj, noSecurity=noSecurity, | ||||||
|  |                                 executeMethods=executeMethods) | ||||||
| 
 | 
 | ||||||
|     def unlink(self, fieldName, obj): |     def unlink(self, fieldName, obj, noSecurity=True, executeMethods=True): | ||||||
|         '''This method unlinks p_obj (which can be a list of objects) from this |         '''This method unlinks p_obj (which can be a list of objects) from this | ||||||
|            one through reference field p_fieldName.''' |            one through reference field p_fieldName. For understanding the 2 last | ||||||
|         return self.getField(fieldName).unlinkObject(self, obj) |            params, check Ref's m_unlinkObject's doc.''' | ||||||
|  |         field = self.getField(fieldName)  | ||||||
|  |         return field.unlinkObject(self, obj, noSecurity=noSecurity, | ||||||
|  |                                   executeMethods=executeMethods) | ||||||
| 
 | 
 | ||||||
|     def sort(self, fieldName, sortKey='title', reverse=False): |     def sort(self, fieldName, sortKey='title', reverse=False): | ||||||
|         '''Sorts referred elements linked to p_self via p_fieldName according |         '''Sorts referred elements linked to p_self via p_fieldName according | ||||||
|  | @ -843,7 +849,7 @@ class AbstractWrapper(object): | ||||||
|         refs._p_changed = 1 |         refs._p_changed = 1 | ||||||
| 
 | 
 | ||||||
|     def create(self, fieldNameOrClass, noSecurity=False, |     def create(self, fieldNameOrClass, noSecurity=False, | ||||||
|                raiseOnWrongAttribute=True, executeOnEdit=True, **kwargs): |                raiseOnWrongAttribute=True, executeMethods=True, **kwargs): | ||||||
|         '''This method creates a new instance of a gen-class. |         '''This method creates a new instance of a gen-class. | ||||||
|          |          | ||||||
|            If p_fieldNameOrClass is the name of a field, the created object will |            If p_fieldNameOrClass is the name of a field, the created object will | ||||||
|  | @ -859,16 +865,17 @@ class AbstractWrapper(object): | ||||||
|            correspond to a field on the created object, an AttributeError will |            correspond to a field on the created object, an AttributeError will | ||||||
|            be raised. Else, the value will be silently ignored. |            be raised. Else, the value will be silently ignored. | ||||||
| 
 | 
 | ||||||
|            If p_executeOnEdit is False, the gen-class's onEdit method, if |            If p_executeMethods is False, the gen-class's onEdit method, if | ||||||
|            present, will not be called. |            present, will not be called; any other defined method will not be | ||||||
|  |            called neither (ie, Ref.insert, Ref.beforeLink, Ref.afterLink...). | ||||||
|         ''' |         ''' | ||||||
|         isField = isinstance(fieldNameOrClass, basestring) |         isField = isinstance(fieldNameOrClass, basestring) | ||||||
|         tool = self.tool.o |         tool = self.tool.o | ||||||
|         # Determine the class of the object to create |         # Determine the class of the object to create | ||||||
|         if isField: |         if isField: | ||||||
|             fieldName = fieldNameOrClass |             fieldName = fieldNameOrClass | ||||||
|             appyType = self.o.getAppyType(fieldName) |             field = self.o.getAppyType(fieldName) | ||||||
|             portalType = tool.getPortalType(appyType.klass) |             portalType = tool.getPortalType(field.klass) | ||||||
|         else: |         else: | ||||||
|             klass = fieldNameOrClass |             klass = fieldNameOrClass | ||||||
|             portalType = tool.getPortalType(klass) |             portalType = tool.getPortalType(klass) | ||||||
|  | @ -885,7 +892,7 @@ class AbstractWrapper(object): | ||||||
|             folder = self.o.getCreateFolder() |             folder = self.o.getCreateFolder() | ||||||
|             if not noSecurity: |             if not noSecurity: | ||||||
|                 # Check that the user can edit this field. |                 # Check that the user can edit this field. | ||||||
|                 appyType.checkAdd(self.o) |                 field.checkAdd(self.o) | ||||||
|         # Create the object |         # Create the object | ||||||
|         zopeObj = createObject(folder, objId, portalType, tool.getAppName(), |         zopeObj = createObject(folder, objId, portalType, tool.getAppName(), | ||||||
|                                noSecurity=noSecurity) |                                noSecurity=noSecurity) | ||||||
|  | @ -898,14 +905,14 @@ class AbstractWrapper(object): | ||||||
|                 if raiseOnWrongAttribute: raise ae |                 if raiseOnWrongAttribute: raise ae | ||||||
|         if isField: |         if isField: | ||||||
|             # Link the object to this one |             # Link the object to this one | ||||||
|             appyType.linkObject(self, appyObj) |             field.linkObject(self, appyObj, executeMethods=executeMethods) | ||||||
|         # Call custom initialization |         # Call custom initialization | ||||||
|         if executeOnEdit and hasattr(appyObj, 'onEdit'): appyObj.onEdit(True) |         if executeMethods and hasattr(appyObj, 'onEdit'): appyObj.onEdit(True) | ||||||
|         zopeObj.reindex() |         zopeObj.reindex() | ||||||
|         return appyObj |         return appyObj | ||||||
| 
 | 
 | ||||||
|     def createFrom(self, fieldNameOrClass, other, noSecurity=False, |     def createFrom(self, fieldNameOrClass, other, noSecurity=False, | ||||||
|                    executeOnEdit=True): |                    executeMethods=True): | ||||||
|         '''Similar to m_create above, excepted that we will use another object |         '''Similar to m_create above, excepted that we will use another object | ||||||
|            (p_other) as base for filling in data for the object to create.''' |            (p_other) as base for filling in data for the object to create.''' | ||||||
|         # Get the field values to set from p_other and store it in a dict. |         # Get the field values to set from p_other and store it in a dict. | ||||||
|  | @ -919,7 +926,7 @@ class AbstractWrapper(object): | ||||||
|             params[field.name] = field.getCopyValue(other.o) |             params[field.name] = field.getCopyValue(other.o) | ||||||
|         return self.create(fieldNameOrClass, noSecurity=noSecurity, |         return self.create(fieldNameOrClass, noSecurity=noSecurity, | ||||||
|                            raiseOnWrongAttribute=False, |                            raiseOnWrongAttribute=False, | ||||||
|                            executeOnEdit=executeOnEdit, **params) |                            executeMethods=executeMethods, **params) | ||||||
| 
 | 
 | ||||||
|     def freeze(self, fieldName, template=None, format='pdf', noSecurity=True, |     def freeze(self, fieldName, template=None, format='pdf', noSecurity=True, | ||||||
|                freezeOdtOnError=True): |                freezeOdtOnError=True): | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Gaetan Delannay
						Gaetan Delannay