mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-04 14:21:39 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6b6824ee1 | ||
|
|
2902fc8931 | ||
|
|
1a6ec398b2 | ||
|
|
7d849e0cc0 | ||
|
|
2958bd9f86 | ||
|
|
15d93c9e5d | ||
|
|
082c34b453 | ||
|
|
32e7932050 | ||
|
|
6becd08f3c | ||
|
|
26fbf9c524 | ||
|
|
d9124f3ffa | ||
|
|
aa1db89bd3 | ||
|
|
ff3a8644ec | ||
|
|
4721469b1d | ||
|
|
c4a3d29964 | ||
|
|
1454526e65 | ||
|
|
2c0026512d | ||
|
|
3c85da292e | ||
|
|
c7b5251b03 | ||
|
|
5307a560bd |
@@ -11,6 +11,8 @@ OPTIONS:
|
||||
-a Architecture to install (i386, x86_64, arm). Default is to detect your arch with "uname -m".
|
||||
-o OS we are running (linux, macos). Default is to detect your OS with "uname -s".
|
||||
-p Profile update (true, false). Should script add gam command to environment. Default is true.
|
||||
-u Admin user email address to use with GAM. Default is to prompt.
|
||||
-r Regular user email address. Used to test service account access to user data. Default is to prompt.
|
||||
-v Version to install (latest, prerelease, draft, 3.8, etc). Default is latest.
|
||||
EOF
|
||||
}
|
||||
@@ -20,7 +22,9 @@ gamarch=$(uname -m)
|
||||
gamos=$(uname -s)
|
||||
update_profile=true
|
||||
gamversion="latest"
|
||||
while getopts "hd:a:o:p:v:" OPTION
|
||||
adminuser=""
|
||||
regularuser=""
|
||||
while getopts "hd:a:o:p:u:r:v:" OPTION
|
||||
do
|
||||
case $OPTION in
|
||||
h) usage; exit;;
|
||||
@@ -28,6 +32,8 @@ do
|
||||
a) gamarch=$OPTARG;;
|
||||
o) gamos=$OPTARG;;
|
||||
p) update_profile=$OPTARG;;
|
||||
u) adminuser=$OPTARG;;
|
||||
r) regularuser=$OPTARG;;
|
||||
v) gamversion=$OPTARG;;
|
||||
?) usage; exit;;
|
||||
esac
|
||||
@@ -180,7 +186,10 @@ while true; do
|
||||
read -p "GAM is now installed. Are you ready to set up a Google API project for GAM? (yes or no) " yn
|
||||
case $yn in
|
||||
[Yy]*)
|
||||
$target_dir/gam/gam create project
|
||||
if [ "$adminuser" == "" ]; then
|
||||
read -p "Please enter your G Suite admin email address: " adminuser
|
||||
fi
|
||||
$target_dir/gam/gam create project $adminuser
|
||||
rc=$?
|
||||
if (( $rc == 0 )); then
|
||||
echo_green "Project creation complete."
|
||||
@@ -205,7 +214,7 @@ while $project_created; do
|
||||
read -p "Are you ready to authorize GAM to perform G Suite management operations as your admin account? (yes or no) " yn
|
||||
case $yn in
|
||||
[Yy]*)
|
||||
$target_dir/gam/gam oauth create
|
||||
$target_dir/gam/gam oauth create $adminuser
|
||||
rc=$?
|
||||
if (( $rc == 0 )); then
|
||||
echo_green "Admin authorization complete."
|
||||
@@ -230,8 +239,11 @@ while $project_created; do
|
||||
read -p "Are you ready to authorize GAM to manage G Suite user data and settings? (yes or no) " yn
|
||||
case $yn in
|
||||
[Yy]*)
|
||||
if [ "$regularuser" == "" ]; then
|
||||
read -p "Please enter the email address of a regular G Suite user: " regularuser
|
||||
fi
|
||||
echo_yellow "Great! Checking service account scopes.This will fail the first time. Follow the steps to authorize and retry. It can take a few minutes for scopes to PASS after they've been authorized in the admin console."
|
||||
$target_dir/gam check serviceaccount
|
||||
$target_dir/gam/gam user $adminuser check serviceaccount
|
||||
rc=$?
|
||||
if (( $rc == 0 )); then
|
||||
echo_green "Service account authorization complete."
|
||||
|
||||
75
src/gam-setup.bat
Normal file
75
src/gam-setup.bat
Normal file
@@ -0,0 +1,75 @@
|
||||
@echo(
|
||||
@set /p adminemail= "Please enter your G Suite admin email address: "
|
||||
|
||||
:createproject
|
||||
@echo(
|
||||
@set /p yn= "Are you ready to set up a Google API project for GAM? [y or n] "
|
||||
@if /I "%yn%"=="n" (
|
||||
@ echo(
|
||||
@ echo You can create an API project later by running:
|
||||
@ echo(
|
||||
@ echo gam create project
|
||||
@ goto alldone
|
||||
)
|
||||
@if /I not "%yn%"=="y" (
|
||||
@ echo(
|
||||
@ echo Please answer y or n.
|
||||
@ goto createproject
|
||||
)
|
||||
@gam create project %adminemail%
|
||||
@if not ERRORLEVEL 1 goto projectdone
|
||||
@echo(
|
||||
@echo Projection creation failed. Trying again. Say n to skip projection creation.
|
||||
@goto createproject
|
||||
:projectdone
|
||||
|
||||
:adminauth
|
||||
@echo(
|
||||
@set /p yn= "Are you ready to authorize GAM to perform G Suite management operations as your admin account? [y or n] "
|
||||
@if /I "%yn%"=="n" (
|
||||
@ echo(
|
||||
@ echo You can authorize an admin later by running:
|
||||
@ echo(
|
||||
@ echo gam oauth create %adminemail%
|
||||
@ goto admindone
|
||||
)
|
||||
@if /I not "%yn%"=="y" (
|
||||
@ echo(
|
||||
@ echo Please answer y or n.
|
||||
@ goto adminauth
|
||||
)
|
||||
@gam oauth create %adminemail%
|
||||
@if not ERRORLEVEL 1 goto admindone
|
||||
@echo(
|
||||
@echo Admin authorization failed. Trying again. Say n to skip admin authorization.
|
||||
@goto adminauth
|
||||
:admindone
|
||||
|
||||
:saauth
|
||||
@echo(
|
||||
@set /p yn= "Are you ready to authorize GAM to manage G Suite user data and settings? [y or n] "
|
||||
@if /I "%yn%"=="n" (
|
||||
@ echo(
|
||||
@ echo You can authorize a service account later by running:
|
||||
@ echo(
|
||||
@ echo gam user %adminemail% check serviceaccount
|
||||
@ goto sadone
|
||||
)
|
||||
@if /I not "%yn%"=="y" (
|
||||
@ echo(
|
||||
@ echo Please answer y or n.
|
||||
@ goto saauth
|
||||
)
|
||||
@echo(
|
||||
@set /p regularuser= "Please enter the email address of a regular G Suite user: "
|
||||
@echo Great! Checking service account scopes. This will fail the first time. Follow the steps to authorize and retry. It can take a few minutes for scopes to PASS after they've been authorized in the admin console.
|
||||
@gam user %regularuser% check serviceaccount
|
||||
@if not ERRORLEVEL 1 goto sadone
|
||||
@echo(
|
||||
@echo Service account authorization failed. Confirm you entered the scopes correctly in the admin console. It can take a few minutes for scopes to PASS after they are entered in the admin console so if you're sure you entered them correctly, go grab a coffee and then hit Y to try again. Say N to skip admin authorization.
|
||||
@goto saauth
|
||||
:sadone
|
||||
|
||||
@echo GAM installation and setup complete!
|
||||
:alldone
|
||||
@pause
|
||||
150
src/gam.py
150
src/gam.py
@@ -23,7 +23,7 @@ For more information, see http://git.io/gam
|
||||
"""
|
||||
|
||||
__author__ = u'Jay Lee <jay0lee@gmail.com>'
|
||||
__version__ = u'4.0'
|
||||
__version__ = u'4.02'
|
||||
__license__ = u'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
import sys
|
||||
@@ -428,7 +428,7 @@ def indentMultiLineText(message, n=0):
|
||||
return message.replace(u'\n', u'\n{0}'.format(u' '*n)).rstrip()
|
||||
|
||||
def showUsage():
|
||||
doGAMVersion(checkForCheck=False)
|
||||
doGAMVersion(checkForArgs=False)
|
||||
print u'''
|
||||
Usage: gam [OPTIONS]...
|
||||
|
||||
@@ -818,32 +818,32 @@ def doGAMCheckForUpdates(forceCheck=False):
|
||||
except (urllib2.HTTPError, urllib2.URLError):
|
||||
return
|
||||
|
||||
def doGAMVersion(checkForCheck=True):
|
||||
def doGAMVersion(checkForArgs=True):
|
||||
force_check = False
|
||||
simple = False
|
||||
i = 2
|
||||
while i < len(sys.argv):
|
||||
myarg = sys.argv[i].lower().replace(u'_', u'')
|
||||
force_check = True
|
||||
if myarg == u'check':
|
||||
force_check = True
|
||||
i += 1
|
||||
elif myarg == u'simple':
|
||||
simple = True
|
||||
i += 1
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam version"' % sys.argv[i]
|
||||
sys.exit(2)
|
||||
if checkForArgs:
|
||||
i = 2
|
||||
while i < len(sys.argv):
|
||||
myarg = sys.argv[i].lower().replace(u'_', u'')
|
||||
if myarg == u'check':
|
||||
force_check = True
|
||||
i += 1
|
||||
elif myarg == u'simple':
|
||||
simple = True
|
||||
i += 1
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam version"' % sys.argv[i]
|
||||
sys.exit(2)
|
||||
if simple:
|
||||
sys.stdout.write(__version__)
|
||||
sys.exit(0)
|
||||
return
|
||||
import struct
|
||||
version_data = u'GAM {0} - {1}\n{2}\nPython {3}.{4}.{5} {6}-bit {7}\ngoogle-api-python-client {8}\n{9} {10}\nPath: {11}'
|
||||
print version_data.format(__version__, GAM_URL, __author__, sys.version_info[0],
|
||||
sys.version_info[1], sys.version_info[2], struct.calcsize(u'P')*8,
|
||||
sys.version_info[3], googleapiclient.__version__, platform.platform(),
|
||||
platform.machine(), GM_Globals[GM_GAM_PATH])
|
||||
if checkForCheck or force_check:
|
||||
sys.version_info[1], sys.version_info[2], struct.calcsize(u'P')*8,
|
||||
sys.version_info[3], googleapiclient.__version__, platform.platform(),
|
||||
platform.machine(), GM_Globals[GM_GAM_PATH])
|
||||
if force_check:
|
||||
doGAMCheckForUpdates(forceCheck=True)
|
||||
|
||||
def handleOAuthTokenError(e, soft_errors):
|
||||
@@ -1214,17 +1214,17 @@ def doCheckServiceAccount(users):
|
||||
for scope in scopes:
|
||||
if scope in all_scopes:
|
||||
continue # don't check same scope twice
|
||||
all_scopes.append(scope)
|
||||
all_scopes.append((api, scope))
|
||||
all_scopes = sorted(all_scopes)
|
||||
for scope in all_scopes:
|
||||
try:
|
||||
service = buildGAPIServiceObject(api, act_as=user, use_scopes=scope)
|
||||
service = buildGAPIServiceObject(scope[0], act_as=user, use_scopes=scope[1])
|
||||
service._http.request.credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]))
|
||||
result = u'PASS'
|
||||
except oauth2client.client.HttpAccessTokenRefreshError:
|
||||
result = u'FAIL'
|
||||
all_scopes_pass = False
|
||||
print u' Scope: {0:60} {1}'.format(scope, result)
|
||||
print u' Scope: {0:60} {1}'.format(scope[1], result)
|
||||
service_account = service._http.request.credentials.serialization_data[u'client_id']
|
||||
if all_scopes_pass:
|
||||
print u'\nAll scopes passed!\nService account %s is fully authorized.' % service_account
|
||||
@@ -1241,7 +1241,7 @@ and grant Client name:
|
||||
|
||||
Access to scopes:
|
||||
|
||||
%s\n''' % (user_domain, service_account, ','.join(all_scopes))
|
||||
%s\n''' % (user_domain, service_account, ',\n'.join([scope[1] for scope in all_scopes]))
|
||||
sys.exit(int(not all_scopes_pass))
|
||||
|
||||
def showReport():
|
||||
@@ -3318,6 +3318,42 @@ def doCalendarWipeData():
|
||||
return
|
||||
callGAPI(cal.calendars(), u'clear', calendarId=calendarId)
|
||||
|
||||
def doCalendarDeleteEvent():
|
||||
calendarId, cal = buildCalendarGAPIObject(sys.argv[2])
|
||||
if not cal:
|
||||
return
|
||||
events = []
|
||||
sendNotifications = None
|
||||
doit = False
|
||||
i = 4
|
||||
while (i < len(sys.argv)):
|
||||
if sys.argv[i].lower() == u'notifyattendees':
|
||||
sendNotifications = True
|
||||
i += 1
|
||||
elif sys.argv[i].lower() in [u'id', u'eventid']:
|
||||
events.append(sys.argv[i+1])
|
||||
i += 2
|
||||
elif sys.argv[i].lower() in [u'query', u'eventquery']:
|
||||
query = sys.argv[i+1]
|
||||
result = callGAPIpages(cal.events(), u'list', items=u'items', calendarId=calendarId, q=query)
|
||||
for event in result:
|
||||
if u'id' in event:
|
||||
events.append(event[u'id'])
|
||||
i += 2
|
||||
elif sys.argv[i].lower() == u'doit':
|
||||
doit = True
|
||||
i += 1
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for gam calendar <email> delete event'
|
||||
sys.exit(3)
|
||||
if doit:
|
||||
for eventId in events:
|
||||
print u' deleting eventId %s' % eventId
|
||||
callGAPI(cal.events(), u'delete', calendarId=calendarId, eventId=eventId)
|
||||
else:
|
||||
for eventId in events:
|
||||
print u' would delete eventId %s. Add doit to command to actually delete event' % eventId
|
||||
|
||||
def doCalendarAddEvent():
|
||||
calendarId, cal = buildCalendarGAPIObject(sys.argv[2])
|
||||
if not cal:
|
||||
@@ -6807,7 +6843,7 @@ def doCreateProject():
|
||||
login_hint = sys.argv[3]
|
||||
except IndexError:
|
||||
while True:
|
||||
login_hint = raw_input(u'What is your G Suite admin email address? ')
|
||||
login_hint = raw_input(u'\nWhat is your G Suite admin email address? ')
|
||||
if login_hint.find(u'@') == -1:
|
||||
print u'Error: that is not a valid email address'
|
||||
else:
|
||||
@@ -6817,12 +6853,12 @@ def doCreateProject():
|
||||
for i in range(3):
|
||||
project_id += u'-%s' % ''.join(random.choice(string.digits + string.ascii_lowercase) for i in range(3))
|
||||
project_name = u'project:%s' % project_id
|
||||
scope=u'https://www.googleapis.com/auth/cloud-platform'
|
||||
client_id=u'297408095146-fug707qsjv4ikron0hugpevbrjhkmsk7.apps.googleusercontent.com'
|
||||
client_secret=u'qM3dP8f_4qedwzWQE1VR4zzU'
|
||||
scope = u'https://www.googleapis.com/auth/cloud-platform'
|
||||
client_id = u'297408095146-fug707qsjv4ikron0hugpevbrjhkmsk7.apps.googleusercontent.com'
|
||||
client_secret = u'qM3dP8f_4qedwzWQE1VR4zzU'
|
||||
flow = oauth2client.client.OAuth2WebServerFlow(client_id=client_id,
|
||||
client_secret=client_secret, scope=scope, redirect_uri=oauth2client.client.OOB_CALLBACK_URN,
|
||||
user_agent=GAM_INFO, access_type=u'online', response_type=u'code', login_hint=login_hint)
|
||||
client_secret=client_secret, scope=scope, redirect_uri=oauth2client.client.OOB_CALLBACK_URN,
|
||||
user_agent=GAM_INFO, access_type=u'online', response_type=u'code', login_hint=login_hint)
|
||||
flags = cmd_flags(noLocalWebserver=GC_Values[GC_NO_BROWSER])
|
||||
storage_dict = {}
|
||||
storage = DictionaryStorage(storage_dict, u'credentials')
|
||||
@@ -6875,15 +6911,15 @@ and accept the Terms of Service (ToS). As soon as you've accepted the ToS popup,
|
||||
|
||||
serveman = googleapiclient.discovery.build(u'servicemanagement', u'v1', http=http, cache_discovery=False)
|
||||
apis = [u'admin-json.googleapis.com', u'appsactivity-json.googleapis.com', u'calendar-json.googleapis.com',
|
||||
u'classroom.googleapis.com', u'drive', u'gmail-json.googleapis.com', u'groupssettings-json.googleapis.com',
|
||||
u'licensing-json.googleapis.com', u'plus-json.googleapis.com', u'contacts-json.googleapis.com']
|
||||
u'classroom.googleapis.com', u'drive', u'gmail-json.googleapis.com', u'groupssettings-json.googleapis.com',
|
||||
u'licensing-json.googleapis.com', u'plus-json.googleapis.com', u'contacts-json.googleapis.com']
|
||||
for api in apis:
|
||||
print u' enabling API %s...' % api
|
||||
enable_operation = callGAPI(serveman.services(), u'enable', serviceName=api, body={u'consumerId': project_name})
|
||||
iam = googleapiclient.discovery.build(u'iam', u'v1', http=http, cache_discovery=False)
|
||||
print u'Creating Service Account'
|
||||
service_account = callGAPI(iam.projects().serviceAccounts(), u'create', name=u'projects/%s' % project_id,
|
||||
body={u'accountId': project_id, u'serviceAccount': {u'displayName': u'GAM Project'}})
|
||||
body={u'accountId': project_id, u'serviceAccount': {u'displayName': u'GAM Project'}})
|
||||
body = {u'privateKeyType': u'TYPE_GOOGLE_CREDENTIALS_FILE', u'keyAlgorithm': u'KEY_ALG_RSA_4096'}
|
||||
key = callGAPI(iam.projects().serviceAccounts().keys(), u'create', name=service_account[u'name'], body=body)
|
||||
oauth2service_data = base64.b64decode(key[u'privateKeyData'])
|
||||
@@ -6923,7 +6959,7 @@ and accept the Terms of Service (ToS). As soon as you've accepted the ToS popup,
|
||||
client_secrets_file = os.path.join(GM_Globals[GM_GAM_PATH], FN_CLIENT_SECRETS_JSON)
|
||||
if os.path.isfile(client_secrets_file):
|
||||
client_secrets_file = u'%s-%s' % (client_secrets_file, project_id)
|
||||
writeFile(client_secrets_file, cs_data, continueOnError=False)
|
||||
writeFile(client_secrets_file, cs_data, continueOnError=False)
|
||||
print u'''Almost there! Now please switch back to your browser and:
|
||||
|
||||
1. Click OK to close "OAuth client" popup if it's still open.
|
||||
@@ -9942,7 +9978,7 @@ OAUTH2_MENU += '''
|
||||
OAUTH2_CMDS = [u's', u'u', u'e', u'c']
|
||||
MAXIMUM_SCOPES = 28
|
||||
|
||||
def doRequestOAuth():
|
||||
def doRequestOAuth(login_hint=None):
|
||||
def _checkMakeScopesList(scopes):
|
||||
del scopes[:]
|
||||
for i in range(num_scopes):
|
||||
@@ -9965,7 +10001,9 @@ def doRequestOAuth():
|
||||
MISSING_CLIENT_SECRETS_MESSAGE = u"""Please configure OAuth 2.0
|
||||
|
||||
To make GAM run you will need to populate the {0} file found at:
|
||||
|
||||
{1}
|
||||
|
||||
with information from the APIs Console <https://console.developers.google.com>.
|
||||
|
||||
See this site for instructions:
|
||||
@@ -9973,6 +10011,24 @@ See this site for instructions:
|
||||
|
||||
""".format(FN_CLIENT_SECRETS_JSON, GC_Values[GC_CLIENT_SECRETS_JSON], GAM_WIKI_CREATE_CLIENT_SECRETS)
|
||||
|
||||
cs_data = readFile(GC_Values[GC_CLIENT_SECRETS_JSON], mode=u'rb', continueOnError=True, displayError=True, encoding=None)
|
||||
if not cs_data:
|
||||
systemErrorExit(14, MISSING_CLIENT_SECRETS_MESSAGE)
|
||||
try:
|
||||
cs_json = json.loads(cs_data)
|
||||
client_id = cs_json[u'installed'][u'client_id']
|
||||
client_secret = cs_json[u'installed'][u'client_secret']
|
||||
except (ValueError, IndexError, KeyError):
|
||||
print u'ERROR: the format of your client secrets file:\n\n%s\n\n is incorrect. Please recreate the file.'
|
||||
sys.exit(3)
|
||||
|
||||
if not login_hint:
|
||||
while True:
|
||||
login_hint = raw_input(u'\nWhat is your G Suite admin email address? ')
|
||||
if login_hint.find(u'@') == -1:
|
||||
print u'Error: that is not a valid email address'
|
||||
else:
|
||||
break
|
||||
num_scopes = len(OAUTH2_SCOPES)
|
||||
menu = OAUTH2_MENU % tuple(range(num_scopes))
|
||||
selected_scopes = []
|
||||
@@ -10034,19 +10090,20 @@ See this site for instructions:
|
||||
status, message = _checkMakeScopesList(scopes)
|
||||
if status:
|
||||
break
|
||||
try:
|
||||
FLOW = oauth2client.client.flow_from_clientsecrets(GC_Values[GC_CLIENT_SECRETS_JSON], scope=scopes)
|
||||
except oauth2client.client.clientsecrets.InvalidClientSecretsError:
|
||||
systemErrorExit(14, MISSING_CLIENT_SECRETS_MESSAGE)
|
||||
flow = oauth2client.client.OAuth2WebServerFlow(client_id=client_id,
|
||||
client_secret=client_secret, scope=scopes, redirect_uri=oauth2client.client.OOB_CALLBACK_URN,
|
||||
user_agent=GAM_INFO, access_type=u'offline', response_type=u'code', login_hint=login_hint)
|
||||
storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT])
|
||||
credentials = storage.get()
|
||||
flags = cmd_flags(noLocalWebserver=GC_Values[GC_NO_BROWSER])
|
||||
if credentials is None or credentials.invalid:
|
||||
http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL])
|
||||
try:
|
||||
credentials = oauth2client.tools.run_flow(flow=FLOW, storage=storage, flags=flags, http=http)
|
||||
credentials = oauth2client.tools.run_flow(flow=flow, storage=storage, flags=flags, http=http)
|
||||
except httplib2.CertificateValidationUnsupported:
|
||||
noPythonSSLExit()
|
||||
else:
|
||||
print u'It looks like you\'ve already authorized GAM. Refusing to overwrite existing file:\n\n%s' % GC_Values[GC_OAUTH2_TXT]
|
||||
|
||||
def batch_worker():
|
||||
while True:
|
||||
@@ -10418,7 +10475,11 @@ def ProcessGAMCommand(args):
|
||||
elif command in [u'oauth', u'oauth2']:
|
||||
argument = sys.argv[2].lower()
|
||||
if argument in [u'request', u'create']:
|
||||
doRequestOAuth()
|
||||
try:
|
||||
login_hint = sys.argv[3]
|
||||
except IndexError:
|
||||
login_hint = None
|
||||
doRequestOAuth(login_hint)
|
||||
elif argument in [u'info', u'verify']:
|
||||
OAuthInfo()
|
||||
elif argument in [u'delete', u'revoke']:
|
||||
@@ -10441,6 +10502,8 @@ def ProcessGAMCommand(args):
|
||||
doCalendarWipeData()
|
||||
elif argument == u'addevent':
|
||||
doCalendarAddEvent()
|
||||
elif argument == u'deleteevent':
|
||||
doCalendarDeleteEvent()
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam calendar"' % argument
|
||||
sys.exit(2)
|
||||
@@ -10742,6 +10805,9 @@ def ProcessGAMCommand(args):
|
||||
checkWhat = sys.argv[4].replace(u'_', '').lower()
|
||||
if checkWhat == u'serviceaccount':
|
||||
doCheckServiceAccount(users)
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam <users> check"' % checkWhat
|
||||
sys.exit(2)
|
||||
elif command == u'profile':
|
||||
doProfile(users)
|
||||
elif command == u'imap':
|
||||
|
||||
11
src/gam.wxs
11
src/gam.wxs
@@ -52,6 +52,12 @@
|
||||
<Component Id="whatsnew_txt" Guid="6aa9863c-90d9-412f-9b73-fda82549a950">
|
||||
<File Name="whatsnew.txt" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="gam_setup_bat" Guid="ef01f93a-4b50-488a-9c04-ec5e13e66218">
|
||||
<File Name="gam-setup.bat" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="gamcommands_txt" Guid="58ff9c45-a7c9-4e22-8845-a9a92610c1f3">
|
||||
<File Name="gamcommands.txt" KeyPath="yes" />
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
|
||||
@@ -59,7 +65,10 @@
|
||||
<InstallUISequence>
|
||||
<ExecuteAction />
|
||||
<Show Dialog="WelcomeDlg" Before="ProgressDlg" />
|
||||
<!-- <Show Dialog="ProgressDlg" After="" /> -->
|
||||
</InstallUISequence>
|
||||
<CustomAction Id="setup_gam" ExeCommand="[INSTALLFOLDER]gam-setup.bat" Directory="INSTALLFOLDER" Execute="commit" Impersonate="yes" Return="asyncWait"/>
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="setup_gam" After="InstallFiles" >NOT Installed AND NOT UPGRADINGPRODUCTCODE AND NOT WIX_UPGRADE_DETECTED</Custom>
|
||||
</InstallExecuteSequence>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
||||
@@ -273,7 +273,7 @@ class Credentials(object):
|
||||
to_serialize[key] = val.decode('utf-8')
|
||||
if isinstance(val, set):
|
||||
to_serialize[key] = list(val)
|
||||
return json.dumps(to_serialize)
|
||||
return json.dumps(to_serialize, indent=4, sort_keys=True)
|
||||
|
||||
def to_json(self):
|
||||
"""Creating a JSON representation of an instance of Credentials.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
GAM 4.02
|
||||
- "gam create project" command simplifies creation of client_secrets.json and oauth2service.json project files.
|
||||
- Automated wizard simplifies GAM setup on Linux and MacOS (coming soon to Windows MSI).
|
||||
- "gam calendar <email> deleteevent" deletes events by ID or query
|
||||
|
||||
GAM 3.8
|
||||
- Old GData APIs removed from GAM. Admin Settings and Email Audit commands are no longer included, keep a copy of GAM 3.72 around if you use them. All Email Settings commands now use new Gmail API.
|
||||
- Updated httplib2, google-api-client, uritemplate libraries
|
||||
|
||||
@@ -11,12 +11,16 @@ del /q /f gam.wixpdb
|
||||
c:\python27-32\scripts\pyinstaller --clean -F --distpath=gam windows-gam.spec
|
||||
xcopy LICENSE gam\
|
||||
xcopy whatsnew.txt gam\
|
||||
xcopy gam-setup.bat gam\
|
||||
xcopy gamcommands.txt gam\
|
||||
del gam\w9xpopen.exe
|
||||
"%ProgramFiles%\7-Zip\7z.exe" a -tzip gam-%1-windows.zip gam\ -xr!.svn
|
||||
|
||||
c:\python27-64\scripts\pyinstaller --clean -F --distpath=gam-64 windows-gam.spec
|
||||
xcopy LICENSE gam-64\
|
||||
xcopy whatsnew.txt gam-64\
|
||||
xcopy gam-setup.bat gam-64\
|
||||
xcopy gamcommands.txt gam-64\
|
||||
"%ProgramFiles%\7-Zip\7z.exe" a -tzip gam-%1-windows-x64.zip gam-64\ -xr!.svn
|
||||
|
||||
set GAMVERSION=%1
|
||||
|
||||
Reference in New Issue
Block a user