Hello,

the 'user-stage' command replaces 'stageuser-add --from-delete' command.
https://fedorahosted.org/freeipa/ticket/5041

Thierry can you check If I don't break everything, it works for me, but the one never knows.

Honza can you please check the framework side? I use self.api.Object.stageuser.add.* in user command, I'm not sure if this is right way, but it works.

Patch attached. I created it in hurry, I'm expecting NACK :D


Just question at the end: should I implement way Active user -> stageuser? IMHO it would be implemented internally by calling 'user-del --preserve' inside 'user-stage'.



>From 74f0f8aa22f0c62284e5254d717baf9a067c6f17 Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Mon, 17 Aug 2015 20:11:21 +0200
Subject: [PATCH] Add user-stage command

This patch replaces 'stageuser-add --from-delete' with new command
user-stage.

Original way always required  to specify first and last name, and
overall combination of options was hard to manage. The new command
requires only login of deleted user (user-del --preserve).

https://fedorahosted.org/freeipa/ticket/5041
---
 API.txt                     |  9 +++++-
 VERSION                     |  4 +--
 ipalib/plugins/stageuser.py | 67 ++++++++++++++++-----------------------------
 ipalib/plugins/user.py      | 43 +++++++++++++++++++++++++++++
 4 files changed, 76 insertions(+), 47 deletions(-)

diff --git a/API.txt b/API.txt
index 04f2f894f7667239d94a2a7278d0cc80704afeb5..ea3fff5c8ee587fb12585f2326fbccc108e760e3 100644
--- a/API.txt
+++ b/API.txt
@@ -4211,7 +4211,7 @@ option: Str('displayname', attribute=True, autofill=True, cli_name='displayname'
 option: Str('employeenumber', attribute=True, cli_name='employeenumber', multivalue=False, required=False)
 option: Str('employeetype', attribute=True, cli_name='employeetype', multivalue=False, required=False)
 option: Str('facsimiletelephonenumber', attribute=True, cli_name='fax', multivalue=True, required=False)
-option: Flag('from_delete?', autofill=True, cli_name='from_delete', default=False)
+option: DeprecatedParam('from_delete?', cli_name='from_delete', default=False)
 option: Str('gecos', attribute=True, autofill=True, cli_name='gecos', multivalue=False, required=False)
 option: Int('gidnumber', attribute=True, cli_name='gidnumber', minvalue=1, multivalue=False, required=False)
 option: Str('givenname', attribute=True, cli_name='first', multivalue=False, required=True)
@@ -5371,6 +5371,13 @@ option: Str('version?', exclude='webui')
 output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: PrimaryKey('value', None, None)
+command: user_stage
+args: 1,1,3
+arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=True)
+option: Str('version?', exclude='webui')
+output: Output('result', <type 'bool'>, None)
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
 command: user_status
 args: 1,4,4
 arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=True)
diff --git a/VERSION b/VERSION
index a3d586df47ab6a6136bd38c0151fe43876bf5ab3..b62a7c9c1cb7bfa83f28c871ca22f5334958e0bf 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=148
-# Last change: ftweedal - add --out option to user-show
+IPA_API_VERSION_MINOR=149
+# Last change: mbasti - add 'user-stage' command
diff --git a/ipalib/plugins/stageuser.py b/ipalib/plugins/stageuser.py
index 29739d5d434b1f384d2f9a0c15cddd2bf887e7b7..700557f2700fca06a20711b6fc48ee7ff5cff07a 100644
--- a/ipalib/plugins/stageuser.py
+++ b/ipalib/plugins/stageuser.py
@@ -23,7 +23,8 @@ import posixpath
 import os
 from copy import deepcopy
 from ipalib import api, errors
-from ipalib import Flag, Int, Password, Str, Bool, StrEnum, DateTime
+from ipalib import (Flag, Int, Password, Str, Bool, StrEnum, DateTime,
+                    DeprecatedParam)
 from ipalib.plugable import Registry
 from ipalib.plugins.baseldap import LDAPCreate, LDAPQuery, LDAPSearch, DN, entry_to_dict, pkey_to_value
 from ipalib.plugins import baseldap
