summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Viktorin <pviktori@redhat.com>2012-02-16 07:11:56 -0500
committerMartin Kosek <mkosek@redhat.com>2012-03-12 17:16:14 +0100
commit7cfc16ca58dfb22bc6e9cd519e6ecc7a10435fa1 (patch)
treea638850c0a1ba891376f49f5f3a2c8ced66ea696
parent1dc11a01d7e2a8e561b3a79aa97bf0939cd3fd25 (diff)
downloadfreeipa-7cfc16ca58dfb22bc6e9cd519e6ecc7a10435fa1.tar.gz
freeipa-7cfc16ca58dfb22bc6e9cd519e6ecc7a10435fa1.tar.xz
freeipa-7cfc16ca58dfb22bc6e9cd519e6ecc7a10435fa1.zip
Enforce that required attributes can't be set to None in CRUD Update
The `required` parameter attribute didn't distinguish between cases where the parameter is not given and all, and where the parameter is given but empty. The case of updating a required attribute couldn't be validated properly, because when it is given but empty, validators don't run. This patch introduces a new flag, 'nonempty', that specifies the parameter can be missing (if not required), but it can't be None. This flag gets added automatically to required parameters in CRUD Update.
-rw-r--r--ipalib/crud.py13
-rw-r--r--ipalib/frontend.py2
-rw-r--r--ipalib/parameters.py9
3 files changed, 17 insertions, 7 deletions
diff --git a/ipalib/crud.py b/ipalib/crud.py
index b9dfb025..12edbf58 100644
--- a/ipalib/crud.py
+++ b/ipalib/crud.py
@@ -186,20 +186,29 @@ class Update(PKQuery):
for option in super(Update, self).get_options():
yield option
for option in self.obj.params_minus_pk():
+ new_flags = option.flags
attribute = 'virtual_attribute' not in option.flags
+ if option.required:
+ # Required options turn into non-required, since not specifying
+ # them means that they are not changed.
+ # However, they cannot be empty (i.e. explicitly set to None).
+ new_flags = new_flags.union(['nonempty'])
if 'no_update' in option.flags:
continue
if 'ask_update' in option.flags:
yield option.clone(
attribute=attribute, query=False, required=False,
- autofill=False, alwaysask=True
+ autofill=False, alwaysask=True, flags=new_flags,
)
elif 'req_update' in option.flags:
yield option.clone(
attribute=attribute, required=True, alwaysask=False,
+ flags=new_flags,
)
else:
- yield option.clone(attribute=attribute, required=False, autofill=False)
+ yield option.clone(attribute=attribute, required=False,
+ autofill=False, flags=new_flags,
+ )
if not self.extra_options_first:
for option in super(Update, self).get_options():
yield option
diff --git a/ipalib/frontend.py b/ipalib/frontend.py
index 028e17e7..da25b4c1 100644
--- a/ipalib/frontend.py
+++ b/ipalib/frontend.py
@@ -651,7 +651,7 @@ class Command(HasParam):
"""
for param in self.params():
value = kw.get(param.name, None)
- param.validate(value, self.env.context)
+ param.validate(value, self.env.context, supplied=param.name in kw)
def verify_client_version(self, client_version):
"""
diff --git a/ipalib/parameters.py b/ipalib/parameters.py
index b1525b4d..48155daf 100644
--- a/ipalib/parameters.py
+++ b/ipalib/parameters.py
@@ -558,9 +558,9 @@ class Param(ReadOnly):
else:
value = self.convert(self.normalize(value))
if hasattr(self, 'env'):
- self.validate(value, self.env.context) #pylint: disable=E1101
+ self.validate(value, self.env.context, supplied=self.name in kw) #pylint: disable=E1101
else:
- self.validate(value)
+ self.validate(value, supplied=self.name in kw)
return value
def kw(self):
@@ -820,15 +820,16 @@ class Param(ReadOnly):
error=ugettext(self.type_error),
)
- def validate(self, value, context=None):
+ def validate(self, value, context=None, supplied=None):
"""
Check validity of ``value``.
:param value: A proposed value for this parameter.
:param context: The context we are running in.
+ :param supplied: True if this parameter was supplied explicitly.
"""
if value is None:
- if self.required:
+ if self.required or (supplied and 'nonempty' in self.flags):
if context == 'cli':
raise RequirementError(name=self.cli_name)
else: