diff --git a/gam.py b/gam.py index 19683a51..51cc8bba 100755 --- a/gam.py +++ b/gam.py @@ -119,7 +119,7 @@ class _DeHTMLParser(HTMLParser): def dehtml(text): try: parser = _DeHTMLParser() - parser.feed(text) + parser.feed(text.encode('utf-8')) parser.close() return parser.text() except: @@ -184,7 +184,7 @@ def doGAMCheckForUpdates(): f.write(str(now_time)) f.close() return - a = urllib2.urlopen(u'https://gam-update.appspot.com/latest-version-announcement.txt?v=%s') + a = urllib2.urlopen(u'https://gam-update.appspot.com/latest-version-announcement.txt?v=%s' % __version__) announcement = a.read() sys.stderr.write(announcement) try: @@ -862,9 +862,11 @@ def showReport(): for app in auth_apps: # put apps at bottom cust_attributes.append(app) output_csv(csv_list=cust_attributes, titles=titles, list_type=u'Customer Report - %s' % try_date, todrive=to_drive) - elif report in [u'doc', u'docs', u'login', u'logins', u'admin', u'drive', u'token', u'tokens']: - if report == u'doc': - report = u'docs' + elif report in [u'doc', u'docs', u'calendar', u'calendars', u'login', u'logins', u'admin', u'drive', u'token', u'tokens']: + if report in [u'doc', u'docs']: + report = u'drive' + elif report in [u'calendars']: + report = u'calendar' elif report == u'logins': report = u'login' elif report == u'tokens': @@ -1413,7 +1415,6 @@ def doPrintPrintJobs(): elif sys.argv[i].lower() in [u'owner', u'user']: owner = sys.argv[i+1] i += 2 - sys.exit(3) else: print u'ERROR: %s is not a valid argument to "gam print printjobs"' % sys.argv[i] sys.exit(3) @@ -1528,7 +1529,7 @@ def changeCalendarAttendees(users): #print ' skipping cancelled event' continue try: - event_summary = str(event[u'summary']) + event_summary = convertUTF8(event[u'summary']) except (KeyError, UnicodeEncodeError, UnicodeDecodeError): event_summary = event[u'id'] try: @@ -2283,7 +2284,7 @@ def doPhoto(users): elif user.find('@') == -1: user = u'%s@%s' % (user, domain) filename = sys.argv[5].replace(u'#user#', user) - filename = sys.argv[5].replace(u'#email#', user) + filename = filename.replace(u'#email#', user) filename = filename.replace(u'#username#', user[:user.find(u'@')]) print u"Updating photo for %s with %s (%s of %s)" % (user, filename, i, count) i += 1 @@ -2354,15 +2355,15 @@ def showCalendars(users): feed = callGAPI(service=cal.calendarList(), function=u'list') for calendar in feed[u'items']: print u' Name: %s' % calendar['id'] - print u' Summary: %s' % calendar['summary'] + print convertUTF8(u' Summary: %s' % calendar['summary']) try: - print u' Description: %s' % calendar['description'] + print convertUTF8(u' Description: %s' % calendar['description']) except KeyError: print u' Description: ' print u' Access Level: %s' % calendar['accessRole'] print u' Timezone: %s' % calendar['timeZone'] try: - print u' Location: %s' % calendar['location'] + print convertUTF8(u' Location: %s' % calendar['location']) except KeyError: pass try: @@ -2455,9 +2456,10 @@ def doDriveActivity(users): page_message = u'Retrieved %%%%total_items%%%% activities for %s' % user feed = callGAPIpages(service=activity.activities(), function=u'list', items=u'activities', page_message=page_message, source=u'drive.google.com', userId=u'me', - drive_ancestorId=drive_ancestorId, groupingStrategy=u'none', pageSize=500) + drive_ancestorId=drive_ancestorId, groupingStrategy=u'none', + drive_fileId=drive_fileId, pageSize=500) for item in feed: - activity_attributes.append(flatten_json(item)[u'combinedEvent']) + activity_attributes.append(flatten_json(item[u'combinedEvent'])) for an_item in activity_attributes[-1].keys(): if an_item not in activity_attributes[0]: activity_attributes[0][an_item] = an_item @@ -2734,7 +2736,7 @@ def printDriveFolderContents(feed, folderId, indent): for file in feed: for parent in file[u'parents']: if folderId == parent[u'id']: - print u'%s%s' % (' ' * indent, file[u'title']) + print ' ' * indent, convertUTF8(file[u'title']) if file[u'mimeType'] == u'application/vnd.google-apps.folder': printDriveFolderContents(feed, file[u'id'], indent+1) @@ -2767,11 +2769,11 @@ def deleteEmptyDriveFolders(users): for folder in feed: children = callGAPI(service=drive.children(), function=u'list', folderId=folder[u'id'], maxResults=1, fields=u'items(id)') if not u'items' in children or len(children[u'items']) == 0: - print u' deleting empty folder %s...' % folder[u'title'] + print convertUTF8(u' deleting empty folder %s...' % folder[u'title']) callGAPI(service=drive.files(), function=u'delete', fileId=folder[u'id']) deleted_empty = True else: - print u' not deleting folder %s because it contains at least 1 item (%s)' % (folder[u'title'], children[u'items'][0][u'id']) + print convertUTF8(u' not deleting folder %s because it contains at least 1 item (%s)' % (folder[u'title'], children[u'items'][0][u'id'])) def doUpdateDriveFile(users): convert = ocr = ocrLanguage = parent_query = local_filepath = media_body = fileIds = drivefilename = None @@ -3761,7 +3763,7 @@ def showLabels(users): for label in labels[u'labels']: if label[u'type'] == u'system' and not show_system: continue - print label[u'name'] + print convertUTF8(label[u'name']) for a_key in label.keys(): if a_key == u'name': continue @@ -4240,6 +4242,8 @@ def doCreateOrUpdateUserSchema(): def doPrintUserSchemas(): cd = buildGAPIObject(u'directory') schemas = callGAPI(service=cd.schemas(), function=u'list', customerId=customerId) + if not schemas or u'schemas' not in schemas: + return for schema in schemas[u'schemas']: print u'Schema: %s' % schema[u'schemaName'] for a_key in schema.keys(): @@ -4618,7 +4622,6 @@ def doCreateGroup(): body[u'email'] = u'%s@%s' % (body[u'email'], domain) got_name = False i = 4 - true_false = [u'true', u'false'] gs_body = dict() while i < len(sys.argv): if sys.argv[i].lower() == u'name': @@ -5229,7 +5232,7 @@ def doUpdateGroup(): use_cd_api = True cd_body[u'adminCreated'] = sys.argv[i+1].lower() if cd_body[u'adminCreated'] not in true_false: - print u'Error: Value for admincreated must be true or false. Got %s' % admin_created + print u'Error: Value for admincreated must be true or false. Got %s' % cd_body[u'adminCreated'] sys.exit(9) i += 2 else: @@ -5524,7 +5527,7 @@ def doGetUserInfo(user_email=None): credentials = storage.get() if credentials is None or credentials.invalid: doRequestOAuth() - credentials = storage.get() + credentials = storage.get() user_email = credentials.id_token[u'email'] if user_email[:4].lower() == u'uid:': user_email = user_email[4:] @@ -6052,8 +6055,7 @@ def doGetOrgInfo(): result = callGAPI(service=cd.orgunits(), function=u'get', customerId=customerId, orgUnitPath=name) print_json(None, result) if get_users: - if name != u'/': - name = u'/%s' % name + name = result[u'orgUnitPath'] print u'Users: ' page_message = u'Got %%total_items%% users: %%first_item%% - %%last_item%%\n' users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, message_attribute=u'primaryEmail', customer=customerId, query=u"orgUnitPath='%s'" % name, maxResults=500, fields=u'users(primaryEmail,orgUnitPath),nextPageToken') @@ -6372,6 +6374,7 @@ def doGetDomainInfo(): adm = buildGAPIObject(u'admin-settings') if len(sys.argv) > 4 and sys.argv[3].lower() == u'logo': target_file = sys.argv[4] + adminObj = getAdminSettingsObject() logo_image = adminObj.GetDomainLogo() try: fp = open(target_file, 'wb') @@ -6477,8 +6480,8 @@ def doUndeleteUser(): user_uid = False orgUnit = u'/' try: - if sys.argv[3].lower() in [u'ou', u'org']: - orgUnit = sys.argv[4] + if sys.argv[4].lower() in [u'ou', u'org']: + orgUnit = sys.argv[5] except IndexError: pass cd = buildGAPIObject(u'directory') @@ -6516,7 +6519,7 @@ def doUndeleteUser(): else: user_uid = matching_users[0][u'id'] print u"Undeleting account for %s" % user - callGAPI(service=cd.users(), function=u'undelete', userKey=user_uid, body={u'orgUnit': orgUnit}) + callGAPI(service=cd.users(), function=u'undelete', userKey=user_uid, body={u'orgUnitPath': orgUnit}) def doDeleteGroup(): group = sys.argv[3] @@ -6807,6 +6810,7 @@ def doPrintGroups(): i = 3 printname = printdesc = printid = members = owners = managers = settings = admin_created = aliases = todrive = False usedomain = usemember = None + listDelimiter = u'\n' group_attributes = [{u'Email': u'Email'}] titles = [u'Email'] fields = u'nextPageToken,groups(email)' @@ -6818,6 +6822,9 @@ def doPrintGroups(): elif sys.argv[i].lower() == u'todrive': todrive = True i += 1 + elif sys.argv[i].lower() == u'delimiter': + listDelimiter = sys.argv[i+1] + i += 2 elif sys.argv[i].lower() == u'member': usemember = sys.argv[i+1].lower() i += 2 @@ -6910,8 +6917,6 @@ def doPrintGroups(): if aliases: try: group.update({u'Aliases': ' '.join(group_vals[u'aliases'])}) - for alias in group_vals[u'aliases']: - print u'%s,%s' % (group_vals[u'email'].lower(), alias.lower()) except KeyError: pass try: @@ -6952,11 +6957,11 @@ def doPrintGroups(): except KeyError: all_true_members.append(member_email) if members: - group.update({u'Members': u"\n".join(all_true_members)}) + group.update({u'Members': listDelimiter.join(all_true_members)}) if managers: - group.update({u'Managers': u"\n".join(all_managers)}) + group.update({u'Managers': listDelimiter.join(all_managers)}) if owners: - group.update({u'Owners': u"\n".join(all_owners)}) + group.update({u'Owners': listDelimiter.join(all_owners)}) if settings: sys.stderr.write(u" Retrieving Settings for group %s (%s of %s)...\r\n" % (group_vals[u'email'], count, total_groups)) gs = buildGAPIObject(u'groupssettings') @@ -7131,10 +7136,9 @@ def doPrintGroupMembers(): continue try: member_attributes[0][title] - member_attr[title] = member[title] except KeyError: member_attributes[0][title] = title - member_attr[title] = member[title] + member_attr[title] = member[title] member_attributes.append(member_attr) i += 1 titles = member_attributes[0].keys() @@ -7162,10 +7166,15 @@ def doPrintMobileDevices(): sys.exit(3) elif orderBy == u'lastsync': orderBy = u'lastSync' + elif orderBy == u'deviceid': + orderBy = u'deviceId' i += 2 elif sys.argv[i].lower() in [u'ascending', u'descending']: sortOrder = sys.argv[i].upper() i += 1 + else: + print 'Error: %s is not a valid argument to "gam print mobile"' % sys.argv[i] + sys.exit(3) sys.stderr.write(u'Retrieving All Mobile Devices for organization (may take some time for large accounts)...\n') page_message = u'Got %%num_items%% mobile devices...\n' all_mobile = callGAPIpages(service=cd.mobiledevices(), function=u'list', items=u'mobiledevices', page_message=page_message, customerId=customerId, query=query, orderBy=orderBy, sortOrder=sortOrder) @@ -7223,6 +7232,9 @@ def doPrintCrosDevices(): elif sys.argv[i].lower() in [u'ascending', u'descending']: sortOrder = sys.argv[i].upper() i += 1 + else: + print 'Error: %s is not a valid argument to "gam print cros"' % sys.argv[i] + sys.exit(3) sys.stderr.write(u'Retrieving All Chrome OS Devices for organization (may take some time for large accounts)...\n') page_message = u'Got %%num_items%% Chrome devices...\n' all_cros = callGAPIpages(service=cd.chromeosdevices(), function=u'list', items=u'chromeosdevices', page_message=page_message, query=query, customerId=customerId, sortOrder=sortOrder) @@ -7737,10 +7749,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa if entity_type == u'user': users = [entity,] elif entity_type == u'users': - if entity.find(u' ') != -1: - users = entity.split(u' ') - else: - users = entity.split(u',') + users = entity.replace(u',', u' ').split() elif entity_type == u'group': got_uids = True group = entity @@ -8210,10 +8219,10 @@ try: for arg in argv_template: if arg[0] != '~': argv.append(arg) - elif arg[1:] in row.keys(): + elif arg[1:] in row: argv.append(row[arg[1:]]) else: - print 'Error: header "%s" not found in CSV headers of %s, giving up.' % (row.keys(), arg[1:]) + print 'Error: header "%s" not found in CSV headers of "%s", giving up.' % (arg[1:], ','.join(row.keys())) sys.exit(0) items.append(argv) run_batch(items)