@@ -260,23 +261,16 @@ class stageuser_add(baseuser_add):
     has_output_params = baseuser_add.has_output_params + stageuser_output_params
 
     takes_options = LDAPCreate.takes_options + (
-        Flag('from_delete?',
+        DeprecatedParam('from_delete?',
             doc=_('Create Stage user in from a delete user'),
             cli_name='from_delete',
             default=False,
         ),
     )
 
-    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
-        assert isinstance(dn, DN)
-
-        if not options.get('from_delete'):
-            # then givenname and sn are required attributes
-            if 'givenname' not in entry_attrs:
-                raise errors.RequirementError(name='givenname', error=_('givenname is required'))
-
-            if 'sn' not in entry_attrs:
-                raise errors.RequirementError(name='sn', error=_('sn is required'))
+    def set_default_values_pre_callback(self, ldap, dn, entry_attrs,
+                                        attrs_list, *keys, **options):
+        # this method is used for "user-stage" command too
 
         # we don't want an user private group to be created for this user
         # add NO_UPG_MAGIC description attribute to let the DS plugin know
@@ -326,13 +320,6 @@ class stageuser_add(baseuser_add):
         # Kerberos principal
         entry_attrs.setdefault('krbprincipalname', '%s@%s' % (entry_attrs['uid'], api.env.realm))
 
-
-        # If requested, generate a userpassword
-        if 'userpassword' not in entry_attrs and options.get('random'):
-            entry_attrs['userpassword'] = ipa_generate_password(baseuser_pwdchars)
-            # save the password so it can be displayed in post_callback
-            setattr(context, 'randompassword', entry_attrs['userpassword'])
-
         # Check the email or create it
         if 'mail' in entry_attrs:
             entry_attrs['mail'] = self.obj.normalize_and_validate_email(entry_attrs['mail'], config)
@@ -364,38 +351,30 @@ class stageuser_add(baseuser_add):
 
                 answer = self.api.Object['radiusproxy'].get_dn_if_exists(cl)
                 entry_attrs['ipatokenradiusconfiglink'] = answer
-
         return dn
 
-    def execute(self, *keys, **options):
-        '''
-        A stage entry may be taken from the Delete container.
-        In that case we rather do 'MODRDN' than 'ADD'.
-        '''
-        if options.get('from_delete'):
-            ldap = self.obj.backend
+    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+        assert isinstance(dn, DN)
+
+        if 'givenname' not in entry_attrs:
+            raise errors.RequirementError(name='givenname',
+                                          error=_('givenname is required'))
 
-            staging_dn = self.obj.get_dn(*keys, **options)
-            delete_dn = DN(staging_dn[0], self.obj.delete_container_dn, api.env.basedn)
-            new_dn = DN(staging_dn[0], self.obj.stage_container_dn, api.env.basedn)
-            # Check that this value is a Active user
-            try:
-                entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(delete_dn, ['dn'])
-            except errors.NotFound:
-                self.obj.handle_not_found(*keys)
+        if 'sn' not in entry_attrs:
+            raise errors.RequirementError(name='sn', error=_('sn is required'))
 
-            self._exc_wrapper(keys, options, ldap.move_entry)(
-                delete_dn, new_dn)
-            entry_attrs = entry_to_dict(entry_attrs, **options)
-            entry_attrs['dn'] = new_dn
+        # If requested, generate a userpassword
+        if 'userpassword' not in entry_attrs and options.get('random'):
+            entry_attrs['userpassword'] = ipa_generate_password(baseuser_pwdchars)
+            # save the password so it can be displayed in post_callback
+            setattr(context, 'randompassword', entry_attrs['userpassword'])
 
-            if self.obj.primary_key and keys[-1] is not None:
-                return dict(result=entry_attrs, value=keys[-1])
-            return dict(result=entry_attrs, value=u'')
-        else:
-            return super(stageuser_add, self).execute(*keys, **options)
+        dn = self.set_default_values_pre_callback(self, ldap, dn, entry_attrs,
+                                                  attrs_list, *keys, **options)
+        return dn
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+        # this method is used for "user-stage" command too
         assert isinstance(dn, DN)
         config = ldap.get_ipa_config()
 
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index 4de33b9ff80799f5e499e05ef38cfc444e69a316..ae7fe1ac58f3b6fced64a50d676c79c560dcef8d 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -861,6 +861,49 @@ class user_undel(LDAPQuery):
             value=pkey_to_value(keys[0], options),
         )
 
+
+@register()
+class user_stage(LDAPQuery):
+    __doc__ = _('Move deleted user into staged area')
+
+    has_output = output.standard_value
+    msg_summary = _('Staged user account "%(value)s"')
+
+    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
+                     **options):
+        return self.api.Object.stageuser.add.set_default_values_pre_callback(
+            ldap, dn, entry_attrs, attrs_list, *keys, **options)
+
+    def execute(self, *keys, **options):
+        ldap = self.obj.backend
+
+        staging_dn = self.obj.get_dn(*keys, **options)
+        delete_dn = DN(staging_dn[0], self.obj.delete_container_dn,
+                       api.env.basedn)
+        new_dn = DN(staging_dn[0], self.obj.stage_container_dn, api.env.basedn)
+        # Check that this value is a Active user
+        try:
+            entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(
+                delete_dn, ['dn'])
+        except errors.NotFound:
+            self.obj.handle_not_found(*keys)
+
+        self._exc_wrapper(keys, options, ldap.move_entry)(
+            delete_dn, new_dn)
+        entry_attrs = entry_to_dict(entry_attrs, **options)
+        entry_attrs['dn'] = new_dn
+
+        return dict(
+            result=True,
+            value=pkey_to_value(keys[0], options),
+        )
+
+    def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+        return self.api.Object.stageuser.add.post_callback(ldap, dn,
+                                                           entry_attrs,
+                                                           *keys, **options)
+
+
 @register()
 class user_disable(LDAPQuery):
     __doc__ = _('Disable a user account.')
-- 
2.4.3

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to