Several fixes/updates (#1426)

* agreedToTerms is now read-only

* Fix sync devices

* assetTag if specified is part of sync device key

* Handle missing assetTags

* Leave agreedtoterms as an undocumented option

* More assetTag processing, the field is not returned from the API if it's empty

* Fix DriveFileAttribute formatting

* memberKey has been replaced by preferredMemberKey

* Correct license name

* If notdemail.txt is present, write_csv_file will not send an email
This commit is contained in:
Ross Scroggs
2021-10-05 05:37:09 -07:00
committed by GitHub
parent 0a627d5c79
commit 3200de56cc
6 changed files with 58 additions and 31 deletions

View File

@ -699,9 +699,10 @@ Specify a collection of Users by directly specifying them or by specifiying item
(contentrestrictions readonly true [reason <String>])|
copyrequireswriterpermission|
(lastviewedbyme <Time>)|(modifieddate|modifiedtime <Time>)|(description <String>)|(mimetype <MimeType>)|
(parentid <DriveFolderID>)|(parentname <DriveFolderName>)|(anyownerparentname <DriveFolderName>)|writerscantshare|writerscanshare
(parentid <DriveFolderID>)|(parentname <DriveFolderName>)|(anyownerparentname <DriveFolderName>)|
(securityupdate <Boolean>)|
(shortcut <DriveFileID>)
(shortcut <DriveFileID>)|
writerscantshare|writerscanshare
<DriveFileUpdateAttribute> ::=
(localfile <FileName>|-)|
(convert)|(ocr)|(ocrlanguage <Language>)|
@ -710,9 +711,10 @@ Specify a collection of Users by directly specifying them or by specifiying item
(contentrestrictions readonly true [reason <String>])|
(copyrequireswriterpermission <Boolean>)|
(lastviewedbyme <Time>)|(modifieddate <Time>)|(description <String>)|(mimetype <MimeType>)|
(parentid <DriveFolderID>)|(parentname <DriveFolderName>)|(anyownerparentname <DriveFolderName>)|writerscantshare|writerscanshare
(parentid <DriveFolderID>)|(parentname <DriveFolderName>)|(anyownerparentname <DriveFolderName>)|
(securityupdate <Boolean>)|
(shortcut <DriveFileID>)
(shortcut <DriveFileID>)|
writerscantshare|writerscanshare
<GroupSettingsAttribute> ::=
(allowexternalmembers <Boolean>)|
(allowwebposting <Boolean>)|
@ -798,7 +800,6 @@ Specify a collection of Users by directly specifying them or by specifiying item
field <FieldName> (type bool|date|double|email|int64|phone|string) [multivalued|multivalue] [indexed] [restricted] [range <Number> <Number>] endfield
<UserBasicAttribute> ::=
(agreed2terms|agreedtoterms <Boolean>)|
(changepassword|changepasswordatnextlogin <Boolean>)|
(base64-md5|base64-sha1|crypt|sha|sha1|sha-1|md5|nohash)|
(customerid <String>)|

View File

@ -550,6 +550,7 @@ def SetGlobalVariables():
filePresentValue=4,
fileAbsentValue=0)
_getOldSignalFile(GC_NO_BROWSER, 'nobrowser.txt')
_getOldSignalFile(GC_NO_TDEMAIL, 'notdemail.txt')
_getOldSignalFile(GC_OAUTH_BROWSER, 'oauthbrowser.txt')
# _getOldSignalFile(GC_NO_CACHE, u'nocache.txt')
# _getOldSignalFile(GC_CACHE_DISCOVERY_ONLY, u'allcache.txt', filePresentValue=False, fileAbsentValue=True)
@ -6676,12 +6677,12 @@ def getUserAttributes(i, cd, updateCmd):
body['changePasswordAtNextLogin'] = getBoolean(
sys.argv[i + 1], myarg)
i += 2
elif myarg == 'ipwhitelisted':
body['ipWhitelisted'] = getBoolean(sys.argv[i + 1], myarg)
i += 2
elif myarg == 'agreedtoterms':
body['agreedToTerms'] = getBoolean(sys.argv[i + 1], myarg)
i += 2
elif myarg == 'ipwhitelisted':
body['ipWhitelisted'] = getBoolean(sys.argv[i + 1], myarg)
i += 2
elif myarg in ['org', 'ou']:
body['orgUnitPath'] = gapi_directory_orgunits.getOrgUnitItem(
sys.argv[i + 1], pathOnly=True)

