mirror of
https://github.com/GAM-team/GAM.git
synced 2025-07-09 22:23:35 +00:00
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:
@ -699,9 +699,10 @@ Specify a collection of Users by directly specifying them or by specifiying item
|
|||||||
(contentrestrictions readonly true [reason <String>])|
|
(contentrestrictions readonly true [reason <String>])|
|
||||||
copyrequireswriterpermission|
|
copyrequireswriterpermission|
|
||||||
(lastviewedbyme <Time>)|(modifieddate|modifiedtime <Time>)|(description <String>)|(mimetype <MimeType>)|
|
(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>)|
|
(securityupdate <Boolean>)|
|
||||||
(shortcut <DriveFileID>)
|
(shortcut <DriveFileID>)|
|
||||||
|
writerscantshare|writerscanshare
|
||||||
<DriveFileUpdateAttribute> ::=
|
<DriveFileUpdateAttribute> ::=
|
||||||
(localfile <FileName>|-)|
|
(localfile <FileName>|-)|
|
||||||
(convert)|(ocr)|(ocrlanguage <Language>)|
|
(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>])|
|
(contentrestrictions readonly true [reason <String>])|
|
||||||
(copyrequireswriterpermission <Boolean>)|
|
(copyrequireswriterpermission <Boolean>)|
|
||||||
(lastviewedbyme <Time>)|(modifieddate <Time>)|(description <String>)|(mimetype <MimeType>)|
|
(lastviewedbyme <Time>)|(modifieddate <Time>)|(description <String>)|(mimetype <MimeType>)|
|
||||||
(parentid <DriveFolderID>)|(parentname <DriveFolderName>)|(anyownerparentname <DriveFolderName>)|writerscantshare|writerscanshare
|
(parentid <DriveFolderID>)|(parentname <DriveFolderName>)|(anyownerparentname <DriveFolderName>)|
|
||||||
(securityupdate <Boolean>)|
|
(securityupdate <Boolean>)|
|
||||||
(shortcut <DriveFileID>)
|
(shortcut <DriveFileID>)|
|
||||||
|
writerscantshare|writerscanshare
|
||||||
<GroupSettingsAttribute> ::=
|
<GroupSettingsAttribute> ::=
|
||||||
(allowexternalmembers <Boolean>)|
|
(allowexternalmembers <Boolean>)|
|
||||||
(allowwebposting <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
|
field <FieldName> (type bool|date|double|email|int64|phone|string) [multivalued|multivalue] [indexed] [restricted] [range <Number> <Number>] endfield
|
||||||
|
|
||||||
<UserBasicAttribute> ::=
|
<UserBasicAttribute> ::=
|
||||||
(agreed2terms|agreedtoterms <Boolean>)|
|
|
||||||
(changepassword|changepasswordatnextlogin <Boolean>)|
|
(changepassword|changepasswordatnextlogin <Boolean>)|
|
||||||
(base64-md5|base64-sha1|crypt|sha|sha1|sha-1|md5|nohash)|
|
(base64-md5|base64-sha1|crypt|sha|sha1|sha-1|md5|nohash)|
|
||||||
(customerid <String>)|
|
(customerid <String>)|
|
||||||
|
@ -550,6 +550,7 @@ def SetGlobalVariables():
|
|||||||
filePresentValue=4,
|
filePresentValue=4,
|
||||||
fileAbsentValue=0)
|
fileAbsentValue=0)
|
||||||
_getOldSignalFile(GC_NO_BROWSER, 'nobrowser.txt')
|
_getOldSignalFile(GC_NO_BROWSER, 'nobrowser.txt')
|
||||||
|
_getOldSignalFile(GC_NO_TDEMAIL, 'notdemail.txt')
|
||||||
_getOldSignalFile(GC_OAUTH_BROWSER, 'oauthbrowser.txt')
|
_getOldSignalFile(GC_OAUTH_BROWSER, 'oauthbrowser.txt')
|
||||||
# _getOldSignalFile(GC_NO_CACHE, u'nocache.txt')
|
# _getOldSignalFile(GC_NO_CACHE, u'nocache.txt')
|
||||||
# _getOldSignalFile(GC_CACHE_DISCOVERY_ONLY, u'allcache.txt', filePresentValue=False, fileAbsentValue=True)
|
# _getOldSignalFile(GC_CACHE_DISCOVERY_ONLY, u'allcache.txt', filePresentValue=False, fileAbsentValue=True)
|
||||||
@ -6676,12 +6677,12 @@ def getUserAttributes(i, cd, updateCmd):
|
|||||||
body['changePasswordAtNextLogin'] = getBoolean(
|
body['changePasswordAtNextLogin'] = getBoolean(
|
||||||
sys.argv[i + 1], myarg)
|
sys.argv[i + 1], myarg)
|
||||||
i += 2
|
i += 2
|
||||||
elif myarg == 'ipwhitelisted':
|
|
||||||
body['ipWhitelisted'] = getBoolean(sys.argv[i + 1], myarg)
|
|
||||||
i += 2
|
|
||||||
elif myarg == 'agreedtoterms':
|
elif myarg == 'agreedtoterms':
|
||||||
body['agreedToTerms'] = getBoolean(sys.argv[i + 1], myarg)
|
body['agreedToTerms'] = getBoolean(sys.argv[i + 1], myarg)
|
||||||
i += 2
|
i += 2
|
||||||
|
elif myarg == 'ipwhitelisted':
|
||||||
|
body['ipWhitelisted'] = getBoolean(sys.argv[i + 1], myarg)
|
||||||
|
i += 2
|
||||||
elif myarg in ['org', 'ou']:
|
elif myarg in ['org', 'ou']:
|
||||||
body['orgUnitPath'] = gapi_directory_orgunits.getOrgUnitItem(
|
body['orgUnitPath'] = gapi_directory_orgunits.getOrgUnitItem(
|
||||||
sys.argv[i + 1], pathOnly=True)
|
sys.argv[i + 1], pathOnly=True)
|
||||||
|
@ -283,7 +283,8 @@ and follow recommend steps to authorize GAM for Drive access.''')
|
|||||||
if GC_Values[GC_NO_BROWSER]:
|
if GC_Values[GC_NO_BROWSER]:
|
||||||
msg_txt = f'Drive file uploaded to:\n {file_url}'
|
msg_txt = f'Drive file uploaded to:\n {file_url}'
|
||||||
msg_subj = f'{GC_Values[GC_DOMAIN]} - {list_type}'
|
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)
|
print(msg_txt)
|
||||||
else:
|
else:
|
||||||
webbrowser.open(file_url)
|
webbrowser.open(file_url)
|
||||||
|
@ -405,7 +405,7 @@ def sync():
|
|||||||
controlflow.csv_field_error_exit(devicetype_column, input_file.fieldnames)
|
controlflow.csv_field_error_exit(devicetype_column, input_file.fieldnames)
|
||||||
if assettag_column and assettag_column not in input_file.fieldnames:
|
if assettag_column and assettag_column not in input_file.fieldnames:
|
||||||
controlflow.csv_field_error_exit(assettag_column, input_file.fieldnames)
|
controlflow.csv_field_error_exit(assettag_column, input_file.fieldnames)
|
||||||
local_devices = []
|
local_devices = {}
|
||||||
for row in input_file:
|
for row in input_file:
|
||||||
# upper() is very important to comparison since Google
|
# upper() is very important to comparison since Google
|
||||||
# always return uppercase serials
|
# always return uppercase serials
|
||||||
@ -414,28 +414,43 @@ def sync():
|
|||||||
local_device['deviceType'] = static_devicetype
|
local_device['deviceType'] = static_devicetype
|
||||||
else:
|
else:
|
||||||
local_device['deviceType'] = row[devicetype_column].strip()
|
local_device['deviceType'] = row[devicetype_column].strip()
|
||||||
|
sndt = f"{local_device['serialNumber']}-{local_device['deviceType']}"
|
||||||
if assettag_column:
|
if assettag_column:
|
||||||
local_device['assetTag'] = row[assettag_column].strip()
|
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)
|
fileutils.close_file(f)
|
||||||
page_message = gapi.got_total_items_msg('Company Devices', '...\n')
|
page_message = gapi.got_total_items_msg('Company Devices', '...\n')
|
||||||
device_fields = ['serialNumber', 'deviceType', 'lastSyncTime', 'name']
|
device_fields = ['serialNumber', 'deviceType', 'lastSyncTime', 'name']
|
||||||
if assettag_column:
|
if assettag_column:
|
||||||
device_fields.append('assetTag')
|
device_fields.append('assetTag')
|
||||||
fields = f'nextPageToken,devices({",".join(device_fields)})'
|
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,
|
customer=customer, page_message=page_message,
|
||||||
pageSize=100, filter=device_filter, view='COMPANY_INVENTORY', fields=fields)
|
pageSize=100, filter=device_filter, view='COMPANY_INVENTORY', fields=fields)
|
||||||
remote_device_map = {}
|
for remote_device in result:
|
||||||
for remote_device in remote_devices:
|
|
||||||
sn = remote_device['serialNumber']
|
sn = remote_device['serialNumber']
|
||||||
last_sync = remote_device.pop('lastSyncTime', NEVER_TIME_NOMS)
|
last_sync = remote_device.pop('lastSyncTime', NEVER_TIME_NOMS)
|
||||||
name = remote_device.pop('name')
|
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:
|
if last_sync == NEVER_TIME_NOMS:
|
||||||
remote_device_map[sn]['unassigned'] = True
|
remote_device_map[sndt]['unassigned'] = True
|
||||||
devices_to_add = [device for device in local_devices if device not in remote_devices]
|
devices_to_add = []
|
||||||
missing_devices = [device for device in remote_devices if device not in local_devices]
|
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...')
|
print(f'Need to add {len(devices_to_add)} and remove {len(missing_devices)} devices...')
|
||||||
for add_device in devices_to_add:
|
for add_device in devices_to_add:
|
||||||
print(f'Creating {add_device["serialNumber"]}')
|
print(f'Creating {add_device["serialNumber"]}')
|
||||||
@ -447,8 +462,11 @@ def sync():
|
|||||||
print(f' {add_device["serialNumber"]} already exists')
|
print(f' {add_device["serialNumber"]} already exists')
|
||||||
for missing_device in missing_devices:
|
for missing_device in missing_devices:
|
||||||
sn = missing_device['serialNumber']
|
sn = missing_device['serialNumber']
|
||||||
name = remote_device_map[sn]['name']
|
sndt = f"{sn}-{missing_device['deviceType']}"
|
||||||
unassigned = remote_device_map[sn].get('unassigned')
|
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
|
action = unassigned_missing_action if unassigned else assigned_missing_action
|
||||||
if action == 'donothing':
|
if action == 'donothing':
|
||||||
pass
|
pass
|
||||||
|
@ -116,7 +116,7 @@ def info():
|
|||||||
print(' Members:')
|
print(' Members:')
|
||||||
for member in members:
|
for member in members:
|
||||||
role = get_single_role(member.get('roles', [])).lower()
|
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()
|
member_type = member.get('type', 'USER').lower()
|
||||||
jc_string = ''
|
jc_string = ''
|
||||||
if showJoinDate:
|
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]:
|
for member in cached_group_members[group_id]:
|
||||||
member_id = member.get('name', '')
|
member_id = member.get('name', '')
|
||||||
member_id = member_id.split('/')[-1]
|
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()
|
member_type = member.get('type', 'USER').lower()
|
||||||
if show_role:
|
if show_role:
|
||||||
role = get_single_role(member.get('roles', [])).lower()
|
role = get_single_role(member.get('roles', [])).lower()
|
||||||
@ -315,7 +315,7 @@ def print_():
|
|||||||
'list',
|
'list',
|
||||||
'memberships',
|
'memberships',
|
||||||
page_message=page_message,
|
page_message=page_message,
|
||||||
message_attribute=['memberKey', 'id'],
|
message_attribute=['preferredMemberKey', 'id'],
|
||||||
soft_errors=True,
|
soft_errors=True,
|
||||||
parent=groupKey_id,
|
parent=groupKey_id,
|
||||||
view='BASIC')
|
view='BASIC')
|
||||||
@ -329,7 +329,7 @@ def print_():
|
|||||||
ownersList = []
|
ownersList = []
|
||||||
ownersCount = 0
|
ownersCount = 0
|
||||||
for member in groupMembers:
|
for member in groupMembers:
|
||||||
member_email = member['memberKey']['id']
|
member_email = member['preferredMemberKey']['id']
|
||||||
role = get_single_role(member.get('roles', []))
|
role = get_single_role(member.get('roles', []))
|
||||||
if not validRoles or role in validRoles:
|
if not validRoles or role in validRoles:
|
||||||
if role == ROLE_MEMBER:
|
if role == ROLE_MEMBER:
|
||||||
@ -479,8 +479,8 @@ def print_members():
|
|||||||
view='FULL',
|
view='FULL',
|
||||||
pageSize=500,
|
pageSize=500,
|
||||||
page_message=page_message,
|
page_message=page_message,
|
||||||
message_attribute=['memberKey', 'id'])
|
message_attribute=['preferredMemberKey', 'id'])
|
||||||
#fields='nextPageToken,memberships(memberKey,roles,createTime,updateTime)')
|
#fields='nextPageToken,memberships(preferredMemberKey,roles,createTime,updateTime)')
|
||||||
if roles:
|
if roles:
|
||||||
group_members = filter_members_to_roles(group_members, roles)
|
group_members = filter_members_to_roles(group_members, roles)
|
||||||
for member in group_members:
|
for member in group_members:
|
||||||
@ -565,7 +565,7 @@ def update():
|
|||||||
items.append(item)
|
items.append(item)
|
||||||
elif len(users_email) > 0:
|
elif len(users_email) > 0:
|
||||||
body = {
|
body = {
|
||||||
'memberKey': {
|
'preferredMemberKey': {
|
||||||
'id': users_email[0]
|
'id': users_email[0]
|
||||||
},
|
},
|
||||||
'roles': [{
|
'roles': [{
|
||||||
@ -785,12 +785,12 @@ def update():
|
|||||||
page_message=page_message,
|
page_message=page_message,
|
||||||
throw_reasons=gapi_errors.MEMBERS_THROW_REASONS,
|
throw_reasons=gapi_errors.MEMBERS_THROW_REASONS,
|
||||||
parent=parent,
|
parent=parent,
|
||||||
fields='nextPageToken,memberships(memberKey,roles)')
|
fields='nextPageToken,memberships(preferredMemberKey,roles)')
|
||||||
result = filter_members_to_roles(result, roles)
|
result = filter_members_to_roles(result, roles)
|
||||||
if not result:
|
if not result:
|
||||||
print('Group already has 0 members')
|
print('Group already has 0 members')
|
||||||
return
|
return
|
||||||
users_email = [member['memberKey']['id'] for member in result]
|
users_email = [member['preferredMemberKey']['id'] for member in result]
|
||||||
sys.stderr.write(
|
sys.stderr.write(
|
||||||
f'Group: {group}, Will remove {len(users_email)} {", ".join(roles).lower()}s.\n'
|
f'Group: {group}, Will remove {len(users_email)} {", ".join(roles).lower()}s.\n'
|
||||||
)
|
)
|
||||||
|
@ -124,7 +124,7 @@ SKUS = {
|
|||||||
'Google-Apps': {
|
'Google-Apps': {
|
||||||
'product': 'Google-Apps',
|
'product': 'Google-Apps',
|
||||||
'aliases': ['standard', 'free'],
|
'aliases': ['standard', 'free'],
|
||||||
'displayName': 'G Suite Free/Standard'
|
'displayName': 'G Suite Legacy'
|
||||||
},
|
},
|
||||||
'Google-Apps-For-Business': {
|
'Google-Apps-For-Business': {
|
||||||
'product': 'Google-Apps',
|
'product': 'Google-Apps',
|
||||||
@ -1246,10 +1246,12 @@ GC_DOMAIN = 'domain'
|
|||||||
GC_DRIVE_DIR = 'drive_dir'
|
GC_DRIVE_DIR = 'drive_dir'
|
||||||
# Enable Delegated Admin Service Accounts
|
# Enable Delegated Admin Service Accounts
|
||||||
GC_ENABLE_DASA = 'enabledasa'
|
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
|
# and doRequestOAuth prints a link and waits for the verification code when
|
||||||
# oauth2.txt is being created
|
# oauth2.txt is being created
|
||||||
GC_NO_BROWSER = 'no_browser'
|
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.
|
# oauth_browser forces usage of web server OAuth flow that proved problematic.
|
||||||
GC_OAUTH_BROWSER = 'oauth_browser'
|
GC_OAUTH_BROWSER = 'oauth_browser'
|
||||||
# Disable GAM API caching
|
# Disable GAM API caching
|
||||||
@ -1304,6 +1306,7 @@ GC_Defaults = {
|
|||||||
GC_DRIVE_DIR: '',
|
GC_DRIVE_DIR: '',
|
||||||
GC_ENABLE_DASA: False,
|
GC_ENABLE_DASA: False,
|
||||||
GC_NO_BROWSER: False,
|
GC_NO_BROWSER: False,
|
||||||
|
GC_NO_TDEMAIL: False,
|
||||||
GC_NO_CACHE: False,
|
GC_NO_CACHE: False,
|
||||||
GC_NO_SHORT_URLS: False,
|
GC_NO_SHORT_URLS: False,
|
||||||
GC_NO_UPDATE_CHECK: False,
|
GC_NO_UPDATE_CHECK: False,
|
||||||
@ -1389,6 +1392,9 @@ GC_VAR_INFO = {
|
|||||||
GC_NO_BROWSER: {
|
GC_NO_BROWSER: {
|
||||||
GC_VAR_TYPE: GC_TYPE_BOOLEAN
|
GC_VAR_TYPE: GC_TYPE_BOOLEAN
|
||||||
},
|
},
|
||||||
|
GC_NO_TDEMAIL: {
|
||||||
|
GC_VAR_TYPE: GC_TYPE_BOOLEAN
|
||||||
|
},
|
||||||
GC_NO_CACHE: {
|
GC_NO_CACHE: {
|
||||||
GC_VAR_TYPE: GC_TYPE_BOOLEAN
|
GC_VAR_TYPE: GC_TYPE_BOOLEAN
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user