mirror of
https://github.com/GAM-team/GAM.git
synced 2025-07-10 14:43:34 +00:00
Initial CloudIdentity Groups work, more APIs to own files
This commit is contained in:
@ -9,8 +9,8 @@ env:
|
|||||||
- MIN_PYTHON_VERSION=3.8.3
|
- MIN_PYTHON_VERSION=3.8.3
|
||||||
- BUILD_OPENSSL_VERSION=1.1.1g
|
- BUILD_OPENSSL_VERSION=1.1.1g
|
||||||
- MIN_OPENSSL_VERSION=1.1.1g
|
- MIN_OPENSSL_VERSION=1.1.1g
|
||||||
- PATCHELF_VERSION=0.10
|
- PATCHELF_VERSION=0.11
|
||||||
- PYINSTALLER_COMMIT=3010fdfaa037e9b19e936711d0c0be9b314b03c6
|
- PYINSTALLER_COMMIT=25eef61621a96fd42e8852a251d408ea57b9adb4
|
||||||
- secure: "FSKvLaiqhKz21SVgAQZI3bSX34Ffyev4l+R2G//QXNDu6UVQcuFsykzw+eZEG7fkhotXr8BMDL7xIkookiL8eLwUtcd/Z95HCjPBBHcmCSQleyvuuJBxdrQ9xldmiGLzMCYiumSH9OH4uJhQ39Yjnjsa8TK+PlTci6a/BTzlYyBSyDYDf7Iv/uhfQPDHL3pNwrQPHf4fL6/jcvo+uaPcv83AVZkNzZjjyoi9Aa+uh9xlbyHg11jp44463qqxoxTdYik3pYuXRBPjknjOGcnFHqn+QOVSdRQoiwbmT8xVuYuCzTv9THhuJ//i5u7s4y3Xyl7u17B3tdm86UlMpQHy/w9EsYaSBPOU4oPNomRtOnTSugh0v9ZBwptP5XfbslII/iA+LQdzTHhchn0W0CRyDqjOMSestWlrsq5NZJtBJTYHbebllOhEI7xbj9tY+re1zFWSPMOPgHJP23ovsdk3hD9OT93AzRHInCx5IxL6QvEgRhAancRuGkf2rGP0g/vX9fQ0Il3rNMSQxHB5CyHUBtUJ9nhU79YkMDZicD0jFMEwjWJO3itAp3ynoLXRgktgQCYUfgc9SpdWKD5SXLCYnSo22JD3D1P6h2EertRHaoKRLb+CRXQC/lM8uh/W+BjA2Xe6Vut2I/72ndjM+10T7E2xk1CFyCH37a5p8cH26Fs="
|
- secure: "FSKvLaiqhKz21SVgAQZI3bSX34Ffyev4l+R2G//QXNDu6UVQcuFsykzw+eZEG7fkhotXr8BMDL7xIkookiL8eLwUtcd/Z95HCjPBBHcmCSQleyvuuJBxdrQ9xldmiGLzMCYiumSH9OH4uJhQ39Yjnjsa8TK+PlTci6a/BTzlYyBSyDYDf7Iv/uhfQPDHL3pNwrQPHf4fL6/jcvo+uaPcv83AVZkNzZjjyoi9Aa+uh9xlbyHg11jp44463qqxoxTdYik3pYuXRBPjknjOGcnFHqn+QOVSdRQoiwbmT8xVuYuCzTv9THhuJ//i5u7s4y3Xyl7u17B3tdm86UlMpQHy/w9EsYaSBPOU4oPNomRtOnTSugh0v9ZBwptP5XfbslII/iA+LQdzTHhchn0W0CRyDqjOMSestWlrsq5NZJtBJTYHbebllOhEI7xbj9tY+re1zFWSPMOPgHJP23ovsdk3hD9OT93AzRHInCx5IxL6QvEgRhAancRuGkf2rGP0g/vX9fQ0Il3rNMSQxHB5CyHUBtUJ9nhU79YkMDZicD0jFMEwjWJO3itAp3ynoLXRgktgQCYUfgc9SpdWKD5SXLCYnSo22JD3D1P6h2EertRHaoKRLb+CRXQC/lM8uh/W+BjA2Xe6Vut2I/72ndjM+10T7E2xk1CFyCH37a5p8cH26Fs="
|
||||||
- secure: "J9380tGLOZWa7dSH1y5Il8T5JQpN6ad81gI6VR1HIU0svpRdjgikyDA7ca2MKYDUYYY9yVSkTV6gCl6iIU/9+SKaYugpP+tkvdGYkC2moJdcTgYM/WOnIK9ExQ3BPhN1neGxJjPTwKo1ft27mtZ2I5vuCiBwIcnKWLnKPyW3PD+mWpfqiLuEzkHoAh6G3jC4qbcCrZDeX/knE+PzqESUEi+8k1G8gYcSDWujba9ypSsqZ8T/MXagGla6l7y2Rz+/KZTJmFHwKAA10V+xPLVqxoiqi4ar66yUqy0BamwRXPcseI+ns3Q+4lUpMqVQ5GlRy7LF1xC8myjmcAexXk0F9hg+CMzewKI8UgmQH/ZJvQZEh8s6mW26+CqA4d3zMQkWaR0WtEtpiuH7AGHCflIqvEQ6UiG7ia3B8iZfW2wl0j/kqx4OuHkS3r0pWKVVIIvCj9Ow2BHP7SpiV1AcUGsVxzwbgTh67fitna3Z3c6Uj8ccQlNr7ZIt1az6Wf3w5njijkLOiBpQSLKunTTCTSge/JzBTKUcie3RE9vzirl58gUxAt36nDtPWnory+RttMZrOkBVbTeSxp+IUe8pNwLFPHABsafXsjkfzBOtFmm+0ZXWt2Rlog5NvlemJfQUWDlsL4g+BSakzN+4sIPKzSauWDHyaEeULY7Uprkil6c5zwo="
|
- secure: "J9380tGLOZWa7dSH1y5Il8T5JQpN6ad81gI6VR1HIU0svpRdjgikyDA7ca2MKYDUYYY9yVSkTV6gCl6iIU/9+SKaYugpP+tkvdGYkC2moJdcTgYM/WOnIK9ExQ3BPhN1neGxJjPTwKo1ft27mtZ2I5vuCiBwIcnKWLnKPyW3PD+mWpfqiLuEzkHoAh6G3jC4qbcCrZDeX/knE+PzqESUEi+8k1G8gYcSDWujba9ypSsqZ8T/MXagGla6l7y2Rz+/KZTJmFHwKAA10V+xPLVqxoiqi4ar66yUqy0BamwRXPcseI+ns3Q+4lUpMqVQ5GlRy7LF1xC8myjmcAexXk0F9hg+CMzewKI8UgmQH/ZJvQZEh8s6mW26+CqA4d3zMQkWaR0WtEtpiuH7AGHCflIqvEQ6UiG7ia3B8iZfW2wl0j/kqx4OuHkS3r0pWKVVIIvCj9Ow2BHP7SpiV1AcUGsVxzwbgTh67fitna3Z3c6Uj8ccQlNr7ZIt1az6Wf3w5njijkLOiBpQSLKunTTCTSge/JzBTKUcie3RE9vzirl58gUxAt36nDtPWnory+RttMZrOkBVbTeSxp+IUe8pNwLFPHABsafXsjkfzBOtFmm+0ZXWt2Rlog5NvlemJfQUWDlsL4g+BSakzN+4sIPKzSauWDHyaEeULY7Uprkil6c5zwo="
|
||||||
- secure: "szcjWHPr0Bf1KCkyTrV5Fu3ADhWk+pg8YWucjXHdybmhaQIKG7iBNg8LJ5d0OBTwAg31wK4ZgyLVSa2gKrAZ3UeDjykJFsR711xDSQOod51Wrgqu4FbXDewE817DUk3Cwe1l5DCu3/fjEw4vbm8B/qb7iMTRKCq6hJd97FwT5oauP0QHNPer9JjrW4F0Hk9ttkgEU2dXWvBMsTJsDOGNI3ddABE2HskxV4T4thelDYGKBDHhUOAsRwSjXgWy77Tvz98psPIvd+6+WPYNRdRWcPDyAR3Z1O/fNjUymrQI6eMaHoSFrmhDS5lbhjINRfdUmECyfCfIFeLWWiw4g4bq7l+4HBORbei55tAIjhEsxJQoqHi0Q5dD5TFh8IiWqowkFbpvNonMSIpKtB0cyT5jU1G/jRA7MPcIvSrdzHaDkoDNHJgAeZfgjOhzTGYYD19lGIljz5BQBcNFZY2dJbja+Jr4He2CMAOBOdERa4Zn1VyNfOmd8Bn5hu0C9D2ybnSCxjXXq5TRiktR8X7WycVZYfqMZXAwP9FEHVitJ4MZEGUc7S92K5gX4wmjcJjLS+Xo/0nsduQm8PuiMjbcPM7/oGx8Xm1KuSfHdKWMBoaesPaDvRX+YcuiNstXf1DkCWl72TsFABzddlNUMl/s2YSKkCSHAJ5ILqrB28Gx89kzVlg="
|
- secure: "szcjWHPr0Bf1KCkyTrV5Fu3ADhWk+pg8YWucjXHdybmhaQIKG7iBNg8LJ5d0OBTwAg31wK4ZgyLVSa2gKrAZ3UeDjykJFsR711xDSQOod51Wrgqu4FbXDewE817DUk3Cwe1l5DCu3/fjEw4vbm8B/qb7iMTRKCq6hJd97FwT5oauP0QHNPer9JjrW4F0Hk9ttkgEU2dXWvBMsTJsDOGNI3ddABE2HskxV4T4thelDYGKBDHhUOAsRwSjXgWy77Tvz98psPIvd+6+WPYNRdRWcPDyAR3Z1O/fNjUymrQI6eMaHoSFrmhDS5lbhjINRfdUmECyfCfIFeLWWiw4g4bq7l+4HBORbei55tAIjhEsxJQoqHi0Q5dD5TFh8IiWqowkFbpvNonMSIpKtB0cyT5jU1G/jRA7MPcIvSrdzHaDkoDNHJgAeZfgjOhzTGYYD19lGIljz5BQBcNFZY2dJbja+Jr4He2CMAOBOdERa4Zn1VyNfOmd8Bn5hu0C9D2ybnSCxjXXq5TRiktR8X7WycVZYfqMZXAwP9FEHVitJ4MZEGUc7S92K5gX4wmjcJjLS+Xo/0nsduQm8PuiMjbcPM7/oGx8Xm1KuSfHdKWMBoaesPaDvRX+YcuiNstXf1DkCWl72TsFABzddlNUMl/s2YSKkCSHAJ5ILqrB28Gx89kzVlg="
|
||||||
|
2151
src/gam/__init__.py
2151
src/gam/__init__.py
File diff suppressed because it is too large
Load Diff
@ -246,9 +246,9 @@ def get_all_pages(service,
|
|||||||
display a unique property of the first item in the current page.
|
display a unique property of the first item in the current page.
|
||||||
LAST_ITEM_MARKER : In conjunction with `message_attribute` arg, will
|
LAST_ITEM_MARKER : In conjunction with `message_attribute` arg, will
|
||||||
display a unique property of the last item in the current page.
|
display a unique property of the last item in the current page.
|
||||||
message_attribute: String, the name of a signature field within a single
|
message_attribute: String or list, the name of a signature field within a
|
||||||
returned item which identifies that unique item. This field is used with
|
single returned item which identifies that unique item. This field is used
|
||||||
`page_message` to templatize a paging status message.
|
with `page_message` to templatize a paging status message.
|
||||||
soft_errors: Bool, If True, writes non-fatal errors to stderr.
|
soft_errors: Bool, If True, writes non-fatal errors to stderr.
|
||||||
throw_reasons: A list of Google HTTP error reason strings indicating the
|
throw_reasons: A list of Google HTTP error reason strings indicating the
|
||||||
errors generated by this request should be re-thrown. All other HTTP
|
errors generated by this request should be re-thrown. All other HTTP
|
||||||
@ -293,11 +293,17 @@ def get_all_pages(service,
|
|||||||
if message_attribute:
|
if message_attribute:
|
||||||
first_item = page_items[0] if num_page_items > 0 else {}
|
first_item = page_items[0] if num_page_items > 0 else {}
|
||||||
last_item = page_items[-1] if num_page_items > 1 else first_item
|
last_item = page_items[-1] if num_page_items > 1 else first_item
|
||||||
show_message = show_message.replace(
|
if type(message_attribute) is str:
|
||||||
FIRST_ITEM_MARKER,
|
first_item = str(first_item.get(message_attribute, ''))
|
||||||
str(first_item.get(message_attribute, '')))
|
last_item = str(last_item.get(message_attribute, ''))
|
||||||
show_message = show_message.replace(
|
else:
|
||||||
LAST_ITEM_MARKER, str(last_item.get(message_attribute, '')))
|
for attr in message_attribute:
|
||||||
|
first_item = first_item.get(attr, {})
|
||||||
|
last_item = last_item.get(attr, {})
|
||||||
|
first_item = str(first_item)
|
||||||
|
last_item = str(last_item)
|
||||||
|
show_message = show_message.replace(FIRST_ITEM_MARKER, first_item)
|
||||||
|
show_message = show_message.replace(LAST_ITEM_MARKER, last_item)
|
||||||
sys.stderr.write('\r')
|
sys.stderr.write('\r')
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
sys.stderr.write(show_message)
|
sys.stderr.write(show_message)
|
||||||
|
5
src/gam/gapi/cloudidentity/__init__.py
Normal file
5
src/gam/gapi/cloudidentity/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import gam
|
||||||
|
|
||||||
|
|
||||||
|
def build():
|
||||||
|
return gam.buildGAPIObject('cloudidentity')
|
711
src/gam/gapi/cloudidentity/groups.py
Normal file
711
src/gam/gapi/cloudidentity/groups.py
Normal file
@ -0,0 +1,711 @@
|
|||||||
|
import csv
|
||||||
|
|
||||||
|
import gam
|
||||||
|
from gam.var import *
|
||||||
|
from gam import controlflow
|
||||||
|
from gam import display
|
||||||
|
from gam import gapi
|
||||||
|
from gam import utils
|
||||||
|
from gam.gapi import errors as gapi_errors
|
||||||
|
from gam.gapi import cloudidentity as gapi_cloudidentity
|
||||||
|
from gam.gapi.directory import customer as gapi_directory_customer
|
||||||
|
from gam.gapi.directory import groups as gapi_directory_groups
|
||||||
|
|
||||||
|
|
||||||
|
def create():
|
||||||
|
ci = gapi_cloudidentity.build()
|
||||||
|
initialGroupConfig = 'EMPTY'
|
||||||
|
gapi_directory_customer.setTrueCustomerId()
|
||||||
|
parent = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
|
||||||
|
body = {'groupKey': {
|
||||||
|
'id': gam.normalizeEmailAddressOrUID(sys.argv[3], noUid=True)
|
||||||
|
},
|
||||||
|
'parent': parent,
|
||||||
|
'labels': {'cloudidentity.googleapis.com/groups.discussion_forum': ''},
|
||||||
|
}
|
||||||
|
i = 4
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
|
if myarg == 'name':
|
||||||
|
body['displayName'] = sys.argv[i+1]
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'description':
|
||||||
|
body['description'] = sys.argv[i+1]
|
||||||
|
i += 2
|
||||||
|
elif myarg in ['alias', 'aliases']:
|
||||||
|
# As of 2020/06/25 this doesn't work (yet?)
|
||||||
|
aliases = sys.argv[i+1].split(' ')
|
||||||
|
body['additionalGroupKeys'] = []
|
||||||
|
for alias in aliases:
|
||||||
|
body['additionalGroupKeys'].append({'id': alias})
|
||||||
|
i += 2
|
||||||
|
elif myarg in ['dynamic']:
|
||||||
|
# As of 2020/06/25 this doesn't work (yet?)
|
||||||
|
body['dynamicGroupMetadata'] = {'queries': [{'query': sys.argv[i+1]}]}
|
||||||
|
i += 2
|
||||||
|
elif myarg in ['makeowner']:
|
||||||
|
initialGroupConfig = 'WITH_INITIAL_OWNER'
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
print('should not get here')
|
||||||
|
sys.exit(5)
|
||||||
|
print(f'Creating group {body["groupKey"]["id"]}')
|
||||||
|
gapi.call(ci.groups(), 'create', initialGroupConfig=initialGroupConfig,
|
||||||
|
body=body)
|
||||||
|
|
||||||
|
def delete():
|
||||||
|
ci = gapi_cloudidentity.build()
|
||||||
|
group = sys.argv[3]
|
||||||
|
name = group_email_to_id(ci, group)
|
||||||
|
print(f'Deleting group {group}')
|
||||||
|
gapi.call(ci.groups(), 'delete', name=name)
|
||||||
|
|
||||||
|
|
||||||
|
def info():
|
||||||
|
ci = gapi_cloudidentity.build()
|
||||||
|
group = gam.normalizeEmailAddressOrUID(sys.argv[3])
|
||||||
|
getUsers = True
|
||||||
|
showJoinDate = True
|
||||||
|
showUpdateDate = False
|
||||||
|
i = 4
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
|
if myarg == 'nousers':
|
||||||
|
getUsers = False
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'nojoindate':
|
||||||
|
showJoinDate = False
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'showupdatedate':
|
||||||
|
showUpdateDate = True
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(myarg, 'gam info cigroup')
|
||||||
|
name = group_email_to_id(ci, group)
|
||||||
|
basic_info = gapi.call(ci.groups(), 'get', name=name)
|
||||||
|
display.print_json(basic_info)
|
||||||
|
if getUsers:
|
||||||
|
if not showJoinDate and not showUpdateDate:
|
||||||
|
view = 'BASIC'
|
||||||
|
pageSize = 1000
|
||||||
|
else:
|
||||||
|
view = 'FULL'
|
||||||
|
pageSize = 500
|
||||||
|
members = gapi.get_all_pages(
|
||||||
|
ci.groups().memberships(),
|
||||||
|
'list',
|
||||||
|
'memberships',
|
||||||
|
parent=name,
|
||||||
|
fields='*',
|
||||||
|
pageSize=pageSize,
|
||||||
|
view=view)
|
||||||
|
print('Members:')
|
||||||
|
for member in members:
|
||||||
|
role = get_single_role(member.get('roles', [])).lower()
|
||||||
|
email = member.get('memberKey', {}).get('id')
|
||||||
|
jc_string = ''
|
||||||
|
if showJoinDate:
|
||||||
|
joined = member.get('createTime', 'Unknown')
|
||||||
|
jc_string += f' joined {joined}'
|
||||||
|
if showUpdateDate:
|
||||||
|
updated = member.get('updateTime', 'Unknown')
|
||||||
|
jc_string += f' updated {updated}'
|
||||||
|
print(
|
||||||
|
f'{role}: {email}{jc_string}'
|
||||||
|
# f' {member.get("role", ROLE_MEMBER).lower()}: {member.get("email", member["id"])} ({member["type"].lower()})'
|
||||||
|
)
|
||||||
|
print(f'Total {len(members)} users in group')
|
||||||
|
|
||||||
|
|
||||||
|
def info_member():
|
||||||
|
ci = gapi_cloudidentity.build()
|
||||||
|
member = gam.normalizeEmailAddressOrUID(sys.argv[3])
|
||||||
|
group = gam.normalizeEmailAddressOrUID(sys.argv[4])
|
||||||
|
group_name = gapi.call(ci.groups(), 'lookup',
|
||||||
|
groupKey_id=group, fields='name').get('name')
|
||||||
|
member_name = gapi.call(ci.groups().memberships(), 'lookup',
|
||||||
|
parent=group_name, memberKey_id=member,
|
||||||
|
fields='name').get('name')
|
||||||
|
member_details = gapi.call(ci.groups().memberships(), 'get',
|
||||||
|
name=member_name)
|
||||||
|
display.print_json(member_details)
|
||||||
|
|
||||||
|
|
||||||
|
UPDATE_GROUP_SUBCMDS = ['add', 'clear', 'delete', 'remove', 'sync', 'update']
|
||||||
|
GROUP_ROLES_MAP = {
|
||||||
|
'owner': ROLE_OWNER,
|
||||||
|
'owners': ROLE_OWNER,
|
||||||
|
'manager': ROLE_MANAGER,
|
||||||
|
'managers': ROLE_MANAGER,
|
||||||
|
'member': ROLE_MEMBER,
|
||||||
|
'members': ROLE_MEMBER,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def print_():
|
||||||
|
ci = gapi_cloudidentity.build()
|
||||||
|
i = 3
|
||||||
|
members = membersCountOnly = managers = managersCountOnly = owners = ownersCountOnly = False
|
||||||
|
gapi_directory_customer.setTrueCustomerId()
|
||||||
|
parent = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
|
||||||
|
aliasDelimiter = ' '
|
||||||
|
memberDelimiter = '\n'
|
||||||
|
todrive = False
|
||||||
|
titles = []
|
||||||
|
csvRows = []
|
||||||
|
roles = []
|
||||||
|
sortHeaders = False
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower()
|
||||||
|
if myarg == 'todrive':
|
||||||
|
todrive = True
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'delimiter':
|
||||||
|
aliasDelimiter = memberDelimiter = sys.argv[i + 1]
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'sortheaders':
|
||||||
|
sortHeaders = True
|
||||||
|
i += 1
|
||||||
|
elif myarg in ['members', 'memberscount']:
|
||||||
|
roles.append(ROLE_MEMBER)
|
||||||
|
members = True
|
||||||
|
if myarg == 'memberscount':
|
||||||
|
membersCountOnly = True
|
||||||
|
i += 1
|
||||||
|
elif myarg in ['owners', 'ownerscount']:
|
||||||
|
roles.append(ROLE_OWNER)
|
||||||
|
owners = True
|
||||||
|
if myarg == 'ownerscount':
|
||||||
|
ownersCountOnly = True
|
||||||
|
i += 1
|
||||||
|
elif myarg in ['managers', 'managerscount']:
|
||||||
|
roles.append(ROLE_MANAGER)
|
||||||
|
managers = True
|
||||||
|
if myarg == 'managerscount':
|
||||||
|
managersCountOnly = True
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam print cigroups')
|
||||||
|
if roles:
|
||||||
|
if members:
|
||||||
|
display.add_titles_to_csv_file([
|
||||||
|
'MembersCount',
|
||||||
|
], titles)
|
||||||
|
if not membersCountOnly:
|
||||||
|
display.add_titles_to_csv_file([
|
||||||
|
'Members',
|
||||||
|
], titles)
|
||||||
|
if managers:
|
||||||
|
display.add_titles_to_csv_file([
|
||||||
|
'ManagersCount',
|
||||||
|
], titles)
|
||||||
|
if not managersCountOnly:
|
||||||
|
display.add_titles_to_csv_file([
|
||||||
|
'Managers',
|
||||||
|
], titles)
|
||||||
|
if owners:
|
||||||
|
display.add_titles_to_csv_file([
|
||||||
|
'OwnersCount',
|
||||||
|
], titles)
|
||||||
|
if not ownersCountOnly:
|
||||||
|
display.add_titles_to_csv_file([
|
||||||
|
'Owners',
|
||||||
|
], titles)
|
||||||
|
gam.printGettingAllItems('Groups', None)
|
||||||
|
page_message = gapi.got_total_items_first_last_msg('Groups')
|
||||||
|
entityList = gapi.get_all_pages(ci.groups(),
|
||||||
|
'list',
|
||||||
|
'groups',
|
||||||
|
page_message=page_message,
|
||||||
|
message_attribute=['groupKey', 'id'],
|
||||||
|
parent=parent,
|
||||||
|
srcview='FULL',
|
||||||
|
pageSize=500)
|
||||||
|
i = 0
|
||||||
|
count = len(entityList)
|
||||||
|
for groupEntity in entityList:
|
||||||
|
i += 1
|
||||||
|
groupEmail = groupEntity['groupKey']['id']
|
||||||
|
group = utils.flatten_json(groupEntity)
|
||||||
|
for a_key in group:
|
||||||
|
if a_key not in titles:
|
||||||
|
titles.append(a_key)
|
||||||
|
groupKey_id = groupEntity['name']
|
||||||
|
if roles:
|
||||||
|
sys.stderr.write(
|
||||||
|
f' Getting {roles} for {groupEmail}{gam.currentCountNL(i, count)}')
|
||||||
|
page_message = gapi.got_total_items_first_last_msg('Members')
|
||||||
|
validRoles, listRoles, listFields = gam._getRoleVerification(
|
||||||
|
roles, 'nextPageToken,members(email,id,role)')
|
||||||
|
groupMembers = gapi.get_all_pages(ci.groups().memberships(),
|
||||||
|
'list',
|
||||||
|
'memberships',
|
||||||
|
page_message=page_message,
|
||||||
|
message_attribute='email',
|
||||||
|
soft_errors=True,
|
||||||
|
groupKey_id=groupKey_id,
|
||||||
|
view='BASIC')
|
||||||
|
if members:
|
||||||
|
membersList = []
|
||||||
|
membersCount = 0
|
||||||
|
if managers:
|
||||||
|
managersList = []
|
||||||
|
managersCount = 0
|
||||||
|
if owners:
|
||||||
|
ownersList = []
|
||||||
|
ownersCount = 0
|
||||||
|
for member in groupMembers:
|
||||||
|
member_email = member['memberKey']['id']
|
||||||
|
role = get_single_role(member.get('roles'))
|
||||||
|
if not validRoles or role in validRoles:
|
||||||
|
if role == ROLE_MEMBER:
|
||||||
|
if members:
|
||||||
|
membersCount += 1
|
||||||
|
if not membersCountOnly:
|
||||||
|
membersList.append(member_email)
|
||||||
|
elif role == ROLE_MANAGER:
|
||||||
|
if managers:
|
||||||
|
managersCount += 1
|
||||||
|
if not managersCountOnly:
|
||||||
|
managersList.append(member_email)
|
||||||
|
elif role == ROLE_OWNER:
|
||||||
|
if owners:
|
||||||
|
ownersCount += 1
|
||||||
|
if not ownersCountOnly:
|
||||||
|
ownersList.append(member_email)
|
||||||
|
elif members:
|
||||||
|
membersCount += 1
|
||||||
|
if not membersCountOnly:
|
||||||
|
membersList.append(member_email)
|
||||||
|
if members:
|
||||||
|
group['MembersCount'] = membersCount
|
||||||
|
if not membersCountOnly:
|
||||||
|
group['Members'] = memberDelimiter.join(membersList)
|
||||||
|
if managers:
|
||||||
|
group['ManagersCount'] = managersCount
|
||||||
|
if not managersCountOnly:
|
||||||
|
group['Managers'] = memberDelimiter.join(managersList)
|
||||||
|
if owners:
|
||||||
|
group['OwnersCount'] = ownersCount
|
||||||
|
if not ownersCountOnly:
|
||||||
|
group['Owners'] = memberDelimiter.join(ownersList)
|
||||||
|
csvRows.append(group)
|
||||||
|
if sortHeaders:
|
||||||
|
display.sort_csv_titles([
|
||||||
|
'Email',
|
||||||
|
], titles)
|
||||||
|
display.write_csv_file(csvRows, titles, 'Groups', todrive)
|
||||||
|
|
||||||
|
|
||||||
|
def print_members():
|
||||||
|
ci = gapi_cloudidentity.build()
|
||||||
|
todrive = False
|
||||||
|
gapi_directory_customer.setTrueCustomerId()
|
||||||
|
parent = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
|
||||||
|
roles = []
|
||||||
|
titles = ['group']
|
||||||
|
csvRows = []
|
||||||
|
groups_to_get = []
|
||||||
|
i = 3
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
|
if myarg == 'todrive':
|
||||||
|
todrive = True
|
||||||
|
i += 1
|
||||||
|
elif myarg in ['role', 'roles']:
|
||||||
|
for role in sys.argv[i + 1].lower().replace(',', ' ').split():
|
||||||
|
if role in GROUP_ROLES_MAP:
|
||||||
|
roles.append(GROUP_ROLES_MAP[role])
|
||||||
|
else:
|
||||||
|
controlflow.system_error_exit(
|
||||||
|
2,
|
||||||
|
f'{role} is not a valid role for "gam print group-members {myarg}"'
|
||||||
|
)
|
||||||
|
i += 2
|
||||||
|
elif myarg in ['cigroup', 'cigroups']:
|
||||||
|
group_email = gam.normalizeEmailAddressOrUID(sys.argv[i + 1])
|
||||||
|
groups_to_get = [group_email]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i],
|
||||||
|
'gam print cigroup-members')
|
||||||
|
if not groups_to_get:
|
||||||
|
gam.printGettingAllItems('Groups', None)
|
||||||
|
page_message = gapi.got_total_items_first_last_msg('Groups')
|
||||||
|
groups_to_get = gapi.get_all_pages(ci.groups(),
|
||||||
|
'list',
|
||||||
|
'groups',
|
||||||
|
message_attribute=['groupKey', 'id'],
|
||||||
|
page_message=page_message,
|
||||||
|
parent=parent,
|
||||||
|
view='BASIC',
|
||||||
|
pageSize=1000,
|
||||||
|
fields='nextPageToken,groups(groupKey(id))')
|
||||||
|
groups_to_get = [group['groupKey']['id'] for group in groups_to_get]
|
||||||
|
i = 0
|
||||||
|
count = len(groups_to_get)
|
||||||
|
for group_email in groups_to_get:
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
sys.stderr.write(
|
||||||
|
f'Getting members for {group_email}{gam.currentCountNL(i, count)}')
|
||||||
|
group_id = group_email_to_id(ci, group_email)
|
||||||
|
print(f'Getting members of cigroup {group_email}...')
|
||||||
|
page_message = f' {gapi.got_total_items_first_last_msg("Members")}'
|
||||||
|
group_members = gapi.get_all_pages(
|
||||||
|
ci.groups().memberships(),
|
||||||
|
'list',
|
||||||
|
'memberships',
|
||||||
|
soft_errors=True,
|
||||||
|
parent=group_id,
|
||||||
|
view='FULL',
|
||||||
|
pageSize=500,
|
||||||
|
page_message=page_message,
|
||||||
|
message_attribute=['memberKey', 'id'])
|
||||||
|
#fields='nextPageToken,memberships(memberKey,roles,createTime,updateTime)')
|
||||||
|
if roles:
|
||||||
|
group_members = filter_members_to_roles(group_members, roles)
|
||||||
|
for member in group_members:
|
||||||
|
# reduce role to a single value
|
||||||
|
member['role'] = get_single_role(member.pop('roles'))
|
||||||
|
member = utils.flatten_json(member)
|
||||||
|
for title in member:
|
||||||
|
if title not in titles:
|
||||||
|
titles.append(title)
|
||||||
|
member['group'] = group_email
|
||||||
|
csvRows.append(member)
|
||||||
|
display.write_csv_file(csvRows, titles, 'Group Members', todrive)
|
||||||
|
|
||||||
|
|
||||||
|
def update():
|
||||||
|
|
||||||
|
# Convert foo@googlemail.com to foo@gmail.com; eliminate periods in name for foo.bar@gmail.com
|
||||||
|
def _cleanConsumerAddress(emailAddress, mapCleanToOriginal):
|
||||||
|
atLoc = emailAddress.find('@')
|
||||||
|
if atLoc > 0:
|
||||||
|
if emailAddress[atLoc + 1:] in ['gmail.com', 'googlemail.com']:
|
||||||
|
cleanEmailAddress = emailAddress[:atLoc].replace(
|
||||||
|
'.', '') + '@gmail.com'
|
||||||
|
if cleanEmailAddress != emailAddress:
|
||||||
|
mapCleanToOriginal[cleanEmailAddress] = emailAddress
|
||||||
|
return cleanEmailAddress
|
||||||
|
return emailAddress
|
||||||
|
|
||||||
|
def _getRoleAndUsers():
|
||||||
|
checkSuspended = None
|
||||||
|
role = None
|
||||||
|
i = 5
|
||||||
|
if sys.argv[i].lower() in GROUP_ROLES_MAP:
|
||||||
|
role = GROUP_ROLES_MAP[sys.argv[i].lower()]
|
||||||
|
i += 1
|
||||||
|
if sys.argv[i].lower() in ['suspended', 'notsuspended']:
|
||||||
|
checkSuspended = sys.argv[i].lower() == 'suspended'
|
||||||
|
i += 1
|
||||||
|
if sys.argv[i].lower() in usergroup_types:
|
||||||
|
users_email = gam.getUsersToModify(entity_type=sys.argv[i].lower(),
|
||||||
|
entity=sys.argv[i + 1],
|
||||||
|
checkSuspended=checkSuspended,
|
||||||
|
groupUserMembersOnly=False)
|
||||||
|
else:
|
||||||
|
users_email = [
|
||||||
|
gam.normalizeEmailAddressOrUID(sys.argv[i],
|
||||||
|
checkForCustomerId=True)
|
||||||
|
]
|
||||||
|
return (role, users_email)
|
||||||
|
|
||||||
|
ci = gapi_cloudidentity.build()
|
||||||
|
group = sys.argv[3]
|
||||||
|
myarg = sys.argv[4].lower()
|
||||||
|
items = []
|
||||||
|
if myarg in UPDATE_GROUP_SUBCMDS:
|
||||||
|
group = gam.normalizeEmailAddressOrUID(group)
|
||||||
|
if group.startswith('groups/'):
|
||||||
|
parent = group
|
||||||
|
else:
|
||||||
|
parent = group_email_to_id(ci, group)
|
||||||
|
if not parent:
|
||||||
|
return
|
||||||
|
if myarg == 'add':
|
||||||
|
role, users_email = _getRoleAndUsers()
|
||||||
|
if not role:
|
||||||
|
role = ROLE_MEMBER
|
||||||
|
if len(users_email) > 1:
|
||||||
|
sys.stderr.write(
|
||||||
|
f'Group: {group}, Will add {len(users_email)} {role}s.\n')
|
||||||
|
for user_email in users_email:
|
||||||
|
item = ['gam', 'update', 'cigroup', f'id:{parent}', 'add', role, user_email]
|
||||||
|
items.append(item)
|
||||||
|
elif len(users_email) > 0:
|
||||||
|
body = {
|
||||||
|
'memberKey': {
|
||||||
|
'id': users_email[0]
|
||||||
|
},
|
||||||
|
'roles': [{
|
||||||
|
'name': ROLE_MEMBER
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
if role != ROLE_MEMBER:
|
||||||
|
body['roles'].append({'name': role})
|
||||||
|
add_text = [f'as {role}']
|
||||||
|
for i in range(2):
|
||||||
|
try:
|
||||||
|
gapi.call(
|
||||||
|
ci.groups().memberships(),
|
||||||
|
'create',
|
||||||
|
throw_reasons=[
|
||||||
|
gapi_errors.ErrorReason.FOUR_O_NINE,
|
||||||
|
gapi_errors.ErrorReason.MEMBER_NOT_FOUND,
|
||||||
|
gapi_errors.ErrorReason.RESOURCE_NOT_FOUND,
|
||||||
|
gapi_errors.ErrorReason.INVALID_MEMBER,
|
||||||
|
gapi_errors.ErrorReason.
|
||||||
|
CYCLIC_MEMBERSHIPS_NOT_ALLOWED
|
||||||
|
],
|
||||||
|
parent=parent,
|
||||||
|
body=body)
|
||||||
|
print(
|
||||||
|
f' Group: {group}, {users_email[0]} Added {" ".join(add_text)}'
|
||||||
|
)
|
||||||
|
break
|
||||||
|
except (gapi_errors.GapiMemberNotFoundError,
|
||||||
|
gapi_errors.GapiResourceNotFoundError,
|
||||||
|
gapi_errors.GapiInvalidMemberError,
|
||||||
|
gapi_errors.GapiCyclicMembershipsNotAllowedError
|
||||||
|
) as e:
|
||||||
|
print(
|
||||||
|
f' Group: {group}, {users_email[0]} Add {" ".join(add_text)} Failed: {str(e)}'
|
||||||
|
)
|
||||||
|
break
|
||||||
|
elif myarg == 'sync':
|
||||||
|
syncMembersSet = set()
|
||||||
|
syncMembersMap = {}
|
||||||
|
role, users_email = _getRoleAndUsers()
|
||||||
|
for user_email in users_email:
|
||||||
|
if user_email in ('*', GC_Values[GC_CUSTOMER_ID]):
|
||||||
|
syncMembersSet.add(GC_Values[GC_CUSTOMER_ID])
|
||||||
|
else:
|
||||||
|
syncMembersSet.add(
|
||||||
|
_cleanConsumerAddress(user_email.lower(),
|
||||||
|
syncMembersMap))
|
||||||
|
currentMembersSet = set()
|
||||||
|
currentMembersMap = {}
|
||||||
|
for current_email in gam.getUsersToModify(
|
||||||
|
entity_type='cigroup',
|
||||||
|
entity=group,
|
||||||
|
member_type=role,
|
||||||
|
groupUserMembersOnly=False):
|
||||||
|
if current_email == GC_Values[GC_CUSTOMER_ID]:
|
||||||
|
currentMembersSet.add(current_email)
|
||||||
|
else:
|
||||||
|
currentMembersSet.add(
|
||||||
|
_cleanConsumerAddress(current_email.lower(),
|
||||||
|
currentMembersMap))
|
||||||
|
to_add = [
|
||||||
|
syncMembersMap.get(emailAddress, emailAddress)
|
||||||
|
for emailAddress in syncMembersSet - currentMembersSet
|
||||||
|
]
|
||||||
|
to_remove = [
|
||||||
|
currentMembersMap.get(emailAddress, emailAddress)
|
||||||
|
for emailAddress in currentMembersSet - syncMembersSet
|
||||||
|
]
|
||||||
|
sys.stderr.write(
|
||||||
|
f'Group: {group}, Will add {len(to_add)} and remove {len(to_remove)} {role}s.\n'
|
||||||
|
)
|
||||||
|
for user in to_add:
|
||||||
|
item = ['gam', 'update', 'cigroup', f'id:{parent}', 'add', role, user]
|
||||||
|
items.append(item)
|
||||||
|
for user in to_remove:
|
||||||
|
items.append(
|
||||||
|
['gam', 'update', 'cigroup', f'id:{parent}', 'remove', user])
|
||||||
|
elif myarg in ['delete', 'remove']:
|
||||||
|
_, users_email = _getRoleAndUsers()
|
||||||
|
if len(users_email) > 1:
|
||||||
|
sys.stderr.write(
|
||||||
|
f'Group: {group}, Will remove {len(users_email)} emails.\n')
|
||||||
|
for user_email in users_email:
|
||||||
|
items.append(
|
||||||
|
['gam', 'update', 'cigroup', f'id:{parent}', 'remove', user_email])
|
||||||
|
elif len(users_email) == 1:
|
||||||
|
name = membership_email_to_id(ci, parent, users_email[0])
|
||||||
|
try:
|
||||||
|
gapi.call(ci.groups().memberships(),
|
||||||
|
'delete',
|
||||||
|
throw_reasons=[
|
||||||
|
gapi_errors.ErrorReason.MEMBER_NOT_FOUND,
|
||||||
|
gapi_errors.ErrorReason.INVALID_MEMBER
|
||||||
|
],
|
||||||
|
name=name)
|
||||||
|
print(f' Group: {group}, {users_email[0]} Removed')
|
||||||
|
except (gapi_errors.GapiMemberNotFoundError,
|
||||||
|
gapi_errors.GapiInvalidMemberError) as e:
|
||||||
|
print(
|
||||||
|
f' Group: {group}, {users_email[0]} Remove Failed: {str(e)}'
|
||||||
|
)
|
||||||
|
elif myarg == 'update':
|
||||||
|
role, users_email = _getRoleAndUsers()
|
||||||
|
if not role:
|
||||||
|
role = ROLE_MEMBER
|
||||||
|
if len(users_email) > 1:
|
||||||
|
sys.stderr.write(
|
||||||
|
f'Group: {group}, Will update {len(users_email)} {role}s.\n'
|
||||||
|
)
|
||||||
|
for user_email in users_email:
|
||||||
|
item = ['gam', 'update', 'cigroup', f'id:{parent}', 'update', role, user_email]
|
||||||
|
items.append(item)
|
||||||
|
elif len(users_email) > 0:
|
||||||
|
name = membership_email_to_id(ci, parent, users_email[0])
|
||||||
|
addRoles = []
|
||||||
|
removeRoles = []
|
||||||
|
new_role = {'role': role}
|
||||||
|
current_roles = gapi.call(ci.groups().memberships(), 'get', name=name,
|
||||||
|
fields='roles').get('roles', [])
|
||||||
|
current_roles = [role['name'] for role in current_roles]
|
||||||
|
for crole in current_roles:
|
||||||
|
if crole != ROLE_MEMBER and crole != role:
|
||||||
|
removeRoles.append(crole)
|
||||||
|
if role not in current_roles:
|
||||||
|
addRoles.append({'name': role})
|
||||||
|
bodys = []
|
||||||
|
if addRoles:
|
||||||
|
bodys.append({'addRoles': addRoles})
|
||||||
|
if removeRoles:
|
||||||
|
bodys.append({'removeRoles': removeRoles})
|
||||||
|
for body in bodys:
|
||||||
|
try:
|
||||||
|
gapi.call(ci.groups().memberships(),
|
||||||
|
'modifyMembershipRoles',
|
||||||
|
throw_reasons=[
|
||||||
|
gapi_errors.ErrorReason.MEMBER_NOT_FOUND,
|
||||||
|
gapi_errors.ErrorReason.INVALID_MEMBER
|
||||||
|
],
|
||||||
|
name=name,
|
||||||
|
body=body)
|
||||||
|
except (gapi_errors.GapiMemberNotFoundError,
|
||||||
|
gapi_errors.GapiInvalidMemberError) as e:
|
||||||
|
print(
|
||||||
|
f' Group: {group}, {users_email[0]} Update to {role} Failed: {str(e)}'
|
||||||
|
)
|
||||||
|
break
|
||||||
|
print(
|
||||||
|
f' Group: {group}, {users_email[0]} Updated to {role}'
|
||||||
|
)
|
||||||
|
|
||||||
|
else: # clear
|
||||||
|
roles = []
|
||||||
|
i = 5
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower()
|
||||||
|
if myarg.upper() in [ROLE_OWNER, ROLE_MANAGER, ROLE_MEMBER]:
|
||||||
|
roles.append(myarg.upper())
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i],
|
||||||
|
'gam update cigroup clear')
|
||||||
|
if not roles:
|
||||||
|
roles = [ROLE_MEMBER]
|
||||||
|
group = gam.normalizeEmailAddressOrUID(group)
|
||||||
|
member_type_message = f'{",".join(roles).lower()}s'
|
||||||
|
sys.stderr.write(
|
||||||
|
f'Getting {member_type_message} of {group} (may take some time for large groups)...\n'
|
||||||
|
)
|
||||||
|
page_message = gapi.got_total_items_msg(f'{member_type_message}',
|
||||||
|
'...')
|
||||||
|
try:
|
||||||
|
result = gapi.get_all_pages(
|
||||||
|
ci.groups().memberships(),
|
||||||
|
'list',
|
||||||
|
'memberships',
|
||||||
|
page_message=page_message,
|
||||||
|
throw_reasons=gapi_errors.MEMBERS_THROW_REASONS,
|
||||||
|
parent=parent,
|
||||||
|
fields='nextPageToken,memberships(memberKey,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]
|
||||||
|
sys.stderr.write(
|
||||||
|
f'Group: {group}, Will remove {len(users_email)} {", ".join(roles).lower()}s.\n'
|
||||||
|
)
|
||||||
|
for user_email in users_email:
|
||||||
|
items.append(['gam', 'update', 'cigroup', group, 'remove', user_email])
|
||||||
|
except (gapi_errors.GapiGroupNotFoundError,
|
||||||
|
gapi_errors.GapiDomainNotFoundError,
|
||||||
|
gapi_errors.GapiInvalidError,
|
||||||
|
gapi_errors.GapiForbiddenError):
|
||||||
|
gam.entityUnknownWarning('Group', group, 0, 0)
|
||||||
|
if items:
|
||||||
|
gam.run_batch(items)
|
||||||
|
else:
|
||||||
|
i = 4
|
||||||
|
body = {}
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
|
if myarg == 'name':
|
||||||
|
body['displayName'] = sys.argv[i+1]
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'description':
|
||||||
|
body['description'] = sys.argv[i+1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i],
|
||||||
|
'gam update cigroup')
|
||||||
|
updateMask = ','.join(body.keys())
|
||||||
|
name = group_email_to_id(ci, group)
|
||||||
|
print(f'Updating group {group}')
|
||||||
|
gapi.call(ci.groups(), 'patch', updateMask=updateMask, name=name,
|
||||||
|
body=body)
|
||||||
|
|
||||||
|
|
||||||
|
def group_email_to_id(ci, group, i=0, count=0):
|
||||||
|
group = gam.normalizeEmailAddressOrUID(group)
|
||||||
|
try:
|
||||||
|
return gapi.call(ci.groups(),
|
||||||
|
'lookup',
|
||||||
|
throw_reasons=gapi_errors.GROUP_GET_THROW_REASONS,
|
||||||
|
retry_reasons=gapi_errors.GROUP_GET_RETRY_REASONS,
|
||||||
|
groupKey_id=group,
|
||||||
|
fields='name').get('name')
|
||||||
|
except (gapi_errors.GapiGroupNotFoundError,
|
||||||
|
gapi_errors.GapiDomainNotFoundError,
|
||||||
|
gapi_errors.GapiDomainCannotUseApisError,
|
||||||
|
gapi_errors.GapiForbiddenError, gapi_errors.GapiBadRequestError):
|
||||||
|
entityUnknownWarning('Group', group, i, count)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def membership_email_to_id(ci, parent, membership, i=0, count=0):
|
||||||
|
membership = gam.normalizeEmailAddressOrUID(membership)
|
||||||
|
try:
|
||||||
|
return gapi.call(ci.groups().memberships(),
|
||||||
|
'lookup',
|
||||||
|
throw_reasons=gapi_errors.GROUP_GET_THROW_REASONS,
|
||||||
|
retry_reasons=gapi_errors.GROUP_GET_RETRY_REASONS,
|
||||||
|
parent=parent,
|
||||||
|
memberKey_id=membership,
|
||||||
|
fields='name').get('name')
|
||||||
|
except (gapi_errors.GapiGroupNotFoundError,
|
||||||
|
gapi_errors.GapiDomainNotFoundError,
|
||||||
|
gapi_errors.GapiDomainCannotUseApisError,
|
||||||
|
gapi_errors.GapiForbiddenError, gapi_errors.GapiBadRequestError):
|
||||||
|
entityUnknownWarning('Membership', member_email, i, count)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_single_role(roles):
|
||||||
|
''' returns the highest role of member '''
|
||||||
|
roles = [role.get('name') for role in roles]
|
||||||
|
if not roles:
|
||||||
|
return
|
||||||
|
for a_role in [ROLE_OWNER, ROLE_MANAGER, ROLE_MEMBER]:
|
||||||
|
if a_role in roles:
|
||||||
|
return a_role
|
||||||
|
return roles[0]
|
||||||
|
|
||||||
|
def filter_members_to_roles(members, roles):
|
||||||
|
filtered_members = []
|
||||||
|
for member in members:
|
||||||
|
role = get_single_role(member.get('roles', []))
|
||||||
|
if role in roles:
|
||||||
|
filtered_members.include(member)
|
||||||
|
return filtered_members
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
import gam
|
import gam
|
||||||
|
|
||||||
|
|
||||||
def buildGAPIObject():
|
def build():
|
||||||
return gam.buildGAPIObject('directory')
|
return gam.buildGAPIObject('directory')
|
||||||
|
@ -7,8 +7,8 @@ from gam.gapi import directory as gapi_directory
|
|||||||
from gam import utils
|
from gam import utils
|
||||||
|
|
||||||
|
|
||||||
def get(users):
|
def info(users):
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
for user in users:
|
for user in users:
|
||||||
asps = gapi.get_items(cd.asps(), 'list', 'items', userKey=user)
|
asps = gapi.get_items(cd.asps(), 'list', 'items', userKey=user)
|
||||||
if asps:
|
if asps:
|
||||||
@ -34,7 +34,7 @@ def get(users):
|
|||||||
|
|
||||||
def delete(users, cd=None, codeIdList=None):
|
def delete(users, cd=None, codeIdList=None):
|
||||||
if not cd:
|
if not cd:
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
if not codeIdList:
|
if not codeIdList:
|
||||||
codeIdList = sys.argv[5].lower()
|
codeIdList = sys.argv[5].lower()
|
||||||
if codeIdList == 'all':
|
if codeIdList == 'all':
|
||||||
|
@ -11,7 +11,7 @@ from gam import utils
|
|||||||
|
|
||||||
|
|
||||||
def doUpdateCros():
|
def doUpdateCros():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
i, devices = getCrOSDeviceEntity(3, cd)
|
i, devices = getCrOSDeviceEntity(3, cd)
|
||||||
update_body = {}
|
update_body = {}
|
||||||
action_body = {}
|
action_body = {}
|
||||||
@ -52,15 +52,11 @@ def doUpdateCros():
|
|||||||
elif action in ['deprovisionretiringdevice']:
|
elif action in ['deprovisionretiringdevice']:
|
||||||
action = 'deprovision'
|
action = 'deprovision'
|
||||||
deprovisionReason = 'retiring_device'
|
deprovisionReason = 'retiring_device'
|
||||||
elif action == 'deprovisionupgradetransfer':
|
|
||||||
action = 'deprovision'
|
|
||||||
deprovisionReason = 'upgrade_transfer'
|
|
||||||
elif action not in ['disable', 'reenable']:
|
elif action not in ['disable', 'reenable']:
|
||||||
controlflow.system_error_exit(2, f'expected action of ' \
|
controlflow.system_error_exit(2, f'expected action of ' \
|
||||||
f'deprovision_same_model_replace, ' \
|
f'deprovision_same_model_replace, ' \
|
||||||
f'deprovision_different_model_replace, ' \
|
f'deprovision_different_model_replace, ' \
|
||||||
f'deprovision_retiring_device, ' \
|
f'deprovision_retiring_device, disable or reenable,'
|
||||||
f'deprovision_upgrade_transfer, disable or reenable,'
|
|
||||||
f' got {action}')
|
f' got {action}')
|
||||||
action_body = {'action': action}
|
action_body = {'action': action}
|
||||||
if deprovisionReason:
|
if deprovisionReason:
|
||||||
@ -124,7 +120,7 @@ def doUpdateCros():
|
|||||||
|
|
||||||
|
|
||||||
def doGetCrosInfo():
|
def doGetCrosInfo():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
i, devices = getCrOSDeviceEntity(3, cd)
|
i, devices = getCrOSDeviceEntity(3, cd)
|
||||||
downloadfile = None
|
downloadfile = None
|
||||||
targetFolder = GC_Values[GC_DRIVE_DIR]
|
targetFolder = GC_Values[GC_DRIVE_DIR]
|
||||||
@ -334,7 +330,7 @@ def doGetCrosInfo():
|
|||||||
|
|
||||||
|
|
||||||
def doPrintCrosActivity():
|
def doPrintCrosActivity():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
todrive = False
|
todrive = False
|
||||||
titles = [
|
titles = [
|
||||||
'deviceId', 'annotatedAssetId', 'annotatedLocation', 'serialNumber',
|
'deviceId', 'annotatedAssetId', 'annotatedLocation', 'serialNumber',
|
||||||
@ -505,7 +501,7 @@ def doPrintCrosDevices():
|
|||||||
elif myarg in CROS_SYSTEM_RAM_FREE_REPORTS_ARGUMENTS:
|
elif myarg in CROS_SYSTEM_RAM_FREE_REPORTS_ARGUMENTS:
|
||||||
selectedLists['systemRamFreeReports'] = True
|
selectedLists['systemRamFreeReports'] = True
|
||||||
|
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
todrive = False
|
todrive = False
|
||||||
fieldsList = []
|
fieldsList = []
|
||||||
fieldsTitles = {}
|
fieldsTitles = {}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
import gam
|
||||||
from gam.var import *
|
from gam.var import *
|
||||||
from gam import controlflow
|
from gam import controlflow
|
||||||
from gam import gapi
|
from gam import gapi
|
||||||
@ -8,7 +9,7 @@ from gam.gapi import reports as gapi_reports
|
|||||||
|
|
||||||
|
|
||||||
def doGetCustomerInfo():
|
def doGetCustomerInfo():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
customer_info = gapi.call(cd.customers(),
|
customer_info = gapi.call(cd.customers(),
|
||||||
'get',
|
'get',
|
||||||
customerKey=GC_Values[GC_CUSTOMER_ID])
|
customerKey=GC_Values[GC_CUSTOMER_ID])
|
||||||
@ -69,7 +70,7 @@ def doGetCustomerInfo():
|
|||||||
customerId = GC_Values[GC_CUSTOMER_ID]
|
customerId = GC_Values[GC_CUSTOMER_ID]
|
||||||
if customerId == MY_CUSTOMER:
|
if customerId == MY_CUSTOMER:
|
||||||
customerId = None
|
customerId = None
|
||||||
rep = gapi_reports.buildGAPIObject()
|
rep = gapi_reports.build()
|
||||||
usage = None
|
usage = None
|
||||||
throw_reasons = [
|
throw_reasons = [
|
||||||
gapi.errors.ErrorReason.INVALID, gapi.errors.ErrorReason.FORBIDDEN
|
gapi.errors.ErrorReason.INVALID, gapi.errors.ErrorReason.FORBIDDEN
|
||||||
@ -108,7 +109,7 @@ def doGetCustomerInfo():
|
|||||||
|
|
||||||
|
|
||||||
def doUpdateCustomer():
|
def doUpdateCustomer():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
body = {}
|
body = {}
|
||||||
i = 3
|
i = 3
|
||||||
while i < len(sys.argv):
|
while i < len(sys.argv):
|
||||||
@ -138,3 +139,11 @@ def doUpdateCustomer():
|
|||||||
customerKey=GC_Values[GC_CUSTOMER_ID],
|
customerKey=GC_Values[GC_CUSTOMER_ID],
|
||||||
body=body)
|
body=body)
|
||||||
print('Updated customer')
|
print('Updated customer')
|
||||||
|
|
||||||
|
|
||||||
|
def setTrueCustomerId():
|
||||||
|
if GC_Values[GC_CUSTOMER_ID] == MY_CUSTOMER:
|
||||||
|
cd = gapi_directory.build()
|
||||||
|
GC_Values[GC_CUSTOMER_ID] = gapi.call(cd.customers(), 'get',
|
||||||
|
customerKey=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
fields='id').get('id', GC_Values[GC_CUSTOMER_ID])
|
||||||
|
@ -9,7 +9,7 @@ from gam import utils
|
|||||||
|
|
||||||
|
|
||||||
def create():
|
def create():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
body = {'domainAliasName': sys.argv[3], 'parentDomainName': sys.argv[4]}
|
body = {'domainAliasName': sys.argv[3], 'parentDomainName': sys.argv[4]}
|
||||||
print(f'Adding {body["domainAliasName"]} alias for ' \
|
print(f'Adding {body["domainAliasName"]} alias for ' \
|
||||||
f'{body["parentDomainName"]}')
|
f'{body["parentDomainName"]}')
|
||||||
@ -20,7 +20,7 @@ def create():
|
|||||||
|
|
||||||
|
|
||||||
def delete():
|
def delete():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
domainAliasName = sys.argv[3]
|
domainAliasName = sys.argv[3]
|
||||||
print(f'Deleting domain alias {domainAliasName}')
|
print(f'Deleting domain alias {domainAliasName}')
|
||||||
gapi.call(cd.domainAliases(),
|
gapi.call(cd.domainAliases(),
|
||||||
@ -30,7 +30,7 @@ def delete():
|
|||||||
|
|
||||||
|
|
||||||
def info():
|
def info():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
alias = sys.argv[3]
|
alias = sys.argv[3]
|
||||||
result = gapi.call(cd.domainAliases(),
|
result = gapi.call(cd.domainAliases(),
|
||||||
'get',
|
'get',
|
||||||
@ -43,7 +43,7 @@ def info():
|
|||||||
|
|
||||||
|
|
||||||
def print_():
|
def print_():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
todrive = False
|
todrive = False
|
||||||
titles = [
|
titles = [
|
||||||
'domainAliasName',
|
'domainAliasName',
|
||||||
|
@ -10,7 +10,7 @@ from gam import utils
|
|||||||
|
|
||||||
|
|
||||||
def create():
|
def create():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
domain_name = sys.argv[3]
|
domain_name = sys.argv[3]
|
||||||
body = {'domainName': domain_name}
|
body = {'domainName': domain_name}
|
||||||
gapi.call(cd.domains(),
|
gapi.call(cd.domains(),
|
||||||
@ -24,7 +24,7 @@ def info():
|
|||||||
if (len(sys.argv) < 4) or (sys.argv[3] == 'logo'):
|
if (len(sys.argv) < 4) or (sys.argv[3] == 'logo'):
|
||||||
gapi_directory_customer.doGetCustomerInfo()
|
gapi_directory_customer.doGetCustomerInfo()
|
||||||
return
|
return
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
domainName = sys.argv[3]
|
domainName = sys.argv[3]
|
||||||
result = gapi.call(cd.domains(),
|
result = gapi.call(cd.domains(),
|
||||||
'get',
|
'get',
|
||||||
@ -43,7 +43,7 @@ def info():
|
|||||||
|
|
||||||
|
|
||||||
def update():
|
def update():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
domain_name = sys.argv[3]
|
domain_name = sys.argv[3]
|
||||||
i = 4
|
i = 4
|
||||||
body = {}
|
body = {}
|
||||||
@ -62,7 +62,7 @@ def update():
|
|||||||
|
|
||||||
|
|
||||||
def delete():
|
def delete():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
domainName = sys.argv[3]
|
domainName = sys.argv[3]
|
||||||
print(f'Deleting domain {domainName}')
|
print(f'Deleting domain {domainName}')
|
||||||
gapi.call(cd.domains(),
|
gapi.call(cd.domains(),
|
||||||
@ -72,7 +72,7 @@ def delete():
|
|||||||
|
|
||||||
|
|
||||||
def print_():
|
def print_():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
todrive = False
|
todrive = False
|
||||||
titles = [
|
titles = [
|
||||||
'domainName',
|
'domainName',
|
||||||
|
1246
src/gam/gapi/directory/groups.py
Normal file
1246
src/gam/gapi/directory/groups.py
Normal file
File diff suppressed because it is too large
Load Diff
239
src/gam/gapi/directory/mobiledevices.py
Normal file
239
src/gam/gapi/directory/mobiledevices.py
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
import sys
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import gam
|
||||||
|
from gam.var import *
|
||||||
|
from gam import controlflow
|
||||||
|
from gam import display
|
||||||
|
from gam import gapi
|
||||||
|
from gam.gapi import directory as gapi_directory
|
||||||
|
from gam import utils
|
||||||
|
|
||||||
|
|
||||||
|
def delete():
|
||||||
|
cd = gapi_directory.build()
|
||||||
|
resourceId = sys.argv[3]
|
||||||
|
gapi.call(cd.mobiledevices(),
|
||||||
|
'delete',
|
||||||
|
resourceId=resourceId,
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def info():
|
||||||
|
cd = gapi_directory.build()
|
||||||
|
resourceId = sys.argv[3]
|
||||||
|
info = gapi.call(cd.mobiledevices(),
|
||||||
|
'get',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
resourceId=resourceId)
|
||||||
|
if 'deviceId' in info:
|
||||||
|
info['deviceId'] = info['deviceId'].encode('unicode-escape').decode(
|
||||||
|
UTF8)
|
||||||
|
attrib = 'securityPatchLevel'
|
||||||
|
if attrib in info and int(info[attrib]):
|
||||||
|
info[attrib] = utils.formatTimestampYMDHMS(info[attrib])
|
||||||
|
display.print_json(info)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def print_():
|
||||||
|
cd = gapi_directory.build()
|
||||||
|
todrive = False
|
||||||
|
titles = []
|
||||||
|
csvRows = []
|
||||||
|
fields = None
|
||||||
|
projection = orderBy = sortOrder = None
|
||||||
|
queries = [None]
|
||||||
|
delimiter = ' '
|
||||||
|
listLimit = 1
|
||||||
|
appsLimit = -1
|
||||||
|
i = 3
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
|
if myarg == 'todrive':
|
||||||
|
todrive = True
|
||||||
|
i += 1
|
||||||
|
elif myarg in ['query', 'queries']:
|
||||||
|
queries = gam.getQueries(myarg, sys.argv[i + 1])
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'delimiter':
|
||||||
|
delimiter = sys.argv[i + 1]
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'listlimit':
|
||||||
|
listLimit = gam.getInteger(sys.argv[i + 1], myarg, minVal=-1)
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'appslimit':
|
||||||
|
appsLimit = gam.getInteger(sys.argv[i + 1], myarg, minVal=-1)
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'fields':
|
||||||
|
fields = f'nextPageToken,mobiledevices({sys.argv[i+1]})'
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'orderby':
|
||||||
|
orderBy = sys.argv[i + 1].lower()
|
||||||
|
validOrderBy = [
|
||||||
|
'deviceid', 'email', 'lastsync', 'model', 'name', 'os',
|
||||||
|
'status', 'type'
|
||||||
|
]
|
||||||
|
if orderBy not in validOrderBy:
|
||||||
|
controlflow.expected_argument_exit('orderby',
|
||||||
|
', '.join(validOrderBy),
|
||||||
|
orderBy)
|
||||||
|
if orderBy == 'lastsync':
|
||||||
|
orderBy = 'lastSync'
|
||||||
|
elif orderBy == 'deviceid':
|
||||||
|
orderBy = 'deviceId'
|
||||||
|
i += 2
|
||||||
|
elif myarg in SORTORDER_CHOICES_MAP:
|
||||||
|
sortOrder = SORTORDER_CHOICES_MAP[myarg]
|
||||||
|
i += 1
|
||||||
|
elif myarg in PROJECTION_CHOICES_MAP:
|
||||||
|
projection = PROJECTION_CHOICES_MAP[myarg]
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam print mobile')
|
||||||
|
for query in queries:
|
||||||
|
gam.printGettingAllItems('Mobile Devices', query)
|
||||||
|
page_message = gapi.got_total_items_msg('Mobile Devices', '...\n')
|
||||||
|
all_mobile = gapi.get_all_pages(cd.mobiledevices(),
|
||||||
|
'list',
|
||||||
|
'mobiledevices',
|
||||||
|
page_message=page_message,
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
query=query,
|
||||||
|
projection=projection,
|
||||||
|
fields=fields,
|
||||||
|
orderBy=orderBy,
|
||||||
|
sortOrder=sortOrder)
|
||||||
|
for mobile in all_mobile:
|
||||||
|
row = {}
|
||||||
|
for attrib in mobile:
|
||||||
|
if attrib in ['kind', 'etag']:
|
||||||
|
continue
|
||||||
|
if attrib in ['name', 'email', 'otherAccountsInfo']:
|
||||||
|
if attrib not in titles:
|
||||||
|
titles.append(attrib)
|
||||||
|
if listLimit > 0:
|
||||||
|
row[attrib] = delimiter.join(
|
||||||
|
mobile[attrib][0:listLimit])
|
||||||
|
elif listLimit == 0:
|
||||||
|
row[attrib] = delimiter.join(mobile[attrib])
|
||||||
|
elif attrib == 'applications':
|
||||||
|
if appsLimit >= 0:
|
||||||
|
if attrib not in titles:
|
||||||
|
titles.append(attrib)
|
||||||
|
applications = []
|
||||||
|
j = 0
|
||||||
|
for app in mobile[attrib]:
|
||||||
|
j += 1
|
||||||
|
if appsLimit and (j > appsLimit):
|
||||||
|
break
|
||||||
|
appDetails = []
|
||||||
|
for field in [
|
||||||
|
'displayName', 'packageName', 'versionName'
|
||||||
|
]:
|
||||||
|
appDetails.append(app.get(field, '<None>'))
|
||||||
|
appDetails.append(
|
||||||
|
str(app.get('versionCode', '<None>')))
|
||||||
|
permissions = app.get('permission', [])
|
||||||
|
if permissions:
|
||||||
|
appDetails.append('/'.join(permissions))
|
||||||
|
else:
|
||||||
|
appDetails.append('<None>')
|
||||||
|
applications.append('-'.join(appDetails))
|
||||||
|
row[attrib] = delimiter.join(applications)
|
||||||
|
else:
|
||||||
|
if attrib not in titles:
|
||||||
|
titles.append(attrib)
|
||||||
|
if attrib == 'deviceId':
|
||||||
|
row[attrib] = mobile[attrib].encode(
|
||||||
|
'unicode-escape').decode(UTF8)
|
||||||
|
elif attrib == 'securityPatchLevel' and int(mobile[attrib]):
|
||||||
|
row[attrib] = utils.formatTimestampYMDHMS(
|
||||||
|
mobile[attrib])
|
||||||
|
else:
|
||||||
|
row[attrib] = mobile[attrib]
|
||||||
|
csvRows.append(row)
|
||||||
|
display.sort_csv_titles(
|
||||||
|
['resourceId', 'deviceId', 'serialNumber', 'name', 'email', 'status'],
|
||||||
|
titles)
|
||||||
|
display.write_csv_file(csvRows, titles, 'Mobile', todrive)
|
||||||
|
|
||||||
|
|
||||||
|
def update():
|
||||||
|
cd = gapi_directory.build
|
||||||
|
resourceIds = sys.argv[3]
|
||||||
|
match_users = None
|
||||||
|
doit = False
|
||||||
|
if resourceIds[:6] == 'query:':
|
||||||
|
query = resourceIds[6:]
|
||||||
|
fields = 'nextPageToken,mobiledevices(resourceId,email)'
|
||||||
|
page_message = gapi.got_total_items_msg('Mobile Devices', '...\n')
|
||||||
|
devices = gapi.get_all_pages(cd.mobiledevices(),
|
||||||
|
'list',
|
||||||
|
page_message=page_message,
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
items='mobiledevices',
|
||||||
|
query=query,
|
||||||
|
fields=fields)
|
||||||
|
else:
|
||||||
|
devices = [{'resourceId': resourceIds, 'email': ['not set']}]
|
||||||
|
doit = True
|
||||||
|
i = 4
|
||||||
|
body = {}
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
|
if myarg == 'action':
|
||||||
|
body['action'] = sys.argv[i + 1].lower()
|
||||||
|
validActions = [
|
||||||
|
'wipe', 'wipeaccount', 'accountwipe', 'wipe_account',
|
||||||
|
'account_wipe', 'approve', 'block',
|
||||||
|
'cancel_remote_wipe_then_activate',
|
||||||
|
'cancel_remote_wipe_then_block'
|
||||||
|
]
|
||||||
|
if body['action'] not in validActions:
|
||||||
|
controlflow.expected_argument_exit('action',
|
||||||
|
', '.join(validActions),
|
||||||
|
body['action'])
|
||||||
|
if body['action'] == 'wipe':
|
||||||
|
body['action'] = 'admin_remote_wipe'
|
||||||
|
elif body['action'].replace('_',
|
||||||
|
'') in ['accountwipe', 'wipeaccount']:
|
||||||
|
body['action'] = 'admin_account_wipe'
|
||||||
|
i += 2
|
||||||
|
elif myarg in ['ifusers', 'matchusers']:
|
||||||
|
match_users = gam.getUsersToModify(entity_type=sys.argv[i + 1].lower(),
|
||||||
|
entity=sys.argv[i + 2])
|
||||||
|
i += 3
|
||||||
|
elif myarg == 'doit':
|
||||||
|
doit = True
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam update mobile')
|
||||||
|
if body:
|
||||||
|
if doit:
|
||||||
|
print(f'Updating {len(devices)} devices')
|
||||||
|
describe_as = 'Performing'
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f'Showing {len(devices)} changes that would be made, not actually making changes because doit argument not specified'
|
||||||
|
)
|
||||||
|
describe_as = 'Would perform'
|
||||||
|
for device in devices:
|
||||||
|
device_user = device.get('email', [''])[0]
|
||||||
|
if match_users and device_user not in match_users:
|
||||||
|
print(
|
||||||
|
f'Skipping device for user {device_user} that did not match match_users argument'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f'{describe_as} {body["action"]} on user {device_user} device {device["resourceId"]}'
|
||||||
|
)
|
||||||
|
if doit:
|
||||||
|
gapi.call(cd.mobiledevices(),
|
||||||
|
'action',
|
||||||
|
resourceId=device['resourceId'],
|
||||||
|
body=body,
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID])
|
||||||
|
|
||||||
|
|
424
src/gam/gapi/directory/orgunits.py
Normal file
424
src/gam/gapi/directory/orgunits.py
Normal file
@ -0,0 +1,424 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
import gam
|
||||||
|
from gam.var import *
|
||||||
|
from gam import controlflow
|
||||||
|
from gam import display
|
||||||
|
from gam import gapi
|
||||||
|
from gam.gapi import directory as gapi_directory
|
||||||
|
from gam.gapi import errors as gapi_errors
|
||||||
|
from gam import utils
|
||||||
|
|
||||||
|
|
||||||
|
def create():
|
||||||
|
cd = gapi_directory.build()
|
||||||
|
name = getOrgUnitItem(sys.argv[3], pathOnly=True, absolutePath=False)
|
||||||
|
parent = ''
|
||||||
|
body = {}
|
||||||
|
i = 4
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower()
|
||||||
|
if myarg == 'description':
|
||||||
|
body['description'] = sys.argv[i + 1].replace('\\n', '\n')
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'parent':
|
||||||
|
parent = getOrgUnitItem(sys.argv[i + 1])
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'noinherit':
|
||||||
|
body['blockInheritance'] = True
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'inherit':
|
||||||
|
body['blockInheritance'] = False
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam create org')
|
||||||
|
if parent.startswith('id:'):
|
||||||
|
parent = gapi.call(cd.orgunits(),
|
||||||
|
'get',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
orgUnitPath=parent,
|
||||||
|
fields='orgUnitPath')['orgUnitPath']
|
||||||
|
if parent == '/':
|
||||||
|
orgUnitPath = parent + name
|
||||||
|
else:
|
||||||
|
orgUnitPath = parent + '/' + name
|
||||||
|
if orgUnitPath.count('/') > 1:
|
||||||
|
body['parentOrgUnitPath'], body['name'] = orgUnitPath.rsplit('/', 1)
|
||||||
|
else:
|
||||||
|
body['parentOrgUnitPath'] = '/'
|
||||||
|
body['name'] = orgUnitPath[1:]
|
||||||
|
parent = body['parentOrgUnitPath']
|
||||||
|
gapi.call(cd.orgunits(),
|
||||||
|
'insert',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
body=body,
|
||||||
|
retry_reasons=[gapi_errors.ErrorReason.DAILY_LIMIT_EXCEEDED])
|
||||||
|
print(f'Created OrgUnit {body["name"]}')
|
||||||
|
|
||||||
|
|
||||||
|
def delete():
|
||||||
|
cd = gapi_directory.build()
|
||||||
|
name = getOrgUnitItem(sys.argv[3])
|
||||||
|
print(f'Deleting organization {name}')
|
||||||
|
gapi.call(cd.orgunits(),
|
||||||
|
'delete',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
orgUnitPath=encodeOrgUnitPath(makeOrgUnitPathRelative(name)))
|
||||||
|
|
||||||
|
|
||||||
|
def info(name=None, return_attrib=None):
|
||||||
|
cd = gapi_directory.build()
|
||||||
|
checkSuspended = None
|
||||||
|
if not name:
|
||||||
|
name = getOrgUnitItem(sys.argv[3])
|
||||||
|
get_users = True
|
||||||
|
show_children = False
|
||||||
|
i = 4
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower()
|
||||||
|
if myarg == 'nousers':
|
||||||
|
get_users = False
|
||||||
|
i += 1
|
||||||
|
elif myarg in ['children', 'child']:
|
||||||
|
show_children = True
|
||||||
|
i += 1
|
||||||
|
elif myarg in ['suspended', 'notsuspended']:
|
||||||
|
checkSuspended = myarg == 'suspended'
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam info org')
|
||||||
|
if name == '/':
|
||||||
|
orgs = gapi.call(cd.orgunits(),
|
||||||
|
'list',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
type='children',
|
||||||
|
fields='organizationUnits/parentOrgUnitId')
|
||||||
|
if 'organizationUnits' in orgs and orgs['organizationUnits']:
|
||||||
|
name = orgs['organizationUnits'][0]['parentOrgUnitId']
|
||||||
|
else:
|
||||||
|
topLevelOrgId = getTopLevelOrgId(cd, '/')
|
||||||
|
if topLevelOrgId:
|
||||||
|
name = topLevelOrgId
|
||||||
|
else:
|
||||||
|
name = makeOrgUnitPathRelative(name)
|
||||||
|
result = gapi.call(cd.orgunits(),
|
||||||
|
'get',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
orgUnitPath=encodeOrgUnitPath(name))
|
||||||
|
if return_attrib:
|
||||||
|
return result[return_attrib]
|
||||||
|
display.print_json(result)
|
||||||
|
if get_users:
|
||||||
|
name = result['orgUnitPath']
|
||||||
|
page_message = gapi.got_total_items_first_last_msg('Users')
|
||||||
|
users = gapi.get_all_pages(
|
||||||
|
cd.users(),
|
||||||
|
'list',
|
||||||
|
'users',
|
||||||
|
page_message=page_message,
|
||||||
|
message_attribute='primaryEmail',
|
||||||
|
customer=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
query=orgUnitPathQuery(name, checkSuspended),
|
||||||
|
fields='users(primaryEmail,orgUnitPath),nextPageToken')
|
||||||
|
if checkSuspended is None:
|
||||||
|
print('Users:')
|
||||||
|
elif not checkSuspended:
|
||||||
|
print('Users (Not suspended):')
|
||||||
|
else:
|
||||||
|
print('Users (Suspended):')
|
||||||
|
for user in users:
|
||||||
|
if show_children or (name.lower() == user['orgUnitPath'].lower()):
|
||||||
|
sys.stdout.write(f' {user["primaryEmail"]}')
|
||||||
|
if name.lower() != user['orgUnitPath'].lower():
|
||||||
|
print(' (child)')
|
||||||
|
else:
|
||||||
|
print('')
|
||||||
|
|
||||||
|
|
||||||
|
def print_():
|
||||||
|
print_order = [
|
||||||
|
'orgUnitPath', 'orgUnitId', 'name', 'description', 'parentOrgUnitPath',
|
||||||
|
'parentOrgUnitId', 'blockInheritance'
|
||||||
|
]
|
||||||
|
cd = gapi_directory.build()
|
||||||
|
listType = 'all'
|
||||||
|
orgUnitPath = '/'
|
||||||
|
todrive = False
|
||||||
|
fields = ['orgUnitPath', 'name', 'orgUnitId', 'parentOrgUnitId']
|
||||||
|
titles = []
|
||||||
|
csvRows = []
|
||||||
|
parentOrgIds = []
|
||||||
|
retrievedOrgIds = []
|
||||||
|
i = 3
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
|
if myarg == 'todrive':
|
||||||
|
todrive = True
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'toplevelonly':
|
||||||
|
listType = 'children'
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'fromparent':
|
||||||
|
orgUnitPath = getOrgUnitItem(sys.argv[i + 1])
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'allfields':
|
||||||
|
fields = None
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'fields':
|
||||||
|
fields += sys.argv[i + 1].split(',')
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam print orgs')
|
||||||
|
gam.printGettingAllItems('Organizational Units', None)
|
||||||
|
if fields:
|
||||||
|
get_fields = ','.join(fields)
|
||||||
|
list_fields = f'organizationUnits({get_fields})'
|
||||||
|
else:
|
||||||
|
list_fields = None
|
||||||
|
get_fields = None
|
||||||
|
orgs = gapi.call(cd.orgunits(),
|
||||||
|
'list',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
type=listType,
|
||||||
|
orgUnitPath=orgUnitPath,
|
||||||
|
fields=list_fields)
|
||||||
|
if not 'organizationUnits' in orgs:
|
||||||
|
topLevelOrgId = getTopLevelOrgId(cd, orgUnitPath)
|
||||||
|
if topLevelOrgId:
|
||||||
|
parentOrgIds.append(topLevelOrgId)
|
||||||
|
orgunits = []
|
||||||
|
else:
|
||||||
|
orgunits = orgs['organizationUnits']
|
||||||
|
for row in orgunits:
|
||||||
|
retrievedOrgIds.append(row['orgUnitId'])
|
||||||
|
if row['parentOrgUnitId'] not in parentOrgIds:
|
||||||
|
parentOrgIds.append(row['parentOrgUnitId'])
|
||||||
|
missing_parents = set(parentOrgIds) - set(retrievedOrgIds)
|
||||||
|
for missing_parent in missing_parents:
|
||||||
|
try:
|
||||||
|
result = gapi.call(cd.orgunits(),
|
||||||
|
'get',
|
||||||
|
throw_reasons=['required'],
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
orgUnitPath=missing_parent,
|
||||||
|
fields=get_fields)
|
||||||
|
orgunits.append(result)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
for row in orgunits:
|
||||||
|
orgEntity = {}
|
||||||
|
for key, value in list(row.items()):
|
||||||
|
if key in ['kind', 'etag', 'etags']:
|
||||||
|
continue
|
||||||
|
if key not in titles:
|
||||||
|
titles.append(key)
|
||||||
|
orgEntity[key] = value
|
||||||
|
csvRows.append(orgEntity)
|
||||||
|
for title in titles:
|
||||||
|
if title not in print_order:
|
||||||
|
print_order.append(title)
|
||||||
|
titles = sorted(titles, key=print_order.index)
|
||||||
|
# sort results similar to how they list in admin console
|
||||||
|
csvRows.sort(key=lambda x: x['orgUnitPath'].lower(), reverse=False)
|
||||||
|
display.write_csv_file(csvRows, titles, 'Orgs', todrive)
|
||||||
|
|
||||||
|
|
||||||
|
def update():
|
||||||
|
cd = gapi_directory.build()
|
||||||
|
orgUnitPath = getOrgUnitItem(sys.argv[3])
|
||||||
|
if sys.argv[4].lower() in ['move', 'add']:
|
||||||
|
entity_type = sys.argv[5].lower()
|
||||||
|
if entity_type in usergroup_types:
|
||||||
|
users = getUsersToModify(entity_type=entity_type,
|
||||||
|
entity=sys.argv[6])
|
||||||
|
else:
|
||||||
|
entity_type = 'users'
|
||||||
|
users = getUsersToModify(entity_type=entity_type,
|
||||||
|
entity=sys.argv[5])
|
||||||
|
if (entity_type.startswith('cros')) or (
|
||||||
|
(entity_type == 'all') and (sys.argv[6].lower() == 'cros')):
|
||||||
|
for l in range(0, len(users), 50):
|
||||||
|
move_body = {'deviceIds': users[l:l + 50]}
|
||||||
|
print(
|
||||||
|
f' moving {len(move_body["deviceIds"])} devices to {orgUnitPath}'
|
||||||
|
)
|
||||||
|
gapi.call(cd.chromeosdevices(),
|
||||||
|
'moveDevicesToOu',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
orgUnitPath=orgUnitPath,
|
||||||
|
body=move_body)
|
||||||
|
else:
|
||||||
|
i = 0
|
||||||
|
count = len(users)
|
||||||
|
for user in users:
|
||||||
|
i += 1
|
||||||
|
sys.stderr.write(
|
||||||
|
f' moving {user} to {orgUnitPath}{currentCountNL(i, count)}'
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
gapi.call(cd.users(),
|
||||||
|
'update',
|
||||||
|
throw_reasons=[
|
||||||
|
gapi_errors.ErrorReason.CONDITION_NOT_MET
|
||||||
|
],
|
||||||
|
userKey=user,
|
||||||
|
body={'orgUnitPath': orgUnitPath})
|
||||||
|
except gapi_errors.GapiConditionNotMetError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
body = {}
|
||||||
|
i = 4
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower()
|
||||||
|
if myarg == 'name':
|
||||||
|
body['name'] = sys.argv[i + 1]
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'description':
|
||||||
|
body['description'] = sys.argv[i + 1].replace('\\n', '\n')
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'parent':
|
||||||
|
parent = getOrgUnitItem(sys.argv[i + 1])
|
||||||
|
if parent.startswith('id:'):
|
||||||
|
body['parentOrgUnitId'] = parent
|
||||||
|
else:
|
||||||
|
body['parentOrgUnitPath'] = parent
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'noinherit':
|
||||||
|
body['blockInheritance'] = True
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'inherit':
|
||||||
|
body['blockInheritance'] = False
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam update org')
|
||||||
|
gapi.call(cd.orgunits(),
|
||||||
|
'update',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
orgUnitPath=encodeOrgUnitPath(
|
||||||
|
makeOrgUnitPathRelative(orgUnitPath)),
|
||||||
|
body=body)
|
||||||
|
|
||||||
|
|
||||||
|
def orgUnitPathQuery(path, checkSuspended):
|
||||||
|
query = "orgUnitPath='{0}'".format(path.replace(
|
||||||
|
"'", "\\'")) if path != '/' else ''
|
||||||
|
if checkSuspended is not None:
|
||||||
|
query += f' isSuspended={checkSuspended}'
|
||||||
|
return query
|
||||||
|
|
||||||
|
|
||||||
|
def makeOrgUnitPathAbsolute(path):
|
||||||
|
if path == '/':
|
||||||
|
return path
|
||||||
|
if path.startswith('/'):
|
||||||
|
return path.rstrip('/')
|
||||||
|
if path.startswith('id:'):
|
||||||
|
return path
|
||||||
|
if path.startswith('uid:'):
|
||||||
|
return path[1:]
|
||||||
|
return '/' + path.rstrip('/')
|
||||||
|
|
||||||
|
|
||||||
|
def makeOrgUnitPathRelative(path):
|
||||||
|
if path == '/':
|
||||||
|
return path
|
||||||
|
if path.startswith('/'):
|
||||||
|
return path[1:].rstrip('/')
|
||||||
|
if path.startswith('id:'):
|
||||||
|
return path
|
||||||
|
if path.startswith('uid:'):
|
||||||
|
return path[1:]
|
||||||
|
return path.rstrip('/')
|
||||||
|
|
||||||
|
|
||||||
|
def encodeOrgUnitPath(path):
|
||||||
|
if path.find('+') == -1 and path.find('%') == -1:
|
||||||
|
return path
|
||||||
|
encpath = ''
|
||||||
|
for c in path:
|
||||||
|
if c == '+':
|
||||||
|
encpath += '%2B'
|
||||||
|
elif c == '%':
|
||||||
|
encpath += '%25'
|
||||||
|
else:
|
||||||
|
encpath += c
|
||||||
|
return encpath
|
||||||
|
|
||||||
|
|
||||||
|
def getOrgUnitItem(orgUnit, pathOnly=False, absolutePath=True):
|
||||||
|
if pathOnly and (orgUnit.startswith('id:') or orgUnit.startswith('uid:')):
|
||||||
|
controlflow.system_error_exit(
|
||||||
|
2, f'{orgUnit} is not valid in this context')
|
||||||
|
if absolutePath:
|
||||||
|
return makeOrgUnitPathAbsolute(orgUnit)
|
||||||
|
return makeOrgUnitPathRelative(orgUnit)
|
||||||
|
|
||||||
|
|
||||||
|
def getTopLevelOrgId(cd, orgUnitPath):
|
||||||
|
try:
|
||||||
|
# create a temp org so we can learn what the top level org ID is (sigh)
|
||||||
|
temp_org = gapi.call(cd.orgunits(),
|
||||||
|
'insert',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
body={
|
||||||
|
'name': 'temp-delete-me',
|
||||||
|
'parentOrgUnitPath': orgUnitPath
|
||||||
|
},
|
||||||
|
fields='parentOrgUnitId,orgUnitId')
|
||||||
|
gapi.call(cd.orgunits(),
|
||||||
|
'delete',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
orgUnitPath=temp_org['orgUnitId'])
|
||||||
|
return temp_org['parentOrgUnitId']
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def getOrgUnitId(orgUnit, cd=None):
|
||||||
|
if cd is None:
|
||||||
|
cd = buildGAPIObject('directory')
|
||||||
|
orgUnit = getOrgUnitItem(orgUnit)
|
||||||
|
if orgUnit[:3] == 'id:':
|
||||||
|
return (orgUnit, orgUnit)
|
||||||
|
if orgUnit == '/':
|
||||||
|
result = gapi.call(cd.orgunits(),
|
||||||
|
'list',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
orgUnitPath='/',
|
||||||
|
type='children',
|
||||||
|
fields='organizationUnits(parentOrgUnitId)')
|
||||||
|
if result.get('organizationUnits', []):
|
||||||
|
return (orgUnit, result['organizationUnits'][0]['parentOrgUnitId'])
|
||||||
|
topLevelOrgId = getTopLevelOrgId(cd, '/')
|
||||||
|
if topLevelOrgId:
|
||||||
|
return (orgUnit, topLevelOrgId)
|
||||||
|
return (orgUnit, '/') #Bogus but should never happen
|
||||||
|
result = gapi.call(cd.orgunits(),
|
||||||
|
'get',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
orgUnitPath=encodeOrgUnitPath(
|
||||||
|
makeOrgUnitPathRelative(orgUnit)),
|
||||||
|
fields='orgUnitId')
|
||||||
|
return (orgUnit, result['orgUnitId'])
|
||||||
|
|
||||||
|
|
||||||
|
def buildOrgUnitIdToNameMap():
|
||||||
|
cd = buildGAPIObject('directory')
|
||||||
|
result = gapi.call(cd.orgunits(),
|
||||||
|
'list',
|
||||||
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
||||||
|
fields='organizationUnits(orgUnitPath,orgUnitId)',
|
||||||
|
type='all')
|
||||||
|
GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME] = {}
|
||||||
|
for orgUnit in result['organizationUnits']:
|
||||||
|
GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME][
|
||||||
|
orgUnit['orgUnitId']] = orgUnit['orgUnitPath']
|
||||||
|
|
||||||
|
|
||||||
|
def orgunit_from_orgunitid(orgunitid):
|
||||||
|
if not GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME]:
|
||||||
|
buildOrgUnitIdToNameMap()
|
||||||
|
return GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME].get(orgunitid, orgunitid)
|
||||||
|
|
||||||
|
|
27
src/gam/gapi/directory/privileges.py
Normal file
27
src/gam/gapi/directory/privileges.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from gam.var import GC_Values, GC_CUSTOMER_ID
|
||||||
|
from gam import display
|
||||||
|
from gam import gapi
|
||||||
|
from gam.gapi import directory as gapi_directory
|
||||||
|
|
||||||
|
def flatten_privilege_list(privs, parent=None):
|
||||||
|
flat_privs = []
|
||||||
|
for priv in privs:
|
||||||
|
children = []
|
||||||
|
if parent:
|
||||||
|
priv['parent'] = parent
|
||||||
|
if priv.get('childPrivileges'):
|
||||||
|
children = flatten_privilege_list(priv['childPrivileges'], parent=priv['privilegeName'])
|
||||||
|
priv['children'] = ' '.join([child['privilegeName'] for child in children])
|
||||||
|
del(priv['childPrivileges'])
|
||||||
|
flat_privs = flat_privs + children
|
||||||
|
flat_privs.append(priv)
|
||||||
|
return flat_privs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def print_():
|
||||||
|
cd = gapi_directory.build()
|
||||||
|
privs = gapi.call(cd.privileges(), 'list',
|
||||||
|
customer=GC_Values[GC_CUSTOMER_ID])
|
||||||
|
privs = flatten_privilege_list(privs.get('items', []))
|
||||||
|
display.print_json(privs)
|
@ -12,7 +12,7 @@ from gam import utils
|
|||||||
|
|
||||||
def printBuildings():
|
def printBuildings():
|
||||||
to_drive = False
|
to_drive = False
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
titles = []
|
titles = []
|
||||||
csvRows = []
|
csvRows = []
|
||||||
fieldsList = ['buildingId']
|
fieldsList = ['buildingId']
|
||||||
@ -67,7 +67,7 @@ def printBuildings():
|
|||||||
|
|
||||||
|
|
||||||
def printResourceCalendars():
|
def printResourceCalendars():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
todrive = False
|
todrive = False
|
||||||
fieldsList = []
|
fieldsList = []
|
||||||
fieldsTitles = {}
|
fieldsTitles = {}
|
||||||
@ -182,7 +182,7 @@ RESCAL_ARGUMENT_TO_PROPERTY_MAP = {
|
|||||||
|
|
||||||
def printFeatures():
|
def printFeatures():
|
||||||
to_drive = False
|
to_drive = False
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
titles = []
|
titles = []
|
||||||
csvRows = []
|
csvRows = []
|
||||||
fieldsList = ['name']
|
fieldsList = ['name']
|
||||||
@ -260,7 +260,7 @@ def _getBuildingAttributes(args, body={}):
|
|||||||
|
|
||||||
|
|
||||||
def createBuilding():
|
def createBuilding():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
body = {
|
body = {
|
||||||
'floorNames': ['1'],
|
'floorNames': ['1'],
|
||||||
'buildingId': str(uuid.uuid4()),
|
'buildingId': str(uuid.uuid4()),
|
||||||
@ -346,7 +346,7 @@ def getBuildingNameById(cd, buildingId):
|
|||||||
|
|
||||||
|
|
||||||
def updateBuilding():
|
def updateBuilding():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
buildingId = getBuildingByNameOrId(cd, sys.argv[3])
|
buildingId = getBuildingByNameOrId(cd, sys.argv[3])
|
||||||
body = _getBuildingAttributes(sys.argv[4:])
|
body = _getBuildingAttributes(sys.argv[4:])
|
||||||
print(f'Updating building {buildingId}...')
|
print(f'Updating building {buildingId}...')
|
||||||
@ -358,7 +358,7 @@ def updateBuilding():
|
|||||||
|
|
||||||
|
|
||||||
def getBuildingInfo():
|
def getBuildingInfo():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
buildingId = getBuildingByNameOrId(cd, sys.argv[3])
|
buildingId = getBuildingByNameOrId(cd, sys.argv[3])
|
||||||
building = gapi.call(cd.resources().buildings(),
|
building = gapi.call(cd.resources().buildings(),
|
||||||
'get',
|
'get',
|
||||||
@ -374,7 +374,7 @@ def getBuildingInfo():
|
|||||||
|
|
||||||
|
|
||||||
def deleteBuilding():
|
def deleteBuilding():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
buildingId = getBuildingByNameOrId(cd, sys.argv[3])
|
buildingId = getBuildingByNameOrId(cd, sys.argv[3])
|
||||||
print(f'Deleting building {buildingId}...')
|
print(f'Deleting building {buildingId}...')
|
||||||
gapi.call(cd.resources().buildings(),
|
gapi.call(cd.resources().buildings(),
|
||||||
@ -397,7 +397,7 @@ def _getFeatureAttributes(args, body={}):
|
|||||||
|
|
||||||
|
|
||||||
def createFeature():
|
def createFeature():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
body = _getFeatureAttributes(sys.argv[3:])
|
body = _getFeatureAttributes(sys.argv[3:])
|
||||||
print(f'Creating feature {body["name"]}...')
|
print(f'Creating feature {body["name"]}...')
|
||||||
gapi.call(cd.resources().features(),
|
gapi.call(cd.resources().features(),
|
||||||
@ -410,7 +410,7 @@ def updateFeature():
|
|||||||
# update does not work for name and name is only field to be updated
|
# update does not work for name and name is only field to be updated
|
||||||
# if additional writable fields are added to feature in the future
|
# if additional writable fields are added to feature in the future
|
||||||
# we'll add support for update as well as rename
|
# we'll add support for update as well as rename
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
oldName = sys.argv[3]
|
oldName = sys.argv[3]
|
||||||
body = {'newName': sys.argv[5:]}
|
body = {'newName': sys.argv[5:]}
|
||||||
print(f'Updating feature {oldName}...')
|
print(f'Updating feature {oldName}...')
|
||||||
@ -422,7 +422,7 @@ def updateFeature():
|
|||||||
|
|
||||||
|
|
||||||
def deleteFeature():
|
def deleteFeature():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
featureKey = sys.argv[3]
|
featureKey = sys.argv[3]
|
||||||
print(f'Deleting feature {featureKey}...')
|
print(f'Deleting feature {featureKey}...')
|
||||||
gapi.call(cd.resources().features(),
|
gapi.call(cd.resources().features(),
|
||||||
@ -480,7 +480,7 @@ def _getResourceCalendarAttributes(cd, args, body={}):
|
|||||||
|
|
||||||
|
|
||||||
def createResourceCalendar():
|
def createResourceCalendar():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
body = {'resourceId': sys.argv[3], 'resourceName': sys.argv[4]}
|
body = {'resourceId': sys.argv[3], 'resourceName': sys.argv[4]}
|
||||||
body = _getResourceCalendarAttributes(cd, sys.argv[5:], body)
|
body = _getResourceCalendarAttributes(cd, sys.argv[5:], body)
|
||||||
print(f'Creating resource {body["resourceId"]}...')
|
print(f'Creating resource {body["resourceId"]}...')
|
||||||
@ -491,7 +491,7 @@ def createResourceCalendar():
|
|||||||
|
|
||||||
|
|
||||||
def updateResourceCalendar():
|
def updateResourceCalendar():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
resId = sys.argv[3]
|
resId = sys.argv[3]
|
||||||
body = _getResourceCalendarAttributes(cd, sys.argv[4:])
|
body = _getResourceCalendarAttributes(cd, sys.argv[4:])
|
||||||
# Use patch since it seems to work better.
|
# Use patch since it seems to work better.
|
||||||
@ -506,7 +506,7 @@ def updateResourceCalendar():
|
|||||||
|
|
||||||
|
|
||||||
def getResourceCalendarInfo():
|
def getResourceCalendarInfo():
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
resId = sys.argv[3]
|
resId = sys.argv[3]
|
||||||
resource = gapi.call(cd.resources().calendars(),
|
resource = gapi.call(cd.resources().calendars(),
|
||||||
'get',
|
'get',
|
||||||
@ -526,7 +526,7 @@ def getResourceCalendarInfo():
|
|||||||
|
|
||||||
def deleteResourceCalendar():
|
def deleteResourceCalendar():
|
||||||
resId = sys.argv[3]
|
resId = sys.argv[3]
|
||||||
cd = gapi_directory.buildGAPIObject()
|
cd = gapi_directory.build()
|
||||||
print(f'Deleting resource calendar {resId}')
|
print(f'Deleting resource calendar {resId}')
|
||||||
gapi.call(cd.resources().calendars(),
|
gapi.call(cd.resources().calendars(),
|
||||||
'delete',
|
'delete',
|
||||||
|
@ -13,7 +13,7 @@ from gam import gapi
|
|||||||
from gam import utils
|
from gam import utils
|
||||||
|
|
||||||
|
|
||||||
def buildGAPIObject():
|
def build():
|
||||||
return gam.buildGAPIObject('reports')
|
return gam.buildGAPIObject('reports')
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ REPORT_CHOICE_MAP = {
|
|||||||
|
|
||||||
|
|
||||||
def showUsageParameters():
|
def showUsageParameters():
|
||||||
rep = buildGAPIObject()
|
rep = build()
|
||||||
throw_reasons = [
|
throw_reasons = [
|
||||||
gapi.errors.ErrorReason.INVALID, gapi.errors.ErrorReason.BAD_REQUEST
|
gapi.errors.ErrorReason.INVALID, gapi.errors.ErrorReason.BAD_REQUEST
|
||||||
]
|
]
|
||||||
@ -115,7 +115,7 @@ REPORTS_PARAMETERS_SIMPLE_TYPES = [
|
|||||||
|
|
||||||
|
|
||||||
def showUsage():
|
def showUsage():
|
||||||
rep = buildGAPIObject()
|
rep = build()
|
||||||
throw_reasons = [
|
throw_reasons = [
|
||||||
gapi.errors.ErrorReason.INVALID, gapi.errors.ErrorReason.BAD_REQUEST
|
gapi.errors.ErrorReason.INVALID, gapi.errors.ErrorReason.BAD_REQUEST
|
||||||
]
|
]
|
||||||
@ -264,7 +264,7 @@ def showUsage():
|
|||||||
|
|
||||||
|
|
||||||
def showReport():
|
def showReport():
|
||||||
rep = buildGAPIObject()
|
rep = build()
|
||||||
throw_reasons = [gapi.errors.ErrorReason.INVALID]
|
throw_reasons = [gapi.errors.ErrorReason.INVALID]
|
||||||
report = sys.argv[2].lower()
|
report = sys.argv[2].lower()
|
||||||
report = REPORT_CHOICE_MAP.get(report.replace('_', ''), report)
|
report = REPORT_CHOICE_MAP.get(report.replace('_', ''), report)
|
||||||
|
188
src/gam/gapi/siteverification.py
Normal file
188
src/gam/gapi/siteverification.py
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
|
import gam
|
||||||
|
from gam.var import *
|
||||||
|
from gam import controlflow
|
||||||
|
from gam import display
|
||||||
|
from gam import fileutils
|
||||||
|
from gam import gapi
|
||||||
|
from gam.gapi import directory as gapi_directory
|
||||||
|
from gam.gapi import errors as gapi_errors
|
||||||
|
from gam.gapi.directory import customer as gapi_directory_customer
|
||||||
|
from gam import transport
|
||||||
|
from gam import utils
|
||||||
|
|
||||||
|
import gam
|
||||||
|
|
||||||
|
|
||||||
|
def build():
|
||||||
|
return gam.buildGAPIObject('siteVerification')
|
||||||
|
|
||||||
|
|
||||||
|
def create():
|
||||||
|
verif = build()
|
||||||
|
a_domain = sys.argv[3]
|
||||||
|
txt_record = gapi.call(verif.webResource(),
|
||||||
|
'getToken',
|
||||||
|
body={
|
||||||
|
'site': {
|
||||||
|
'type': 'INET_DOMAIN',
|
||||||
|
'identifier': a_domain
|
||||||
|
},
|
||||||
|
'verificationMethod': 'DNS_TXT'
|
||||||
|
})
|
||||||
|
print(f'TXT Record Name: {a_domain}')
|
||||||
|
print(f'TXT Record Value: {txt_record["token"]}')
|
||||||
|
print()
|
||||||
|
cname_record = gapi.call(verif.webResource(),
|
||||||
|
'getToken',
|
||||||
|
body={
|
||||||
|
'site': {
|
||||||
|
'type': 'INET_DOMAIN',
|
||||||
|
'identifier': a_domain
|
||||||
|
},
|
||||||
|
'verificationMethod': 'DNS_CNAME'
|
||||||
|
})
|
||||||
|
cname_token = cname_record['token']
|
||||||
|
cname_list = cname_token.split(' ')
|
||||||
|
cname_subdomain = cname_list[0]
|
||||||
|
cname_value = cname_list[1]
|
||||||
|
print(f'CNAME Record Name: {cname_subdomain}.{a_domain}')
|
||||||
|
print(f'CNAME Record Value: {cname_value}')
|
||||||
|
print('')
|
||||||
|
webserver_file_record = gapi.call(
|
||||||
|
verif.webResource(),
|
||||||
|
'getToken',
|
||||||
|
body={
|
||||||
|
'site': {
|
||||||
|
'type': 'SITE',
|
||||||
|
'identifier': f'http://{a_domain}/'
|
||||||
|
},
|
||||||
|
'verificationMethod': 'FILE'
|
||||||
|
})
|
||||||
|
webserver_file_token = webserver_file_record['token']
|
||||||
|
print(f'Saving web server verification file to: {webserver_file_token}')
|
||||||
|
fileutils.write_file(webserver_file_token,
|
||||||
|
f'google-site-verification: {webserver_file_token}',
|
||||||
|
continue_on_error=True)
|
||||||
|
print(f'Verification File URL: http://{a_domain}/{webserver_file_token}')
|
||||||
|
print()
|
||||||
|
webserver_meta_record = gapi.call(
|
||||||
|
verif.webResource(),
|
||||||
|
'getToken',
|
||||||
|
body={
|
||||||
|
'site': {
|
||||||
|
'type': 'SITE',
|
||||||
|
'identifier': f'http://{a_domain}/'
|
||||||
|
},
|
||||||
|
'verificationMethod': 'META'
|
||||||
|
})
|
||||||
|
print(f'Meta URL: http://{a_domain}/')
|
||||||
|
print(f'Meta HTML Header Data: {webserver_meta_record["token"]}')
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def info():
|
||||||
|
verif = build()
|
||||||
|
sites = gapi.get_items(verif.webResource(), 'list', 'items')
|
||||||
|
if sites:
|
||||||
|
for site in sites:
|
||||||
|
print(f'Site: {site["site"]["identifier"]}')
|
||||||
|
print(f'Type: {site["site"]["type"]}')
|
||||||
|
print('Owners:')
|
||||||
|
for owner in site['owners']:
|
||||||
|
print(f' {owner}')
|
||||||
|
print()
|
||||||
|
else:
|
||||||
|
print('No Sites Verified.')
|
||||||
|
|
||||||
|
|
||||||
|
def update():
|
||||||
|
verif = build()
|
||||||
|
a_domain = sys.argv[3]
|
||||||
|
verificationMethod = sys.argv[4].upper()
|
||||||
|
if verificationMethod == 'CNAME':
|
||||||
|
verificationMethod = 'DNS_CNAME'
|
||||||
|
elif verificationMethod in ['TXT', 'TEXT']:
|
||||||
|
verificationMethod = 'DNS_TXT'
|
||||||
|
if verificationMethod in ['DNS_TXT', 'DNS_CNAME']:
|
||||||
|
verify_type = 'INET_DOMAIN'
|
||||||
|
identifier = a_domain
|
||||||
|
else:
|
||||||
|
verify_type = 'SITE'
|
||||||
|
identifier = f'http://{a_domain}/'
|
||||||
|
body = {
|
||||||
|
'site': {
|
||||||
|
'type': verify_type,
|
||||||
|
'identifier': identifier
|
||||||
|
},
|
||||||
|
'verificationMethod': verificationMethod
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
verify_result = gapi.call(
|
||||||
|
verif.webResource(),
|
||||||
|
'insert',
|
||||||
|
throw_reasons=[gapi_errors.ErrorReason.BAD_REQUEST],
|
||||||
|
verificationMethod=verificationMethod,
|
||||||
|
body=body)
|
||||||
|
except gapi_errors.GapiBadRequestError as e:
|
||||||
|
print(f'ERROR: {str(e)}')
|
||||||
|
verify_data = gapi.call(verif.webResource(), 'getToken', body=body)
|
||||||
|
print(f'Method: {verify_data["method"]}')
|
||||||
|
print(f'Expected Token: {verify_data["token"]}')
|
||||||
|
if verify_data['method'] in ['DNS_CNAME', 'DNS_TXT']:
|
||||||
|
simplehttp = transport.create_http()
|
||||||
|
base_url = 'https://dns.google/resolve?'
|
||||||
|
query_params = {}
|
||||||
|
if verify_data['method'] == 'DNS_CNAME':
|
||||||
|
cname_token = verify_data['token']
|
||||||
|
cname_list = cname_token.split(' ')
|
||||||
|
cname_subdomain = cname_list[0]
|
||||||
|
query_params['name'] = f'{cname_subdomain}.{a_domain}'
|
||||||
|
query_params['type'] = 'cname'
|
||||||
|
else:
|
||||||
|
query_params['name'] = a_domain
|
||||||
|
query_params['type'] = 'txt'
|
||||||
|
full_url = base_url + urlencode(query_params)
|
||||||
|
(_, c) = simplehttp.request(full_url, 'GET')
|
||||||
|
result = json.loads(c)
|
||||||
|
status = result['Status']
|
||||||
|
if status == 0 and 'Answer' in result:
|
||||||
|
answers = result['Answer']
|
||||||
|
if verify_data['method'] == 'DNS_CNAME':
|
||||||
|
answer = answers[0]['data']
|
||||||
|
else:
|
||||||
|
answer = 'no matching record found'
|
||||||
|
for possible_answer in answers:
|
||||||
|
possible_answer['data'] = possible_answer['data'].strip(
|
||||||
|
'"')
|
||||||
|
if possible_answer['data'].startswith(
|
||||||
|
'google-site-verification'):
|
||||||
|
answer = possible_answer['data']
|
||||||
|
break
|
||||||
|
print(
|
||||||
|
f'Unrelated TXT record: {possible_answer["data"]}')
|
||||||
|
print(f'Found DNS Record: {answer}')
|
||||||
|
elif status == 0:
|
||||||
|
controlflow.system_error_exit(1, 'DNS record not found')
|
||||||
|
else:
|
||||||
|
controlflow.system_error_exit(
|
||||||
|
status,
|
||||||
|
DNS_ERROR_CODES_MAP.get(status, f'Unknown error {status}'))
|
||||||
|
return
|
||||||
|
print('SUCCESS!')
|
||||||
|
print(f'Verified: {verify_result["site"]["identifier"]}')
|
||||||
|
print(f'ID: {verify_result["id"]}')
|
||||||
|
print(f'Type: {verify_result["site"]["type"]}')
|
||||||
|
print('All Owners:')
|
||||||
|
try:
|
||||||
|
for owner in verify_result['owners']:
|
||||||
|
print(f' {owner}')
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
print()
|
||||||
|
print(
|
||||||
|
f'You can now add {a_domain} or it\'s subdomains as secondary or domain aliases of the {GC_Values[GC_DOMAIN]} G Suite Account.'
|
||||||
|
)
|
@ -236,6 +236,7 @@ API_VER_MAPPING = {
|
|||||||
'appsactivity': 'v1',
|
'appsactivity': 'v1',
|
||||||
'calendar': 'v3',
|
'calendar': 'v3',
|
||||||
'classroom': 'v1',
|
'classroom': 'v1',
|
||||||
|
'cloudidentity': 'v1beta1',
|
||||||
'cloudresourcemanager': 'v2',
|
'cloudresourcemanager': 'v2',
|
||||||
'cloudresourcemanagerv1': 'v1',
|
'cloudresourcemanagerv1': 'v1',
|
||||||
'datatransfer': 'datatransfer_v1',
|
'datatransfer': 'datatransfer_v1',
|
||||||
|
Reference in New Issue
Block a user