[gen] Ref field: added params 'beforeLink' and 'afterUnlink' allowing to hold methods that execute respectively before an item is linked via a Ref or after it has been unlinked; bugfix in mixin::getUrl.

This commit is contained in:
Gaetan Delannay 2014-06-25 15:42:34 +02:00
parent 8511bcd675
commit 268309045a
2 changed files with 40 additions and 19 deletions

View file

@ -472,13 +472,14 @@ class Ref(Field):
def __init__(self, klass=None, attribute=None, validator=None, def __init__(self, klass=None, attribute=None, validator=None,
multiplicity=(0,1), default=None, add=False, addConfirm=False, multiplicity=(0,1), default=None, add=False, addConfirm=False,
delete=None, noForm=False, link=True, unlink=None, insert=None, delete=None, noForm=False, link=True, unlink=None, insert=None,
back=None, show=True, page='main', group=None, layouts=None, beforeLink=None, afterUnlink=None, back=None, show=True,
showHeaders=False, shownInfo=(), select=None, maxPerPage=30, page='main', group=None, layouts=None, showHeaders=False,
move=0, indexed=False, searchable=False, shownInfo=(), select=None, maxPerPage=30, move=0,
specificReadPermission=False, specificWritePermission=False, indexed=False, searchable=False, specificReadPermission=False,
width=None, height=5, maxChars=None, colspan=1, master=None, specificWritePermission=False, width=None, height=5,
masterValue=None, focus=False, historized=False, mapping=None, maxChars=None, colspan=1, master=None, masterValue=None,
label=None, queryable=False, queryFields=None, queryNbCols=1, focus=False, historized=False, mapping=None, label=None,
queryable=False, queryFields=None, queryNbCols=1,
navigable=False, changeOrder=True, numbered=False, navigable=False, changeOrder=True, numbered=False,
checkboxes=True, checkboxesDefault=None, sdefault='', checkboxes=True, checkboxesDefault=None, sdefault='',
scolspan=1, swidth=None, sheight=None, sselect=None, scolspan=1, swidth=None, sheight=None, sselect=None,
@ -511,6 +512,10 @@ class Ref(Field):
self.link = link self.link = link
# May the user unlink existing objects? # May the user unlink existing objects?
self.unlink = unlink self.unlink = unlink
if unlink == None:
# By default, one may unlink objects via a Ref for which one can
# link objects.
self.unlink = bool(self.link)
# When an object is inserted through this Ref field, at what position is # When an object is inserted through this Ref field, at what position is
# it inserted? If "insert" is: # it inserted? If "insert" is:
# None, it will be inserted at the end; # None, it will be inserted at the end;
@ -529,10 +534,14 @@ class Ref(Field):
# object is inserted at some given place: tied objects are more # object is inserted at some given place: tied objects are more
# maintained in the order of their insertion. # maintained in the order of their insertion.
self.insert = insert self.insert = insert
if unlink == None: # Immediately before an object is going to be linked via this Ref field,
# By default, one may unlink objects via a Ref for which one can # method specified in "beforeLink" wil be executed if specified and will
# link objects. # take the object to link as single parameter.
self.unlink = bool(self.link) self.beforeLink = beforeLink
# Immediately after an object as been unlinked from this Ref field,
# method specified in "afterUnlink" will be executed if specified and
# will take the unlinked object as single parameter.
self.afterUnlink = afterUnlink
self.back = None self.back = None
if back: if back:
# It is a forward reference # It is a forward reference
@ -897,6 +906,8 @@ class Ref(Field):
# Insert p_value into it. # Insert p_value into it.
uid = value.o.id uid = value.o.id
if uid in refs: return if uid in refs: return
# Execute self.beforeLink if present
if 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:
refs.append(uid) refs.append(uid)
@ -945,6 +956,8 @@ class Ref(Field):
uid = value.o.id uid = value.o.id
if uid in refs: if uid in refs:
refs.remove(uid) refs.remove(uid)
# Execute self.afterUnlink if present
if 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, back=True)
@ -1160,17 +1173,18 @@ class Ref(Field):
action = rq['linkAction'] action = rq['linkAction']
tool = obj.getTool() tool = obj.getTool()
msg = None msg = None
appyObj = obj.appy()
if not action.endswith('_many'): if not action.endswith('_many'):
# "link" or "unlink" # "link" or "unlink"
tied = tool.getObject(rq['targetUid']) tied = tool.getObject(rq['targetUid'], appy=True)
exec 'self.%sObject(obj, tied, noSecurity=False)' % action exec 'self.%sObject(appyObj, tied, noSecurity=False)' % action
else: else:
# "link_many", "unlink_many", "delete_many". As a preamble, perform # "link_many", "unlink_many", "delete_many". As a preamble, perform
# a security check once, instead of doing it on every object-level # a security check once, instead of doing it on every object-level
# operation. # operation.
obj.mayEdit(self.writePermission, raiseError=True) obj.mayEdit(self.writePermission, raiseError=True)
# Get the (un-)checked objects from the request. # Get the (un-)checked objects from the request.
uids = rq['targetUid'].strip(',') or (); uids = rq['targetUid'].strip(',') or ()
if uids: uids = uids.split(',') if uids: uids = uids.split(',')
unchecked = rq['semantics'] == 'unchecked' unchecked = rq['semantics'] == 'unchecked'
if action == 'link_many': if action == 'link_many':
@ -1192,7 +1206,8 @@ class Ref(Field):
# Keep only objects being in uids. # Keep only objects being in uids.
if uid not in uids: continue if uid not in uids: continue
# Collect this object # Collect this object
target = not isObj and tool.getObject(value) or value.o target = not isObj and tool.getObject(value, appy=True) or \
value
targets.append(target) targets.append(target)
if not targets: if not targets:
msg = obj.translate('action_null') msg = obj.translate('action_null')
@ -1204,16 +1219,17 @@ class Ref(Field):
for target in targets: for target in targets:
if mustDelete: if mustDelete:
# Delete # Delete
if target.mayDelete(): target.delete() if target.o.mayDelete(): target.o.delete()
else: failed += 1 else: failed += 1
else: else:
# Link or unlink # Link or unlink
exec 'self.%sObject(obj, target)' % action.split('_')[0] exec 'self.%sObject(appyObj, target)' % \
action.split('_')[0]
if failed: if failed:
msg = obj.translate('action_partial', mapping={'nb':failed}) msg = obj.translate('action_partial', mapping={'nb':failed})
urlBack = obj.getUrl(rq['HTTP_REFERER']) urlBack = obj.getUrl(rq['HTTP_REFERER'])
if not msg: msg = obj.translate('action_done') if not msg: msg = obj.translate('action_done')
obj.say(msg) appyObj.say(msg)
tool.goto(urlBack) tool.goto(urlBack)
def autoref(klass, field): def autoref(klass, field):

View file

@ -1353,6 +1353,9 @@ class BaseMixin:
# Define base URL if omitted # Define base URL if omitted
if not base: if not base:
base = self.absolute_url() + suffix base = self.absolute_url() + suffix
existingParams = ''
else:
existingParams = urllib.splitquery(base)[1]
# If a raw URL is asked, remove any param and suffix. # If a raw URL is asked, remove any param and suffix.
if mode == 'raw': if mode == 'raw':
if '?' in base: base = base[:base.index('?')] if '?' in base: base = base[:base.index('?')]
@ -1366,7 +1369,6 @@ class BaseMixin:
if not kwargs: kwargs = self.getUrlDefaults if not kwargs: kwargs = self.getUrlDefaults
if 'page' not in kwargs: kwargs['page'] = True if 'page' not in kwargs: kwargs['page'] = True
if 'nav' not in kwargs: kwargs['nav'] = True if 'nav' not in kwargs: kwargs['nav'] = True
kwargs['popup'] = inPopup and '1' or '0'
# Create URL parameters from kwargs # Create URL parameters from kwargs
params = [] params = []
for name, value in kwargs.iteritems(): for name, value in kwargs.iteritems():
@ -1374,6 +1376,9 @@ class BaseMixin:
params.append('%s=%s' % (name, value)) params.append('%s=%s' % (name, value))
elif self.REQUEST.get(name, ''): elif self.REQUEST.get(name, ''):
params.append('%s=%s' % (name, self.REQUEST[name])) params.append('%s=%s' % (name, self.REQUEST[name]))
# Manage inPopup
if inPopup and ('popup=' not in existingParams):
params.append('popup=1')
if params: if params:
params = '&'.join(params) params = '&'.join(params)
if base.find('?') != -1: params = '&' + params if base.find('?') != -1: params = '&' + params