Add support for the 'no_create', 'no_update', and 'no_search' Param flags
This commit is contained in:
1 parent
ea6dfc30fa
commit
c43b69e77c
2 files changed
+114
-6
No files matched your search
+109
-3
@@ -16,14 +16,114 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
"""
|
||||
Base classes for standard CRUD operations.
|
||||
|
||||
These base classes are for `Method` plugins that provide standard
|
||||
Create, Retrieve, Updated, and Delete operations (CRUD) for their corresponding
|
||||
`Object` plugin. In particuar, these base classes provide logic to
|
||||
automatically create the plugin args and options by inspecting the params on
|
||||
their corresponding `Object` plugin. This provides a single point of definition
|
||||
for LDAP attributes and enforces a simple, consistent API for CRUD operations.
|
||||
|
||||
For example, say we want CRUD operations on a hypothetical "user" entry. First
|
||||
we need an `Object` plugin:
|
||||
|
||||
>>> from ipalib import Object, Str
|
||||
>>> class user(Object):
|
||||
... takes_params = (
|
||||
... Str('login', primary_key=True),
|
||||
... Str('first'),
|
||||
... Str('last'),
|
||||
... Str('ipauniqueid', flags=['no_create', 'no_update']),
|
||||
... )
|
||||
...
|
||||
|
||||
Next we need `Create`, `Retrieve`, `Updated`, and `Delete` plugins, and
|
||||
optionally a `Search` plugin. For brevity, we'll just define `Create` and
|
||||
`Retrieve` plugins:
|
||||
|
||||
>>> from ipalib import crud
|
||||
>>> class user_add(crud.Create):
|
||||
... pass
|
||||
...
|
||||
>>> class user_show(crud.Retrieve):
|
||||
... pass
|
||||
...
|
||||
|
||||
Now we'll register the plugins and finalize the `plugable.API` instance:
|
||||
|
||||
>>> from ipalib import create_api
|
||||
>>> api = create_api()
|
||||
>>> api.register(user)
|
||||
>>> api.register(user_add)
|
||||
>>> api.register(user_show)
|
||||
>>> api.finalize()
|
||||
|
||||
First, notice that our ``user`` `Object` has the params we defined with the
|
||||
``takes_params`` tuple:
|
||||
|
||||
>>> list(api.Object.user.params)
|
||||
['login', 'first', 'last', 'ipauniqueid']
|
||||
>>> api.Object.user.params.login
|
||||
Str('login', primary_key=True)
|
||||
|
||||
Although we defined neither ``takes_args`` nor ``takes_options`` for our
|
||||
``user_add`` plugin, the `Create` base class automatically generated them for
|
||||
us:
|
||||
|
||||
>>> list(api.Command.user_add.args)
|
||||
['login']
|
||||
>>> list(api.Command.user_add.options)
|
||||
['first', 'last']
|
||||
|
||||
Notice that ``'ipauniqueid'`` isn't included in the options for our ``user_add``
|
||||
plugin. This is because of the ``'no_create'`` flag we used when defining the
|
||||
``ipauniqueid`` param. Often times there are LDAP attributes that are
|
||||
automatically created by the server and therefor should not be supplied as an
|
||||
option to the `Create` plugin. Often these same attributes shouldn't be
|
||||
update-able either, in which case you can also supply the ``'no_update'`` flag,
|
||||
as we did with our ``ipauniqueid`` param. Lastly, you can also use the ``'no_search'`` flag for attributes that shouldn't be search-able (because, for
|
||||
example, the attribute isn't indexed).
|
||||
|
||||
As with our ``user_add` plugin, we defined neither ``takes_args`` nor
|
||||
``takes_options`` for our ``user_show`` plugin; instead the `Retrieve` base
|
||||
class created them for us:
|
||||
|
||||
>>> list(api.Command.user_show.args)
|
||||
['login']
|
||||
>>> list(api.Command.user_show.options)
|
||||
[]
|
||||
|
||||
As you can see, `Retrieve` plugins take a single argument (the primary key) and
|
||||
no options. If needed, you can still specify options for your `Retrieve` plugin
|
||||
with a ``takes_options`` tuple.
|
||||
|
||||
Flags like ``'no_create'`` remove LDAP attributes from those that can be
|
||||
supplied as *input* to a `Method`, but they don't effect the attributes that can
|
||||
be returned as *output*. Regardless of what flags have been used, the output
|
||||
entry (or list of entries) can contain all the attributes defined on the
|
||||
`Object` plugin (in our case, the above ``user.params``).
|
||||
|
||||
For example, compare ``user.params`` with ``user_add.output_params`` and
|
||||
``user_show.output_params``:
|
||||
|
||||
>>> list(api.Object.user.params)
|
||||
['login', 'first', 'last', 'ipauniqueid']
|
||||
>>> list(api.Command.user_add.output_params)
|
||||
['login', 'first', 'last', 'ipauniqueid']
|
||||
>>> list(api.Command.user_show.output_params)
|
||||
['login', 'first', 'last', 'ipauniqueid']
|
||||
|
||||
Note that the above are all equal.
|
||||
"""
|
||||
|
||||
from frontend import Method, Object
|
||||
import backend, frontend, parameters, output
|
||||
|
||||
|
||||
class Create(frontend.Method):
|
||||
class Create(Method):
|
||||
"""
|
||||
Create a new entry.
|
||||
"""
|
||||
@@ -39,13 +139,15 @@ class Create(frontend.Method):
|
||||
for option in super(Create, self).get_options():
|
||||
yield option
|
||||
for option in self.obj.params_minus(self.args):
|
||||
if 'no_create' in option.flags:
|
||||
continue
|
||||
yield option.clone(attribute=True)
|
||||
if not self.extra_options_first:
|
||||
for option in super(Create, self).get_options():
|
||||
yield option
|
||||
|
||||
|
||||
class PKQuery(frontend.Method):
|
||||
class PKQuery(Method):
|
||||
"""
|
||||
Base class for `Retrieve`, `Update`, and `Delete`.
|
||||
"""
|
||||
@@ -75,6 +177,8 @@ class Update(PKQuery):
|
||||
for option in super(Update, self).get_options():
|
||||
yield option
|
||||
for option in self.obj.params_minus_pk():
|
||||
if 'no_update' in option.flags:
|
||||
continue
|
||||
yield option.clone(attribute=True, required=False, autofill=False)
|
||||
if not self.extra_options_first:
|
||||
for option in super(Update, self).get_options():
|
||||
@@ -89,7 +193,7 @@ class Delete(PKQuery):
|
||||
has_output = output.standard_delete
|
||||
|
||||
|
||||
class Search(frontend.Method):
|
||||
class Search(Method):
|
||||
"""
|
||||
Retrieve all entries that match a given search criteria.
|
||||
"""
|
||||
@@ -104,6 +208,8 @@ class Search(frontend.Method):
|
||||
for option in super(Search, self).get_options():
|
||||
yield option
|
||||
for option in self.obj.params_minus(self.args):
|
||||
if 'no_search' in option.flags:
|
||||
continue
|
||||
yield option.clone(
|
||||
attribute=True, query=True, required=False, autofill=False
|
||||
)
|
||||
|
||||
@@ -23,6 +23,7 @@ Test the `ipalib.crud` module.
|
||||
|
||||
from tests.util import read_only, raises, get_api, ClassChecker
|
||||
from ipalib import crud, frontend, plugable, config
|
||||
from ipalib.parameters import Str
|
||||
|
||||
|
||||
class CrudChecker(ClassChecker):
|
||||
@@ -38,9 +39,10 @@ class CrudChecker(ClassChecker):
|
||||
class user(frontend.Object):
|
||||
takes_params = (
|
||||
'givenname',
|
||||
'sn',
|
||||
frontend.Param('uid', primary_key=True),
|
||||
Str('sn', flags='no_update'),
|
||||
Str('uid', primary_key=True),
|
||||
'initials',
|
||||
Str('uidnumber', flags=['no_create', 'no_search'])
|
||||
)
|
||||
class user_verb(self.cls):
|
||||
takes_args = args
|
||||
@@ -102,7 +104,7 @@ class test_Update(CrudChecker):
|
||||
"""
|
||||
api = self.get_api()
|
||||
assert list(api.Method.user_verb.options) == \
|
||||
['givenname', 'sn', 'initials']
|
||||
['givenname', 'initials', 'uidnumber']
|
||||
for param in api.Method.user_verb.options():
|
||||
assert param.required is False
|
||||
|
||||
|
||||
Reference in new issue
Block a user