View File

@ -283,7 +283,8 @@ and follow recommend steps to authorize GAM for Drive access.''')
if GC_Values[GC_NO_BROWSER]:
msg_txt = f'Drive file uploaded to:\n {file_url}'
msg_subj = f'{GC_Values[GC_DOMAIN]} - {list_type}'
gam.send_email(msg_subj, msg_txt)
if not GC_Values[GC_NO_TDEMAIL]:
gam.send_email(msg_subj, msg_txt)
print(msg_txt)
else:
webbrowser.open(file_url)

View File

@ -405,7 +405,7 @@ def sync():
controlflow.csv_field_error_exit(devicetype_column, input_file.fieldnames)
if assettag_column and assettag_column not in input_file.fieldnames:
controlflow.csv_field_error_exit(assettag_column, input_file.fieldnames)
local_devices = []
local_devices = {}
for row in input_file:
# upper() is very important to comparison since Google
# always return uppercase serials
@ -414,28 +414,43 @@ def sync():
local_device['deviceType'] = static_devicetype
else:
local_device['deviceType'] = row[devicetype_column].strip()
sndt = f"{local_device['serialNumber']}-{local_device['deviceType']}"
if assettag_column:
local_device['assetTag'] = row[assettag_column].strip()
local_devices.append(local_device)
sndt += f"-{local_device['assetTag']}"
local_devices[sndt] = local_device
fileutils.close_file(f)
page_message = gapi.got_total_items_msg('Company Devices', '...\n')
device_fields = ['serialNumber', 'deviceType', 'lastSyncTime', 'name']
if assettag_column:
device_fields.append('assetTag')
fields = f'nextPageToken,devices({",".join(device_fields)})'
remote_devices = gapi.get_all_pages(ci.devices(), 'list', 'devices',
remote_devices = {}
remote_device_map = {}
result = gapi.get_all_pages(ci.devices(), 'list', 'devices',
customer=customer, page_message=page_message,
pageSize=100, filter=device_filter, view='COMPANY_INVENTORY', fields=fields)
remote_device_map = {}
for remote_device in remote_devices:
for remote_device in result:
sn = remote_device['serialNumber']
last_sync = remote_device.pop('lastSyncTime', NEVER_TIME_NOMS)
name = remote_device.pop('name')
remote_device_map[sn] = {'name': name}
sndt = f"{remote_device['serialNumber']}-{remote_device['deviceType']}"
if assettag_column:
if 'assetTag' not in remote_device:
remote_device['assetTag'] = ''
sndt += f"-{remote_device['assetTag']}"
remote_devices[sndt] = remote_device
remote_device_map[sndt] = {'name': name}
if last_sync == NEVER_TIME_NOMS:
remote_device_map[sn]['unassigned'] = True
devices_to_add = [device for device in local_devices if device not in remote_devices]
missing_devices = [device for device in remote_devices if device not in local_devices]
remote_device_map[sndt]['unassigned'] = True
devices_to_add = []
for sndt, device in iter(local_devices.items()):
if sndt not in remote_devices:
devices_to_add.append(device)
missing_devices = []
for sndt, device in iter(remote_devices.items()):
if sndt not in local_devices:
missing_devices.append(device)
print(f'Need to add {len(devices_to_add)} and remove {len(missing_devices)} devices...')
for add_device in devices_to_add:
print(f'Creating {add_device["serialNumber"]}')
@ -447,8 +462,11 @@ def sync():
print(f' {add_device["serialNumber"]} already exists')
for missing_device in missing_devices:
sn = missing_device['serialNumber']
name = remote_device_map[sn]['name']
unassigned = remote_device_map[sn].get('unassigned')
sndt = f"{sn}-{missing_device['deviceType']}"
if assettag_column:
sndt += f"-{missing_device['assetTag']}"
name = remote_device_map[sndt]['name']
unassigned = remote_device_map[sndt].get('unassigned')
action = unassigned_missing_action if unassigned else assigned_missing_action
if action == 'donothing':
pass

View File

@ -116,7 +116,7 @@ def info():
print(' Members:')
for member in members:
role = get_single_role(member.get('roles', [])).lower()
email = member.get('memberKey', {}).get('id')
email = member.get('preferredMemberKey', {}).get('id')
member_type = member.get('type', 'USER').lower()
jc_string = ''
if showJoinDate:
@ -145,7 +145,7 @@ def print_member_tree(ci, group_id, cached_group_members, spaces, show_role):
for member in cached_group_members[group_id]:
member_id = member.get('name', '')
member_id = member_id.split('/')[-1]
email = member.get('memberKey', {}).get('id')
email = member.get('preferredMemberKey', {}).get('id')
member_type = member.get('type', 'USER').lower()
if show_role:
role = get_single_role(member.get('roles', [])).lower()
@ -315,7 +315,7 @@ def print_():
'list',
'memberships',
page_message=page_message,
message_attribute=['memberKey', 'id'],
message_attribute=['preferredMemberKey', 'id'],
soft_errors=True,
parent=groupKey_id,
view='BASIC')
@ -329,7 +329,7 @@ def print_():
ownersList = []
ownersCount = 0
for member in groupMembers:
member_email = member['memberKey']['id']
member_email = member['preferredMemberKey']['id']
role = get_single_role(member.get('roles', []))
if not validRoles or role in validRoles:
if role == ROLE_MEMBER:
@ -479,8 +479,8 @@ def print_members():
view='FULL',
pageSize=500,
page_message=page_message,
message_attribute=['memberKey', 'id'])
#fields='nextPageToken,memberships(memberKey,roles,createTime,updateTime)')
message_attribute=['preferredMemberKey', 'id'])
#fields='nextPageToken,memberships(preferredMemberKey,roles,createTime,updateTime)')
if roles:
group_members = filter_members_to_roles(group_members, roles)
for member in group_members:
@ -565,7 +565,7 @@ def update():
items.append(item)
elif len(users_email) > 0:
body = {
'memberKey': {
'preferredMemberKey': {
'id': users_email[0]
},
'roles': [{
@ -785,12 +785,12 @@ def update():
page_message=page_message,
throw_reasons=gapi_errors.MEMBERS_THROW_REASONS,
parent=parent,
fields='nextPageToken,memberships(memberKey,roles)')
fields='nextPageToken,memberships(preferredMemberKey,roles)')
result = filter_members_to_roles(result, roles)
if not result:
print('Group already has 0 members')
return
users_email = [member['memberKey']['id'] for member in result]
users_email = [member['preferredMemberKey']['id'] for member in result]
sys.stderr.write(
f'Group: {group}, Will remove {len(users_email)} {", ".join(roles).lower()}s.\n'
)

View File

@ -124,7 +124,7 @@ SKUS = {
'Google-Apps': {
'product': 'Google-Apps',
'aliases': ['standard', 'free'],
'displayName': 'G Suite Free/Standard'
'displayName': 'G Suite Legacy'
},
'Google-Apps-For-Business': {
'product': 'Google-Apps',
@ -1246,10 +1246,12 @@ GC_DOMAIN = 'domain'
GC_DRIVE_DIR = 'drive_dir'
# Enable Delegated Admin Service Accounts
GC_ENABLE_DASA = 'enabledasa'
# If no_browser is False, writeCSVfile won't open a browser when todrive is set
# If no_browser is True, writeCSVfile won't open a browser when todrive is set
# and doRequestOAuth prints a link and waits for the verification code when
# oauth2.txt is being created
GC_NO_BROWSER = 'no_browser'
# If no_tdemail is True, writeCSVfile won't send an email
GC_NO_TDEMAIL = 'no_tdemail'
# oauth_browser forces usage of web server OAuth flow that proved problematic.
GC_OAUTH_BROWSER = 'oauth_browser'
# Disable GAM API caching
@ -1304,6 +1306,7 @@ GC_Defaults = {
GC_DRIVE_DIR: '',
GC_ENABLE_DASA: False,
GC_NO_BROWSER: False,
GC_NO_TDEMAIL: False,
GC_NO_CACHE: False,
GC_NO_SHORT_URLS: False,
GC_NO_UPDATE_CHECK: False,
@ -1389,6 +1392,9 @@ GC_VAR_INFO = {
GC_NO_BROWSER: {
GC_VAR_TYPE: GC_TYPE_BOOLEAN
},
GC_NO_TDEMAIL: {
GC_VAR_TYPE: GC_TYPE_BOOLEAN
},
GC_NO_CACHE: {
GC_VAR_TYPE: GC_TYPE_BOOLEAN
},