[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
|
@ -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…
Reference in a new issue