0

Anybody else seeing this? There appears to have been some changes to the Google provisioning api for multi-domains. I have long running code that could restore a suspended user that has stopped working. I use Python and 2.0.17 of the Python GData libraries and the UpdateUser method to do this. I have also noted that RetrieveUser in the same library is no longer returning the first and last names of suspended users. I have filed an issue at Google apps-api-issues, please star if you are seeing this.

http://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=3281

Kara
  • 6,115
  • 16
  • 50
  • 57
CTy
  • 169
  • 3
  • I've confirmed the firstname, lastname issue with GAM but GAM has no issues restoring a user account that's been suspended. It sounds like something is wrong with the XML being sent by the library, GAM uses the multidomain API call but it has it's own multidomain library. Can you share a code sample that has the unsuspend issue? – Jay Lee Nov 22 '12 at 13:16

3 Answers3

1

This is a simple example that will walk through the problem. Note that user_entry object returned from a RetrieveUser() on a suspended user will not have a property value for either first name or last name. The modified user_entry object is passed to UpdateUser() which does not allow the missing values for first and last names.

#!/usr/bin/python
import sys
import gdata.apps.multidomain.client

if len(sys.argv) < 4:
  print "\nUsage:"
  print sys.argv[0], "admin_email admin_password user_email\n"
  sys.exit(0)

admin = sys.argv[1]
password = sys.argv[2]
email = sys.argv[3]
domain = ""
if '@' in admin:
  admin_name,domain = admin.split('@', 1)
else:
  print "Specify full email address of administrator.\n"
  print "\nUsage:"
  print sys.argv[0], "admin_email admin_password user_email\n"
  sys.exit(0)
if '@' not in email:
  print "Specify full email address of user.\n"
  print "\nUsage:"
  print sys.argv[0], "admin_email admin_password user_email\n"
  sys.exit(0)

md_client = gdata.apps.multidomain.client.MultiDomainProvisioningClient(
  domain=domain)
md_client.ClientLogin(email=admin, password=password, source='MDPROVISIONING')
print "Retrieve user: %s\n" %(email)
user_entry = md_client.RetrieveUser(email)
print user_entry
print ('\nRetrieve results: email: %s, suspended: %s,'
  ' first name: %s, last name: %s\n' 
  %(user_entry.email,user_entry.suspended,
    user_entry.first_name,user_entry.last_name))
print "Update user (suspend): %s\n" %(email)
user_entry.suspended = 'true'
updated_user_entry = md_client.UpdateUser(email, user_entry)
print updated_user_entry
print ('\nSuspend results: email: %s, suspended: %s,'
  ' first name: %s, last name: %s\n' 
  %(updated_user_entry.email,updated_user_entry.suspended,
    updated_user_entry.first_name,updated_user_entry.last_name))
print "Retrieve user: %s\n" %(email)
user_entry = md_client.RetrieveUser(email)
print user_entry
print ('\nRetrieve results: email: %s, suspended: %s,'
  ' first name: %s, last name: %s\n' 
  %(user_entry.email,user_entry.suspended,
    user_entry.first_name,user_entry.last_name))
print "Update user (restore): %s\n" %(email)
user_entry.suspended = 'false'
updated_user_entry = md_client.UpdateUser(email, user_entry)
print updated_user_entry
print ('\nRestore results: email: %s, suspended: %s,'
  ' first name: %s, last name: %s\n' 
  %(updated_user_entry.email,updated_user_entry.suspended,
    updated_user_entry.first_name,updated_user_entry.last_name))
Just
  • 21
  • 3
1

Thanks user1803418, that explains why restoring a user works with GAM and not your code. The lack of firstName and lastName in the RetrieveUser API call is definitely an issue on Google's end that they'll need to fix. However, I'd describe the unsuspend issue as a client library deficiency that's excaberated by the firstName/lastName issue.

The API requires only attributes that are being updated be submitted in the update user API call. There's no need to specify the user's firstName, lastName and other object details. This means retrieving the user in order to perform the update simply makes the update process take longer, only one API call is really necessary.

GAM uses it's own implementation of the multidomain API calls which I wrote before the multidomain/client.py was released. GAM's implementation does not require that all user attributes be set in order to perform the update. You can see this by looking at: http://code.google.com/p/google-apps-manager/source/browse/trunk/gdata/apps/multidomain/service.py#69

only the attributes that are set when calling UpdateUser() are sent to Google. You can see this for yourself by installing GAM and creating a file named debug.gam before unsuspending the user with the GAM command:

gam update user suspended off

the XML request to Google will be minimal, showing only a few fields including the suspended status of the user. firstName and lastName will not be included in the request.

So I think you have 3 options here:

1) wait for a fix from Google for the firstName/lastName issue. This should resolve the unsuspend issue also.

2) rewrite the multidomain/client.py UpdateUser() function so that it does not require all user attributes to be set in order to perform the update.

3) switch your code to use GAM's custom multidomain/service.py library since it supports updating only provided attributes for a user.

Jay Lee
  • 13,415
  • 3
  • 28
  • 59
  • Thanks for checking this. I guess what I'll do for now is modify UpdateUser in the multdomain client. – CTy Nov 26 '12 at 17:35
0

I hope that Google fixes the missing names soon. Modifying UpdateUser in the multidomain client (gdata.apps.multidomain.client) seems to keep things going:

def update_user(self, email, user_entry, **kwargs):

    user_entry = gdata.apps.multidomain.data.UserEntry(
        email=email,first_name=user_entry.first_name,
        last_name=user_entry.last_name,password=user_entry.password,
        change_password=user_entry.change_password_at_next_login,
        suspended=user_entry.suspended, is_admin=user_entry.is_admin,
        ip_whitelisted=user_entry.ip_whitelisted, quota=user_entry.quota)

    return self.update(user_entry,
                   uri=self.MakeMultidomainUserProvisioningUri(email),
                   **kwargs)
CTy
  • 169
  • 3