[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:
|
||||
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
|
||||
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
|
||||
# Security check
|
||||
if not noSecurity: zobj.mayEdit(self.writePermission, raiseError=True)
|
||||
# p_value can be a list of objects
|
||||
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
|
||||
# Gets the list of referred objects (=list of uids), or create it.
|
||||
refs = getattr(zobj.aq_base, self.name, None)
|
||||
|
@ -1001,9 +1011,9 @@ class Ref(Field):
|
|||
uid = value.o.id
|
||||
if uid in refs: return
|
||||
# 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?
|
||||
if not self.insert:
|
||||
if not self.insert or not executeMethods:
|
||||
refs.append(uid)
|
||||
elif self.insert == 'start':
|
||||
refs.insert(0, uid)
|
||||
|
@ -1032,21 +1042,27 @@ class Ref(Field):
|
|||
tool.getObject(uid, appy=True)))
|
||||
refs._p_changed = 1
|
||||
# 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
|
||||
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
|
||||
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
|
||||
# Security check
|
||||
if not noSecurity:
|
||||
zobj.mayEdit(self.writePermission, raiseError=True)
|
||||
self.mayUnlinkElement(obj, value, raiseError=True)
|
||||
if executeMethods:
|
||||
self.mayUnlinkElement(obj, value, raiseError=True)
|
||||
# p_value can be a list of objects
|
||||
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
|
||||
refs = getattr(zobj.aq_base, self.name, None)
|
||||
if not refs: return
|
||||
|
@ -1055,9 +1071,10 @@ class Ref(Field):
|
|||
if uid in refs:
|
||||
refs.remove(uid)
|
||||
# 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
|
||||
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):
|
||||
'''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
|
||||
names are normalized.'''
|
||||
tool = self.appy()
|
||||
if not login: login = tool.user.login
|
||||
# Manage the special case of an anonymous user.
|
||||
if login == 'anon':
|
||||
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)
|
||||
if not user: return login
|
||||
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
|
||||
if not login:
|
||||
user = tool.user
|
||||
else:
|
||||
user = tool.search1('User', noSecurity=True, login=login)
|
||||
return user.getTitle(normalized=normalized)
|
||||
|
||||
def tempFile(self):
|
||||
'''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.wrappers import AbstractWrapper
|
||||
from appy.gen import utils as gutils
|
||||
from appy.shared import utils as sutils
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
class UserWrapper(AbstractWrapper):
|
||||
|
@ -11,6 +12,19 @@ class UserWrapper(AbstractWrapper):
|
|||
specialUsers = ('system', 'anon', 'admin')
|
||||
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):
|
||||
'''When must we show the login field?'''
|
||||
if self.o.isTemporary(): return 'edit'
|
||||
|
|
|
@ -818,15 +818,21 @@ class AbstractWrapper(object):
|
|||
'''Is this object a temporary object being created?'''
|
||||
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
|
||||
through reference field p_fieldName.'''
|
||||
return self.getField(fieldName).linkObject(self, obj)
|
||||
through reference field p_fieldName. For understanding the 2 last
|
||||
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
|
||||
one through reference field p_fieldName.'''
|
||||
return self.getField(fieldName).unlinkObject(self, obj)
|
||||
one through reference field p_fieldName. For understanding the 2 last
|
||||
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):
|
||||
'''Sorts referred elements linked to p_self via p_fieldName according
|
||||
|
@ -843,7 +849,7 @@ class AbstractWrapper(object):
|
|||
refs._p_changed = 1
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
be raised. Else, the value will be silently ignored.
|
||||
|
||||
If p_executeOnEdit is False, the gen-class's onEdit method, if
|
||||
present, will not be called.
|
||||
If p_executeMethods is False, the gen-class's onEdit method, if
|
||||
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)
|
||||
tool = self.tool.o
|
||||
# Determine the class of the object to create
|
||||
if isField:
|
||||
fieldName = fieldNameOrClass
|
||||
appyType = self.o.getAppyType(fieldName)
|
||||
portalType = tool.getPortalType(appyType.klass)
|
||||
field = self.o.getAppyType(fieldName)
|
||||
portalType = tool.getPortalType(field.klass)
|
||||
else:
|
||||
klass = fieldNameOrClass
|
||||
portalType = tool.getPortalType(klass)
|
||||
|
@ -885,7 +892,7 @@ class AbstractWrapper(object):
|
|||
folder = self.o.getCreateFolder()
|
||||
if not noSecurity:
|
||||
# Check that the user can edit this field.
|
||||
appyType.checkAdd(self.o)
|
||||
field.checkAdd(self.o)
|
||||
# Create the object
|
||||
zopeObj = createObject(folder, objId, portalType, tool.getAppName(),
|
||||
noSecurity=noSecurity)
|
||||
|
@ -898,14 +905,14 @@ class AbstractWrapper(object):
|
|||
if raiseOnWrongAttribute: raise ae
|
||||
if isField:
|
||||
# Link the object to this one
|
||||
appyType.linkObject(self, appyObj)
|
||||
field.linkObject(self, appyObj, executeMethods=executeMethods)
|
||||
# Call custom initialization
|
||||
if executeOnEdit and hasattr(appyObj, 'onEdit'): appyObj.onEdit(True)
|
||||
if executeMethods and hasattr(appyObj, 'onEdit'): appyObj.onEdit(True)
|
||||
zopeObj.reindex()
|
||||
return appyObj
|
||||
|
||||
def createFrom(self, fieldNameOrClass, other, noSecurity=False,
|
||||
executeOnEdit=True):
|
||||
executeMethods=True):
|
||||
'''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.'''
|
||||
# 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)
|
||||
return self.create(fieldNameOrClass, noSecurity=noSecurity,
|
||||
raiseOnWrongAttribute=False,
|
||||
executeOnEdit=executeOnEdit, **params)
|
||||
executeMethods=executeMethods, **params)
|
||||
|
||||
def freeze(self, fieldName, template=None, format='pdf', noSecurity=True,
|
||||
freezeOdtOnError=True):
|
||||
|
|
Loading…
Reference in a new issue