mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-05 14:51:39 +00:00
Compare commits
176 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3090c59582 | ||
|
|
1de7e32f25 | ||
|
|
2bf058b089 | ||
|
|
c507714ab6 | ||
|
|
cdc72d2f23 | ||
|
|
2368adfebd | ||
|
|
46c000f6d1 | ||
|
|
4254ed4d86 | ||
|
|
3233807c17 | ||
|
|
b3501a2d4a | ||
|
|
3d5ac7c448 | ||
|
|
11e2a3845d | ||
|
|
9812c23513 | ||
|
|
5c02c1b50c | ||
|
|
f3f3f91fcb | ||
|
|
f8be56efdc | ||
|
|
dcae0155b2 | ||
|
|
7c21c670dc | ||
|
|
44c0d4bf15 | ||
|
|
39159d3ce7 | ||
|
|
62565d7c97 | ||
|
|
b8b268f0ad | ||
|
|
4182b3cd1e | ||
|
|
24c0390174 | ||
|
|
2b336d8c9f | ||
|
|
5b02a22d77 | ||
|
|
b680a6bf12 | ||
|
|
2b65d87bfa | ||
|
|
e214ad8154 | ||
|
|
3bf2ecc6e3 | ||
|
|
594e10d0a4 | ||
|
|
656f87f89c | ||
|
|
a5dd9b69e3 | ||
|
|
ae8949c6d6 | ||
|
|
eeb29355f1 | ||
|
|
4dea7cb650 | ||
|
|
da4177f0e4 | ||
|
|
c7b44ae8d9 | ||
|
|
37726c493d | ||
|
|
83af5ee757 | ||
|
|
34b9029e90 | ||
|
|
4596accf5a | ||
|
|
0034704b3f | ||
|
|
a334645910 | ||
|
|
6519a5b007 | ||
|
|
0aabe4ae9b | ||
|
|
0a41b4ec68 | ||
|
|
9cf4a151aa | ||
|
|
10fcf566b8 | ||
|
|
2704a8b695 | ||
|
|
09814b7dcd | ||
|
|
4f2ce2625d | ||
|
|
9c368b7d10 | ||
|
|
f9bd5506c7 | ||
|
|
4a168d16a3 | ||
|
|
b817bd04ec | ||
|
|
43adae4e70 | ||
|
|
77ebba9c62 | ||
|
|
ee517c1800 | ||
|
|
154099c3f4 | ||
|
|
1746845651 | ||
|
|
d07ab2d7e1 | ||
|
|
f3b970ae14 | ||
|
|
16d8cddf12 | ||
|
|
671f7d810c | ||
|
|
0d94dd3fa5 | ||
|
|
eb5cfde630 | ||
|
|
aa04e3ec1d | ||
|
|
0333e29eef | ||
|
|
8929ee534f | ||
|
|
8eb347488f | ||
|
|
f8642a18df | ||
|
|
12ccd58eae | ||
|
|
95bb288e38 | ||
|
|
5c64f0825f | ||
|
|
25e97b97d4 | ||
|
|
d258d4da63 | ||
|
|
cb79688a73 | ||
|
|
dae75f6234 | ||
|
|
0209b51c4d | ||
|
|
f35c188496 | ||
|
|
c00d820c75 | ||
|
|
69689e286b | ||
|
|
5697580bd0 | ||
|
|
2288e99e56 | ||
|
|
c8fd6e76af | ||
|
|
23cb9afec7 | ||
|
|
20e8175ae1 | ||
|
|
3a38dceb5f | ||
|
|
c885cdefbb | ||
|
|
b7d5374718 | ||
|
|
59a0aadd72 | ||
|
|
a3f218a98d | ||
|
|
0424ced649 | ||
|
|
9f75968684 | ||
|
|
90fd503838 | ||
|
|
a7a3f2eef6 | ||
|
|
008a65329e | ||
|
|
2390c4284e | ||
|
|
75483185d6 | ||
|
|
acb21cb926 | ||
|
|
c0ee674060 | ||
|
|
7d69c8e3bd | ||
|
|
38a37c49de | ||
|
|
a36478b1f5 | ||
|
|
bcb17cd0a5 | ||
|
|
1ec164a25a | ||
|
|
571a9dcb3e | ||
|
|
a0ac6265e9 | ||
|
|
ea6f49f7be | ||
|
|
0470680a4d | ||
|
|
e0c52c8660 | ||
|
|
3182ce031c | ||
|
|
f6dd0ccd12 | ||
|
|
775b0c8c60 | ||
|
|
1c4424dd0b | ||
|
|
8501aec7bc | ||
|
|
05a36d3245 | ||
|
|
2bf8f9164e | ||
|
|
56732ea3e8 | ||
|
|
7a4b32aadb | ||
|
|
16add1bf24 | ||
|
|
433cdfe87d | ||
|
|
a3d0a0250a | ||
|
|
b037333d2b | ||
|
|
bf6c2ef266 | ||
|
|
abde922b49 | ||
|
|
eca89ca5e9 | ||
|
|
a91c987107 | ||
|
|
12166e2245 | ||
|
|
e612c20141 | ||
|
|
d2039e5566 | ||
|
|
20bba75e41 | ||
|
|
2d26b647c8 | ||
|
|
ab0bec7a7b | ||
|
|
b6c5f1b1e7 | ||
|
|
881cc4d255 | ||
|
|
3d61973071 | ||
|
|
5ae1f3c441 | ||
|
|
6ae4cf495d | ||
|
|
900fc9c4e3 | ||
|
|
0207e84551 | ||
|
|
3a2d663c86 | ||
|
|
7aaaaf9125 | ||
|
|
e051b9bffa | ||
|
|
df0bcda952 | ||
|
|
d871378336 | ||
|
|
f99add7a3f | ||
|
|
7515700b1a | ||
|
|
99db4d50d3 | ||
|
|
0cd8246bdb | ||
|
|
29ee81ef18 | ||
|
|
9e09c06770 | ||
|
|
65603ca314 | ||
|
|
a983d23f91 | ||
|
|
3545306559 | ||
|
|
08163cc5cd | ||
|
|
c629c3424c | ||
|
|
ef403119d9 | ||
|
|
798c126881 | ||
|
|
813d503bb8 | ||
|
|
7e71a06c5f | ||
|
|
68475a00c1 | ||
|
|
4d71b6943c | ||
|
|
42caddb8a3 | ||
|
|
52d8604099 | ||
|
|
2df3aef52d | ||
|
|
9773e25932 | ||
|
|
cd766d90e4 | ||
|
|
8f69fc84a8 | ||
|
|
a8f0882220 | ||
|
|
d79c28d2d3 | ||
|
|
ba756d12b2 | ||
|
|
48e6872233 | ||
|
|
5037a9bbfd | ||
|
|
a58e5e4276 |
14
.github/ISSUE_TEMPLATE.txt
vendored
Normal file
14
.github/ISSUE_TEMPLATE.txt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
The issue tracker is for reporting product deficiencies. "How do I?" questions should be posted to the discussion forum at https://groups.google.com/group/google-apps-manager. When in doubt, start at the discussion forum and return here only when instructed to do so.
|
||||
|
||||
Please confirm the following:
|
||||
* I have upgraded to the latest GAM release from https://git.io/gamreleases and I still have this issue.
|
||||
* I am typing the command as described in the GAM Wiki at https://github.com/jay0lee/gam/wiki
|
||||
|
||||
Full steps to reproduce the issue:
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
Expected outcome (what are you trying to do?):
|
||||
|
||||
Actual outcome (what errors or bad behavior do you see instead?):
|
||||
3
src/.gitignore
vendored
3
src/.gitignore
vendored
@@ -67,3 +67,6 @@ gamcache/
|
||||
gam/
|
||||
gam-64/
|
||||
*.zip
|
||||
*.msi
|
||||
*.wixobj
|
||||
*.wixpdb
|
||||
|
||||
@@ -16,7 +16,7 @@ If an item contains spaces, it should be surrounded by " or '.
|
||||
<String> ::= a string of characters, surrounded by " or ' if it contains spaces
|
||||
<TrueValues> ::= true|on|yes|enabled|1
|
||||
<FalseValues>= false|off|no|disabled|0
|
||||
<DataTransferService> ::= googleplus|google+|gplus|g+|googledrive|gdrive
|
||||
<DataTransferService> ::= googleplus|google+|gplus|g+|googledrive|gdrive|drive
|
||||
<ProductID> ::= Google-Apps|Google-Coordinate|Google-Drive-storage|Google-Vault
|
||||
<SKUID> ::= apps|gafb|gafw|gams|gau|unlimited|d4w|dfw|coordinate|vault|vfe|
|
||||
drive-20gb|drive20gb|20gb|drive-50gb|drive50gb|50gb|drive-200gb|drive200gb|200gb|drive-400gb|drive400gb|400gb|
|
||||
@@ -27,7 +27,7 @@ If an item contains spaces, it should be surrounded by " or '.
|
||||
|
||||
# Basic items built from primatives
|
||||
<Boolean> ::= <TrueValues>|<FalseValues>
|
||||
<ByteCount> ::= <Number>[M|K|B]
|
||||
<ByteCount> ::= <Number>[m|k|b]
|
||||
<CIDRnetmask> ::= <Number>.<Number>.<Number>.<Number>/<Number>
|
||||
<ColorHex> ::= #<Hex><Hex><Hex><Hex><Hex><Hex>
|
||||
<DomainName> ::= <String>(.<String>)+
|
||||
@@ -58,11 +58,9 @@ If an item contains spaces, it should be surrounded by " or '.
|
||||
<CourseParticipantType> ::= teacher|teachers|student|students
|
||||
<CrOSID> ::= <String>
|
||||
<CrOSItem> ::= <CrOSID>|(query:<QueryCrOS>)|(query <QueryCrOS>)
|
||||
<DestEmailAddress> ::= <EmailAddress>
|
||||
<DomainAlias> ::= <String>
|
||||
<DriveFileACLRole> :: =commenter|editor|owner|reader|writer
|
||||
<EventColorIndex> ::== <Number in range 1-11>
|
||||
<FieldName> ::= <String>
|
||||
<DestEmailAddress> ::= <EmailAddress>
|
||||
<DriveFileID> ::= <String>
|
||||
<DriveFileURL> :: = https://docs.google.com/a/<DomainName>/document/d/<DriveFileID>/<String>
|
||||
<DriveFileItem> ::= <DriveFileID>|<DriveFileURL>
|
||||
@@ -70,6 +68,7 @@ If an item contains spaces, it should be surrounded by " or '.
|
||||
<DriveFolderID> ::= <String>
|
||||
<DriveFolderName> ::= <String>
|
||||
<EmailItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||
<EventColorIndex> ::== <Number in range 1-11>
|
||||
<EventID> ::= <String>
|
||||
<FieldName> ::= <String>
|
||||
<FileName> ::= <String>
|
||||
@@ -90,9 +89,11 @@ If an item contains spaces, it should be surrounded by " or '.
|
||||
<NotificationID> ::= <String>
|
||||
<OrgUnitID> ::= <String>
|
||||
<OrgUnitPath> ::= /|(/<String)+
|
||||
<ParameterKey> ::= <String>
|
||||
<ParameterValue> ::= <String>
|
||||
<PermissionID> ::= id:<String>|<EmailAddress>|anyone|anyonewithlink
|
||||
<PrinterID> ::= <String>
|
||||
<PrintJobAge> ::= <Number>(m|h|d)
|
||||
<PrintJobAge> ::= <Number>[m|h|d]
|
||||
<PrintJobID> ::= <String>
|
||||
<PrintJobStatus> ::= done|error|held|in_progress|queued|submitted
|
||||
<PropertyKey> ::= <String>
|
||||
@@ -201,24 +202,22 @@ If an item contains spaces, it should be surrounded by " or '.
|
||||
<GroupFieldName> ::=
|
||||
admincreated|
|
||||
aliases|
|
||||
description|
|
||||
email|
|
||||
id|
|
||||
name
|
||||
|
||||
<GroupSettingsFieldName> ::=
|
||||
allowexternalmembers|
|
||||
allowgooglecommunication|
|
||||
allowwebposting|
|
||||
archiveonly|
|
||||
customreplyto|
|
||||
defaultmessagedenynotificationtext|
|
||||
description|
|
||||
email|
|
||||
id|
|
||||
includeinglobaladdresslist|gal|
|
||||
isarchived|
|
||||
maxmessagebytes|
|
||||
memberscanpostasthegroup|
|
||||
messagedisplayfont|
|
||||
messagemoderationlevel|
|
||||
name
|
||||
primarylanguage|
|
||||
replyto|
|
||||
sendmessagedenynotification|
|
||||
@@ -304,7 +303,6 @@ If an item contains spaces, it should be surrounded by " or '.
|
||||
<FileFormatList> ::= '<FileFormat>(,<FileFormat)*'
|
||||
<FilterIDList> ::= '<FilterID>(,<FilterID>)*'
|
||||
<GroupFieldNameList> ::= '<GroupFieldName(,<GroupFieldName>)*'
|
||||
<GroupSettingsFieldNameList> ::= '<GroupSettingsFieldName(,<GroupSettingsFieldName>)*'
|
||||
<GroupList> ::= '<GroupItem>(,<GroupItem>)*'
|
||||
<GuardianStateList> ::= '<GuardianState>(,<GuardianState>)*'
|
||||
<LabelNameList> ::= '<LabelName>(,<LabelName)*'
|
||||
@@ -387,10 +385,12 @@ If an item contains spaces, it should be surrounded by " or '.
|
||||
(allowgooglecommunication <Boolean>)|
|
||||
(allowwebposting <Boolean>)|
|
||||
(archiveonly <Boolean>)|
|
||||
(customfootertext <String>)|
|
||||
(customreplyto <EmailAddress>)|
|
||||
(defaultmessagedenynotificationtext <String>)|
|
||||
(description <String>)|
|
||||
(gal|includeInGlobalAddressList <Boolean>)|
|
||||
(includecustomfooter <Boolean>)|
|
||||
(isarchived <Boolean>)|
|
||||
(maxmessagebytes <ByteCount>)|
|
||||
(memberscanpostasthegroup <Boolean>)|
|
||||
@@ -457,7 +457,7 @@ gam version
|
||||
gam help
|
||||
|
||||
gam batch <FileName>|- [charset <Charset>]
|
||||
gam csv <FileName>|- [charset <Charset>] [matchfield <FieldName> <RegularExpression>] gam <GAM argument list>
|
||||
gam csv <FileName>|- [charset <Charset>] gam <GAM argument list>
|
||||
|
||||
gam oauth|oauth2 create|request
|
||||
gam oauth|oauth2 delete|revoke
|
||||
@@ -495,7 +495,7 @@ gam update customer [adminsecondaryemail|alternateemail <EmailAddress>] [languag
|
||||
[address1|addressline1 <String>] [address2|addressline2 <String>] [address3|addressline3 <String>]
|
||||
[locality <String>] [region <String>] [postalcode <String>] [country|countrycode <String>]
|
||||
|
||||
gam create datatransfer|transfer <OldOwnerID> <DataTransferService> <NewOwnerID>
|
||||
gam create datatransfer|transfer <OldOwnerID> <DataTransferService> <NewOwnerID> (<ParameterKey> <ParameterValue>)*
|
||||
gam info datatransfer|transfer <TransferID>
|
||||
gam print datatransfers|transfers [todrive] [olduser|oldowner <UserItem>] [newuser|newowner <UserItem>] [status <String>]
|
||||
|
||||
@@ -585,7 +585,7 @@ gam update group <GroupItem> clear [owner] [manager] [member]
|
||||
|
||||
gam print groups [todrive] ([domain <DomainName>] [member <UserItem>])
|
||||
[maxresults <Number>] [delimiter <String>]
|
||||
[members] [owners] [managers] [settings] <GroupFieldName>* [fields <GroupFieldNameList>|<GroupSettingsFieldNameList>]
|
||||
[members] [owners] [managers] [settings] <GroupFieldName>* [fields <GroupFieldNameList>]
|
||||
|
||||
|
||||
gam print group-members|groups-members [todrive] ([domain <DomainName>] [member <UserItem>])|[group <GroupItem>]
|
||||
@@ -643,11 +643,12 @@ gam course <CourseID> delete alias <CourseAlias>
|
||||
gam course <CourseID> add teachers|students <UserItem>
|
||||
gam course <CourseID> delete|remove teachers|students <UserItem>
|
||||
gam course <CourseID> sync teachers|students <UserTypeEntity>
|
||||
gam print course-participants [todrive](course <CourseID>)* [teacher] [student] [show all|students|teachers]
|
||||
gam print course-participants [todrive] (course|class <CourseID>)*|([teacher <UserItem>] [student <UserItem>]) [show all|students|teachers]
|
||||
|
||||
gam create guardian|guardianinvite|inviteguardian <EmailAddress> <UserItem>
|
||||
gam delete guardian|guardians <GuardianID <UserItem>
|
||||
gam print guardian|guardians [nocsv] [todrive] [invitedguardian <GuardianID>] [student <UserItem>] [invitations] [states <GuardianStateList>] [<UserTypeEntity>]
|
||||
gam delete guardian|guardians <GuardianID>|<EmailAddress> <UserItem>
|
||||
gam show guardian|guardians [invitedguardian <GuardianID>] [student <UserItem>] [invitations] [states <GuardianStateList>] [<UserTypeEntity>]
|
||||
gam print guardian|guardians [todrive] [invitedguardian <GuardianID>] [student <UserItem>] [invitations] [states <GuardianStateList>] [<UserTypeEntity>]
|
||||
|
||||
gam printer register
|
||||
gam update printer <PrinterID> <PrinterAttributes>+
|
||||
@@ -697,6 +698,7 @@ gam <UserTypeEntity> transfer seccals <UserItem> [keepuser]
|
||||
gam <UserTypeEntity> print|show driveactivity [todrive] [fileid <DriveFileID>] [folderid <DriveFolderID>]
|
||||
gam <UserTypeEntity> print|show drivesettings [todrive]
|
||||
gam <UserTypeEntity> print|show filelist [todrive] [query <QueryDriveFile>] [allfields|<DriveFieldName>*]
|
||||
|
||||
gam <UserTypeEntity> show fileinfo <DriveFileID> [allfields|<DriveFieldName>*]
|
||||
gam <UserTypeEntity> show filerevisions <DriveFileID>
|
||||
gam <UserTypeEntity> show filetree
|
||||
@@ -709,7 +711,6 @@ gam <UserTypeEntity> transfer drive <UserItem> [keepuser]
|
||||
gam <UserTypeEntity> delete|del emptydrivefolders
|
||||
gam <UserTypeEntity> empty drivetrash
|
||||
|
||||
|
||||
gam <UserTypeEntity> add drivefileacl <DriveFileID> anyone|(user <UserItem>)|(group <GroupItem>)|(domain <DomainName>)
|
||||
(role <DriveFileACLRole>) [withlink] [sendmail] [emailmessage <String>]
|
||||
gam <UserTypeEntity> update drivefileacl <DriveFileID> <PermissionID>
|
||||
@@ -794,8 +795,8 @@ gam <UserTypeEntity> language <Language>
|
||||
|
||||
gam <UserTypeEntity> pagesize 25|50|100
|
||||
|
||||
gam <UserTypeEntity> [add] sendas <EmailAddress> <Name> [replyto <EmailAddress>] [default] [treatasalias <Boolean>] [signature|sig <String>|(file <FileName> [charset <CharSet>]) (replace <RegularExpression> <String>)*]
|
||||
gam <UserTypeEntity> update sendas <EmailAddress> [name <Name>] [replyto <EmailAddress>] [default] [treatasalias <Boolean>] [signature|sig <String>|(file <FileName> [charset <CharSet>]) (replace <RegularExpression> <String>)*]
|
||||
gam <UserTypeEntity> [add] sendas <EmailAddress> <Name> [signature|sig <String>|(file <FileName> [charset <CharSet>]) (replace <RegularExpression> <String>)*] [replyto <EmailAddress>] [default] [treatasalias <Boolean>]
|
||||
gam <UserTypeEntity> update sendas <EmailAddress> [name <Name>] [signature|sig <String>|(file <FileName> [charset <CharSet>]) (replace <RegularExpression> <String>)*] [replyto <EmailAddress>] [default] [treatasalias <Boolean>]
|
||||
gam <UserTypeEntity> delete sendas <EmailAddress>
|
||||
gam <UserTypeEntity> show sendas [format]
|
||||
gam <UserTypeEntity> info sendas <EmailAddress> [format]
|
||||
@@ -803,7 +804,7 @@ gam <UserTypeEntity> print sendas [todrive]
|
||||
|
||||
gam <UserTypeEntity> shortcuts <Boolean>
|
||||
|
||||
gam <UserTypeEntity> signature|sig <String>|(file <FileName> [charset <Charset>]) (replace <Tag> <String>)* [name <String>] [replyto <EmailAddress>]
|
||||
gam <UserTypeEntity> signature|sig <String>|(file <FileName> [charset <Charset>]) (replace <Tag> <String>)* [name <String>] [replyto <EmailAddress>] [default] [treatasalias <Boolean>]
|
||||
gam <UserTypeEntity> show signature|sig [format]
|
||||
|
||||
gam <UserTypeEntity> snippets <Boolean>
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
rmdir /q /s gam
|
||||
rmdir /q /s gam-64
|
||||
rmdir /q /s build
|
||||
rmdir /q /s dist
|
||||
del /q /f gam-%1-windows.zip
|
||||
del /q /f gam-%1-windows-x64.zip
|
||||
|
||||
c:\python27-32\scripts\pyinstaller -F --distpath=gam gam.spec
|
||||
xcopy LICENSE gam\
|
||||
xcopy whatsnew.txt gam\
|
||||
del gam\w9xpopen.exe
|
||||
"%ProgramFiles(x86)%\7-Zip\7z.exe" a -tzip gam-%1-windows.zip gam\ -xr!.svn
|
||||
|
||||
c:\python27\scripts\pyinstaller -F --distpath=gam-64 gam.spec
|
||||
xcopy LICENSE gam-64\
|
||||
xcopy whatsnew.txt gam-64\
|
||||
"%ProgramFiles(x86)%\7-Zip\7z.exe" a -tzip gam-%1-windows-x64.zip gam-64\ -xr!.svn
|
||||
299
src/gam.py
299
src/gam.py
@@ -24,7 +24,7 @@ For more information, see http://git.io/gam
|
||||
"""
|
||||
|
||||
__author__ = u'Jay Lee <jay0lee@gmail.com>'
|
||||
__version__ = u'3.71'
|
||||
__version__ = u'3.72'
|
||||
__license__ = u'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
import sys, os, time, datetime, random, socket, csv, platform, re, base64, string, codecs, StringIO, subprocess, collections, mimetypes
|
||||
@@ -1729,7 +1729,7 @@ def doDelCourseParticipant():
|
||||
def doDelCourse():
|
||||
croom = buildGAPIObject(u'classroom')
|
||||
courseId = sys.argv[3]
|
||||
if not courseId.isdigit():
|
||||
if not courseId.isdigit() and courseid[:2] != u'd:':
|
||||
courseId = u'd:%s' % courseId
|
||||
callGAPI(croom.courses(), u'delete', id=courseId)
|
||||
print u'Deleted Course %s' % courseId
|
||||
@@ -1737,7 +1737,7 @@ def doDelCourse():
|
||||
def doUpdateCourse():
|
||||
croom = buildGAPIObject(u'classroom')
|
||||
courseId = sys.argv[3]
|
||||
if not courseId.isdigit():
|
||||
if not courseId.isdigit() and courseid[:2] != u'd:':
|
||||
courseId = u'd:%s' % courseId
|
||||
body = {}
|
||||
i = 4
|
||||
@@ -2096,7 +2096,7 @@ def buildOrgUnitIdToNameMap():
|
||||
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][orgunitid]
|
||||
return GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME].get(orgunitid, orgunitid)
|
||||
|
||||
def buildRoleIdToNameToIdMap():
|
||||
cd = buildGAPIObject(u'directory')
|
||||
@@ -2113,7 +2113,7 @@ def buildRoleIdToNameToIdMap():
|
||||
def role_from_roleid(roleid):
|
||||
if not GM_Globals[GM_MAP_ROLE_ID_TO_NAME]:
|
||||
buildRoleIdToNameToIdMap()
|
||||
return GM_Globals[GM_MAP_ROLE_ID_TO_NAME][roleid]
|
||||
return GM_Globals[GM_MAP_ROLE_ID_TO_NAME].get(roleid, roleid)
|
||||
|
||||
def roleid_from_role(role):
|
||||
if not GM_Globals[GM_MAP_ROLE_NAME_TO_ID]:
|
||||
@@ -2155,6 +2155,7 @@ SERVICE_NAME_CHOICES_MAP = {
|
||||
u'googleplus': u'Google+',
|
||||
u'gplus': u'Google+',
|
||||
u'g+': u'Google+',
|
||||
u'drive': u'Drive',
|
||||
u'googledrive': u'Drive',
|
||||
u'gdrive': u'Drive',
|
||||
}
|
||||
@@ -2282,72 +2283,71 @@ def doGetDataTransferInfo():
|
||||
print u' None'
|
||||
print
|
||||
|
||||
def doPrintGuardians():
|
||||
def doPrintShowGuardians(csvFormat):
|
||||
croom = buildGAPIObject(u'classroom')
|
||||
invitedEmailAddress = None
|
||||
studentIds = [u'-',]
|
||||
states = None
|
||||
service = croom.userProfiles().guardians()
|
||||
items = u'guardians'
|
||||
guardians = []
|
||||
show_csv = True
|
||||
csvRows = []
|
||||
todrive = False
|
||||
titles = []
|
||||
itemName = 'Guardians'
|
||||
if csvFormat:
|
||||
csvRows = []
|
||||
todrive = False
|
||||
titles = [u'studentEmail', u'studentId', u'invitedEmailAddress', u'guardianId']
|
||||
i = 3
|
||||
while i < len(sys.argv):
|
||||
if sys.argv[i].lower() == u'invitedguardian':
|
||||
invitedEmailAddress = sys.argv[i+1]
|
||||
i += 2
|
||||
elif sys.argv[i].lower() == u'nocsv':
|
||||
show_csv = False
|
||||
i += 1
|
||||
elif sys.argv[i].lower() == u'todrive':
|
||||
myarg = sys.argv[i].lower()
|
||||
if csvFormat and myarg == u'todrive':
|
||||
todrive = True
|
||||
i += 1
|
||||
elif sys.argv[i].lower() == u'student':
|
||||
elif myarg == u'invitedguardian':
|
||||
invitedEmailAddress = sys.argv[i+1]
|
||||
i += 2
|
||||
elif myarg == u'student':
|
||||
studentIds = [sys.argv[i+1],]
|
||||
i += 2
|
||||
elif sys.argv[i].lower() == u'invitations':
|
||||
elif myarg == u'invitations':
|
||||
service = croom.userProfiles().guardianInvitations()
|
||||
items = u'guardianInvitations'
|
||||
itemName = 'Guardian Invitations'
|
||||
titles = [u'studentEmail', u'studentId', u'invitedEmailAddress', u'invitationId']
|
||||
if states == None:
|
||||
states = [u'COMPLETE', u'PENDING', u'GUARDIAN_INVITATION_STATE_UNSPECIFIED']
|
||||
i += 1
|
||||
elif sys.argv[i].lower() == u'states':
|
||||
elif myarg == u'states':
|
||||
states = sys.argv[i+1].upper().replace(u',', u' ').split()
|
||||
i += 2
|
||||
elif sys.argv[i].lower() in usergroup_types:
|
||||
studentIds = getUsersToModify(entity_type=sys.argv[i], entity=sys.argv[i+1])
|
||||
elif myarg in usergroup_types:
|
||||
studentIds = getUsersToModify(entity_type=myarg, entity=sys.argv[i+1])
|
||||
i += 2
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam print guardians"' % sys.argv[i]
|
||||
print u'ERROR: %s is not a valid argument for "gam %s guardians"' % (sys.argv[i], [u'show', u'print'][csvFormat])
|
||||
sys.exit(2)
|
||||
n = 1
|
||||
i = 0
|
||||
count = len(studentIds)
|
||||
for studentId in studentIds:
|
||||
i += 1
|
||||
kwargs = {u'invitedEmailAddress': invitedEmailAddress, u'studentId': studentId}
|
||||
if items == u'guardianInvitations':
|
||||
kwargs[u'states'] = states
|
||||
if studentId != u'-':
|
||||
sys.stderr.write('\r')
|
||||
sys.stderr.flush()
|
||||
sys.stderr.write(u'Getting guardians for %s (%s/%s)%s' % (studentId, n, len(studentIds), u' ' * 40))
|
||||
student_guardians = callGAPIpages(service, u'list', items=items, soft_errors=True, **kwargs)
|
||||
# add student email to results since API does not return it
|
||||
i = 0
|
||||
while i < len(student_guardians):
|
||||
student_guardians[i][u'studentEmail'] = studentId
|
||||
i += 1
|
||||
guardians = guardians + student_guardians
|
||||
n += 1
|
||||
sys.stderr.write(u'\n')
|
||||
if show_csv:
|
||||
for guardian in guardians:
|
||||
addRowTitlesToCSVfile(flatten_json(guardian), csvRows, titles)
|
||||
writeCSVfile(csvRows, titles, u'Guardians', todrive)
|
||||
else:
|
||||
for guardian in guardians:
|
||||
print_json(None, guardian)
|
||||
if csvFormat:
|
||||
sys.stderr.write('\r')
|
||||
sys.stderr.flush()
|
||||
sys.stderr.write(u'Getting %s for %s%s%s' % (itemName, studentId, currentCount(i, count), u' ' * 40))
|
||||
guardians = callGAPIpages(service, u'list', items=items, soft_errors=True, **kwargs)
|
||||
if not csvFormat:
|
||||
print u'Student: {0}, {1}:{2}'.format(studentId, itemName, currentCount(i, count))
|
||||
for guardian in guardians:
|
||||
print_json(None, guardian, spacing=u' ')
|
||||
else:
|
||||
for guardian in guardians:
|
||||
guardian[u'studentEmail'] = studentId
|
||||
addRowTitlesToCSVfile(flatten_json(guardian), csvRows, titles)
|
||||
if csvFormat:
|
||||
sys.stderr.write(u'\n')
|
||||
writeCSVfile(csvRows, titles, itemName, todrive)
|
||||
|
||||
def doInviteGuardian():
|
||||
croom = buildGAPIObject(u'classroom')
|
||||
@@ -2361,7 +2361,7 @@ def doDeleteGuardian():
|
||||
guardianId = sys.argv[3]
|
||||
studentId = sys.argv[4]
|
||||
try:
|
||||
callGAPI(croom.userProfiles().guardians(), u'delete', throw_reasons=[u'notFound'], studentId=studentId, guardianId=guardianId)
|
||||
callGAPI(croom.userProfiles().guardians(), u'delete', throw_reasons=[u'forbidden', u'notFound'], studentId=studentId, guardianId=guardianId)
|
||||
print u'Deleted %s as a guardian of %s' % (guardianId, studentId)
|
||||
except googleapiclient.errors.HttpError:
|
||||
# See if there's a pending invitation
|
||||
@@ -2424,7 +2424,7 @@ def doCreateCourse():
|
||||
def doGetCourseInfo():
|
||||
croom = buildGAPIObject(u'classroom')
|
||||
courseId = sys.argv[3]
|
||||
if not courseId.isdigit():
|
||||
if not courseId.isdigit() and courseId[:2] != u'd:':
|
||||
courseId = u'd:%s' % courseId
|
||||
info = callGAPI(croom.courses(), u'get', id=courseId)
|
||||
print_json(None, info)
|
||||
@@ -2529,8 +2529,8 @@ def doPrintCourseParticipants():
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam print course-participants"' % sys.argv[i]
|
||||
sys.exit(2)
|
||||
sys.stderr.write(u'Retrieving courses for organization (may take some time for large accounts)...\n')
|
||||
if len(courses) == 0:
|
||||
sys.stderr.write(u'Retrieving courses for organization (may take some time for large accounts)...\n')
|
||||
page_message = u'Got %%num_items%% courses...\n'
|
||||
all_courses = callGAPIpages(croom.courses(), u'list', u'courses', page_message=page_message, teacherId=teacherId, studentId=studentId)
|
||||
for course in all_courses:
|
||||
@@ -4979,15 +4979,46 @@ def _processTags(tagReplacements, message):
|
||||
message = re.sub(match.group(0), tagReplacements.get(match.group(1), u''), message)
|
||||
return message
|
||||
|
||||
def getSendAsAttributes(i, myarg, body, tagReplacements, command):
|
||||
if myarg == u'replace':
|
||||
matchTag = getString(i+1, u'Tag')
|
||||
matchReplacement = getString(i+2, u'String', emptyOK=True)
|
||||
tagReplacements[matchTag] = matchReplacement
|
||||
i += 3
|
||||
elif myarg == u'name':
|
||||
body[u'displayName'] = sys.argv[i+1]
|
||||
i += 2
|
||||
elif myarg == u'replyto':
|
||||
body[u'replyToAddress'] = sys.argv[i+1]
|
||||
i += 2
|
||||
elif myarg == u'default':
|
||||
body[u'isDefault'] = True
|
||||
i += 1
|
||||
elif myarg == u'treatasalias':
|
||||
if sys.argv[i+1].lower() == u'true':
|
||||
body[u'treatAsAlias'] = True
|
||||
elif sys.argv[i+1].lower() == u'false':
|
||||
body[u'treatAsAlias'] = False
|
||||
else:
|
||||
print u'ERROR: value for treatasalias must be true or false; got %s' % sys.argv[i+1]
|
||||
sys.exit(2)
|
||||
i += 2
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam <users> %s"' % (sys.argv[i], command)
|
||||
sys.exit(2)
|
||||
return i
|
||||
|
||||
def addUpdateSendAs(users, i, addCmd):
|
||||
emailAddress = sys.argv[i]
|
||||
if emailAddress.find(u'@') < 0:
|
||||
emailAddress = emailAddress+u'@'+GC_Values[GC_DOMAIN]
|
||||
i += 1
|
||||
if addCmd:
|
||||
command = [u'sendas', u'add sendas'][i == 6]
|
||||
body = {u'sendAsEmail': emailAddress, u'displayName': sys.argv[i]}
|
||||
i += 1
|
||||
else:
|
||||
command = u'update sendas'
|
||||
body = {}
|
||||
signature = None
|
||||
tagReplacements = {}
|
||||
@@ -5000,32 +5031,8 @@ def addUpdateSendAs(users, i, addCmd):
|
||||
filename = sys.argv[i]
|
||||
i, encoding = getCharSet(i+1)
|
||||
signature = readFile(filename, encoding=encoding)
|
||||
elif myarg == u'replace':
|
||||
matchTag = getString(i+1, u'Tag')
|
||||
matchReplacement = getString(i+2, u'String', emptyOK=True)
|
||||
tagReplacements[matchTag] = matchReplacement
|
||||
i += 3
|
||||
elif myarg == u'treatasalias':
|
||||
if sys.argv[i+1].lower() == u'true':
|
||||
body[u'treatAsAlias'] = True
|
||||
elif sys.argv[i+1].lower() == u'false':
|
||||
body[u'treatAsAlias'] = False
|
||||
else:
|
||||
print u'ERROR: value for treatasalias must be true or false; got %s' % sys.argv[i+1]
|
||||
sys.exit(2)
|
||||
i += 2
|
||||
elif myarg == u'default':
|
||||
body[u'isDefault'] = True
|
||||
i += 1
|
||||
elif sys.argv[i].lower() == u'replyto':
|
||||
body[u'replyToAddress'] = sys.argv[i+1]
|
||||
i += 2
|
||||
elif myarg == u'name':
|
||||
body[u'displayName'] = sys.argv[i+1]
|
||||
i += 2
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam <users> sendas"' % sys.argv[i]
|
||||
sys.exit(2)
|
||||
i = getSendAsAttributes(i, myarg, body, tagReplacements, command)
|
||||
if signature != None:
|
||||
if not signature:
|
||||
body[u'signature'] = None
|
||||
@@ -5135,6 +5142,7 @@ def infoSendAs(users):
|
||||
user, gmail = buildGmailGAPIObject(user)
|
||||
if not gmail:
|
||||
continue
|
||||
print u'User: {0}, Show SendAs Address:{1}'.format(user, currentCount(i, count))
|
||||
result = callGAPI(gmail.users().settings().sendAs(), u'get',
|
||||
soft_errors=True,
|
||||
userId=u'me', sendAsEmail=emailAddress)
|
||||
@@ -6213,20 +6221,7 @@ def doSignature(users):
|
||||
body = {u'sendAsEmail': None}
|
||||
while i < len(sys.argv):
|
||||
myarg = sys.argv[i].lower()
|
||||
if myarg == u'replace':
|
||||
matchTag = getString(i+1, u'Tag')
|
||||
matchReplacement = getString(i+2, u'String', emptyOK=True)
|
||||
tagReplacements[matchTag] = matchReplacement
|
||||
i += 3
|
||||
elif myarg == u'name':
|
||||
body[u'displayName'] = sys.argv[i+1]
|
||||
i += 2
|
||||
elif myarg == u'replyto':
|
||||
body[u'replyToAddress'] = sys.argv[i+1]
|
||||
i += 2
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam <users> signature"' % sys.argv[i]
|
||||
sys.exit(2)
|
||||
i = getSendAsAttributes(i, myarg, body, tagReplacements, u'signature')
|
||||
if tagReplacements:
|
||||
body[u'signature'] = _processTags(tagReplacements, signature)
|
||||
else:
|
||||
@@ -7373,6 +7368,9 @@ def doUpdateCros():
|
||||
devices = [deviceId,]
|
||||
i = 4
|
||||
body = {}
|
||||
update_device = True
|
||||
action_device = False
|
||||
ack_wipe = False
|
||||
while i < len(sys.argv):
|
||||
if sys.argv[i].lower() == u'user':
|
||||
body[u'annotatedUser'] = sys.argv[i + 1]
|
||||
@@ -7383,15 +7381,32 @@ def doUpdateCros():
|
||||
elif sys.argv[i].lower() == u'notes':
|
||||
body[u'notes'] = sys.argv[i + 1]
|
||||
i += 2
|
||||
elif sys.argv[i].lower() == u'status':
|
||||
body[u'status'] = sys.argv[i + 1].upper()
|
||||
#if body[u'status'] not in [u'ACTIVE', u'DEPROVISIONED']:
|
||||
# print u'ERROR: status must be active or deprovisioned; got %s' % body[u'status']
|
||||
# sys.exit(2)
|
||||
elif sys.argv[i].lower() == u'action':
|
||||
update_device = False
|
||||
action_device = True
|
||||
action = sys.argv[i+1].replace(u'_', u'').replace(u'-', u'').lower()
|
||||
deprovisionReason = None
|
||||
if action in [u'deprovisionsamemodelreplace', u'deprovisionsamemodelreplacement']:
|
||||
action = u'deprovision'
|
||||
deprovisionReason = u'same_model_replacement'
|
||||
elif action in [u'deprovisiondifferentmodelreplace', u'deprovisiondifferentmodelreplacement']:
|
||||
action = u'deprovision'
|
||||
deprovisionReason = u'differentmodelreplacement'
|
||||
elif action in [u'deprovisionretiringdevice']:
|
||||
action = u'deprovision'
|
||||
deprovisionReason = u'retiring_device'
|
||||
elif action not in [u'disable', u'reenable']:
|
||||
print u'ERROR: expected action of deprovision_same_model_replace, deprovision_different_model_replace, deprovision_retiring_device, disable or reenable, got %s' % action
|
||||
sys.exit(3)
|
||||
body = {u'action': action}
|
||||
if deprovisionReason:
|
||||
body[u'deprovisionReason'] = deprovisionReason
|
||||
i += 2
|
||||
elif sys.argv[i].replace(u'_', u'').lower() in [u'acknowledgedevicetouchrequirement']:
|
||||
ack_wipe = True
|
||||
i += 1
|
||||
elif sys.argv[i].lower() in [u'tag', u'asset', u'assetid']:
|
||||
body[u'annotatedAssetId'] = sys.argv[i + 1]
|
||||
#annotatedAssetId - Handle Asset Tag Field 2015-04-13
|
||||
i += 2
|
||||
elif sys.argv[i].lower() in [u'ou', u'org']:
|
||||
body[u'orgUnitPath'] = sys.argv[i + 1]
|
||||
@@ -7401,12 +7416,19 @@ def doUpdateCros():
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam update cros"' % sys.argv[i]
|
||||
sys.exit(2)
|
||||
i = 0
|
||||
i = 1
|
||||
device_count = len(devices)
|
||||
for this_device in devices:
|
||||
if update_device:
|
||||
print u' updating %s (%s of %s)' % (this_device, i, device_count)
|
||||
callGAPI(service=cd.chromeosdevices(), function=u'patch', deviceId=this_device, body=body, customerId=GC_Values[GC_CUSTOMER_ID])
|
||||
elif action_device:
|
||||
if body[u'action'] == u'deprovision' and not ack_wipe:
|
||||
print u'WARNING: Refusing to deprovision %s because acknowledge_device_touch_requirement not specified. Deprovisioning a device means the device will have to be physically wiped and re-enrolled to be managed by your domain again. This requires physical access to the device and is very time consuming to perform for each device. Please add "acknowledge_device_touch_requirement" to the GAM command if you understand this and wish to proceed with the deprovision. Please also be aware that deprovisioning can have an effect on your device license count. See https://support.google.com/chrome/a/answer/3523633 for full details.' % (this_device)
|
||||
sys.exit(3)
|
||||
print u' performing action %s for %s (%s of %s)' % (action, this_device, i, device_count)
|
||||
callGAPI(cd.chromeosdevices(), function=u'action', customerId=GC_Values[GC_CUSTOMER_ID], resourceId=this_device, body=body)
|
||||
i += 1
|
||||
print u' updating %s (%s/%s)' % (this_device, i, device_count)
|
||||
callGAPI(cd.chromeosdevices(), u'patch', deviceId=this_device, body=body, customerId=GC_Values[GC_CUSTOMER_ID])
|
||||
|
||||
def doUpdateMobile():
|
||||
cd = buildGAPIObject(u'directory')
|
||||
@@ -8727,7 +8749,7 @@ def writeCSVfile(csvRows, titles, list_type, todrive):
|
||||
else:
|
||||
writer = csv.DictWriter(sys.stdout, fieldnames=titles, dialect=u'nixstdout', quoting=csv.QUOTE_MINIMAL)
|
||||
try:
|
||||
writer.writeheader()
|
||||
writer.writerow(dict((item, item) for item in writer.fieldnames))
|
||||
writer.writerows(csvRows)
|
||||
except IOError as e:
|
||||
systemErrorExit(6, e)
|
||||
@@ -8984,9 +9006,11 @@ GROUP_ATTRIBUTES_ARGUMENT_TO_PROPERTY_MAP = {
|
||||
u'allowgooglecommunication': u'allowGoogleCommunication',
|
||||
u'allowwebposting': u'allowWebPosting',
|
||||
u'archiveonly': u'archiveOnly',
|
||||
u'customfootertext': u'customFooterText',
|
||||
u'customreplyto': u'customReplyTo',
|
||||
u'defaultmessagedenynotificationtext': u'defaultMessageDenyNotificationText',
|
||||
u'gal': u'includeInGlobalAddressList',
|
||||
u'includecustomfooter': u'includeCustomFooter',
|
||||
u'includeinglobaladdresslist': u'includeInGlobalAddressList',
|
||||
u'isarchived': u'isArchived',
|
||||
u'maxmessagebytes': u'maxMessageBytes',
|
||||
@@ -9265,17 +9289,17 @@ def doPrintAliases():
|
||||
continue
|
||||
writeCSVfile(csvRows, titles, u'Aliases', todrive)
|
||||
|
||||
MEMBERS_FIELD_NAMES = [u'group', u'id', u'email', u'role', u'type', u'name',]
|
||||
|
||||
def doPrintGroupMembers():
|
||||
cd = buildGAPIObject(u'directory')
|
||||
todrive = groupname = membernames = False
|
||||
todrive = False
|
||||
membernames = False
|
||||
customer = GC_Values[GC_CUSTOMER_ID]
|
||||
usedomain = usemember = None
|
||||
fieldsList = []
|
||||
titles = []
|
||||
usedomain = None
|
||||
usemember = None
|
||||
fields = None
|
||||
titles = [u'group']
|
||||
csvRows = []
|
||||
all_groups = []
|
||||
groups_to_get = []
|
||||
i = 3
|
||||
while i < len(sys.argv):
|
||||
if sys.argv[i].lower() == u'domain':
|
||||
@@ -9290,57 +9314,42 @@ def doPrintGroupMembers():
|
||||
customer = None
|
||||
i += 2
|
||||
elif sys.argv[i].lower() == u'fields':
|
||||
fieldNameList = sys.argv[i+1].lower()
|
||||
for field in fieldNameList.lower().replace(u',', u' ').split():
|
||||
if field in MEMBERS_FIELD_NAMES:
|
||||
fieldsList.append(field)
|
||||
titles.append(field)
|
||||
else:
|
||||
print u'ERROR: field name must be one of %s; got %s' % (u', '.join(MEMBERS_FIELD_NAMES), field)
|
||||
sys.exit(2)
|
||||
memberFieldsList = sys.argv[i+1].replace(u',', u' ').lower().split()
|
||||
fields = u'nextPageToken,members(%s)' % (','.join(memberFieldsList))
|
||||
i += 2
|
||||
elif sys.argv[i].lower() == u'membernames':
|
||||
membernames = True
|
||||
titles.append(u'name')
|
||||
i += 1
|
||||
elif sys.argv[i].lower() == u'group':
|
||||
group_email = sys.argv[i+1].lower()
|
||||
if group_email.find(u'@') == -1:
|
||||
group_email = u'%s@%s' % (group_email, GC_Values[GC_DOMAIN])
|
||||
all_groups = [{u'email': group_email}]
|
||||
groups_to_get = [{u'email': group_email}]
|
||||
i += 2
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam print group-members"' % sys.argv[i]
|
||||
sys.exit(2)
|
||||
if not fieldsList:
|
||||
for field in [u'id', u'role', u'group', u'email', u'type']:
|
||||
fieldsList.append(field)
|
||||
titles.append(field)
|
||||
if membernames:
|
||||
titles.append(u'name')
|
||||
else:
|
||||
if u'name'in fieldsList:
|
||||
membernames = True
|
||||
fieldsList.remove(u'name')
|
||||
if u'group' in fieldsList:
|
||||
groupname = True
|
||||
fieldsList.remove(u'group')
|
||||
if not all_groups:
|
||||
all_groups = callGAPIpages(cd.groups(), u'list', u'groups', message_attribute=u'email',
|
||||
customer=customer, domain=usedomain, userKey=usemember, fields=u'nextPageToken,groups(email)')
|
||||
if not groups_to_get:
|
||||
groups_to_get = callGAPIpages(cd.groups(), u'list', u'groups', message_attribute=u'email',
|
||||
customer=customer, domain=usedomain, userKey=usemember, fields=u'nextPageToken,groups(email)')
|
||||
i = 0
|
||||
count = len(all_groups)
|
||||
for group in all_groups:
|
||||
count = len(groups_to_get)
|
||||
for group in groups_to_get:
|
||||
i += 1
|
||||
group_email = group[u'email']
|
||||
sys.stderr.write(u'Getting members for %s (%s/%s)\n' % (group_email, i, count))
|
||||
group_members = callGAPIpages(cd.members(), u'list', u'members', message_attribute=u'email', groupKey=group_email)
|
||||
group_members = callGAPIpages(cd.members(), u'list', u'members',
|
||||
message_attribute=u'email', groupKey=group_email, fields=fields)
|
||||
for member in group_members:
|
||||
member_attr = {}
|
||||
if groupname:
|
||||
member_attr[u'group'] = group_email
|
||||
for title in fieldsList:
|
||||
member_attr[title] = member[title]
|
||||
if membernames:
|
||||
for unwanted_item in [u'kind', u'etag']:
|
||||
if unwanted_item in member:
|
||||
del member[unwanted_item]
|
||||
for title in member:
|
||||
if title not in titles:
|
||||
titles.append(title)
|
||||
member[u'group'] = group_email
|
||||
if membernames and u'type' in member and u'id' in member:
|
||||
if member[u'type'] == u'USER':
|
||||
try:
|
||||
mbinfo = callGAPI(cd.users(), u'get',
|
||||
@@ -9359,8 +9368,8 @@ def doPrintGroupMembers():
|
||||
memberName = u'Unknown'
|
||||
else:
|
||||
memberName = u'Unknown'
|
||||
member_attr[u'name'] = memberName
|
||||
csvRows.append(member_attr)
|
||||
member[u'name'] = memberName
|
||||
csvRows.append(member)
|
||||
writeCSVfile(csvRows, titles, u'Group Members', todrive)
|
||||
|
||||
def doPrintMobileDevices():
|
||||
@@ -10534,9 +10543,13 @@ def ProcessGAMCommand(args):
|
||||
command = sys.argv[1].lower()
|
||||
if command == u'batch':
|
||||
import shlex
|
||||
f = openFile(sys.argv[2])
|
||||
i = 2
|
||||
filename = sys.argv[i]
|
||||
i, encoding = getCharSet(i+1)
|
||||
f = openFile(filename)
|
||||
batchFile = UTF8Recoder(f, encoding) if encoding != u'utf-8' else f
|
||||
items = []
|
||||
for line in f:
|
||||
for line in batchFile:
|
||||
argv = shlex.split(line)
|
||||
if not argv:
|
||||
continue
|
||||
@@ -10817,7 +10830,7 @@ def ProcessGAMCommand(args):
|
||||
elif argument in [u'roles', u'adminroles']:
|
||||
doPrintAdminRoles()
|
||||
elif argument in [u'guardian', u'guardians']:
|
||||
doPrintGuardians()
|
||||
doPrintShowGuardians(True)
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam print"' % argument
|
||||
sys.exit(2)
|
||||
@@ -10826,6 +10839,8 @@ def ProcessGAMCommand(args):
|
||||
argument = sys.argv[2].lower()
|
||||
if argument in [u'schema', u'schemas']:
|
||||
doPrintShowUserSchemas(False)
|
||||
elif argument in [u'guardian', u'guardians']:
|
||||
doPrintShowGuardians(False)
|
||||
else:
|
||||
print u'ERROR: %s is not a valid argument for "gam show"' % argument
|
||||
sys.exit(2)
|
||||
|
||||
64
src/gam.wxs
Normal file
64
src/gam.wxs
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" >
|
||||
<Product
|
||||
Id="*"
|
||||
Name="GAM"
|
||||
Language="1033"
|
||||
Version="$(env.GAMVERSION)"
|
||||
Manufacturer="Jay Lee - jay0lee@gmail.com"
|
||||
UpgradeCode="15C5FD61-B04C-4E04-A26D-CD8424C19D9F">
|
||||
<Package
|
||||
InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
|
||||
|
||||
<MajorUpgrade
|
||||
DowngradeErrorMessage=
|
||||
"A newer version of [ProductName] is already installed."
|
||||
Schedule="afterInstallExecute" />
|
||||
<MediaTemplate EmbedCab="yes" />
|
||||
|
||||
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
|
||||
<WixVariable Id="WixUILicenseRtf" Value="LICENSE.rtf" />
|
||||
<UIRef Id="WixUI_InstallDir" />
|
||||
|
||||
<Feature
|
||||
Id="gam"
|
||||
Title="GAM"
|
||||
Level="1">
|
||||
<ComponentGroupRef Id="ProductComponents" />
|
||||
</Feature>
|
||||
</Product>
|
||||
|
||||
<Fragment>
|
||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||
<Directory Id="ROOTDRIVE">
|
||||
<Directory Id="INSTALLFOLDER" Name="GAM" />
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<!-- Group of components that are our main application items -->
|
||||
<ComponentGroup
|
||||
Id="ProductComponents"
|
||||
Directory="INSTALLFOLDER"
|
||||
Source="gam-64">
|
||||
<Component Id="gam_exe" Guid="886abc07-73c5-4acc-9f71-58daf62aabc1">
|
||||
<File Name="gam.exe" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="license" Guid="7a15de2e-fb91-4d0a-b8bf-c8b19c68f569">
|
||||
<File Name="LICENSE" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="whatsnew_txt" Guid="6aa9863c-90d9-412f-9b73-fda82549a950">
|
||||
<File Name="whatsnew.txt" KeyPath="yes" />
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<InstallUISequence>
|
||||
<ExecuteAction />
|
||||
<Show Dialog="WelcomeDlg" Before="ProgressDlg" />
|
||||
<!-- <Show Dialog="ProgressDlg" After="" /> -->
|
||||
</InstallUISequence>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
BIN
src/license.rtf
Normal file
BIN
src/license.rtf
Normal file
Binary file not shown.
10
src/linux-build.sh
Executable file
10
src/linux-build.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
rm -rf gam
|
||||
rm -rf build
|
||||
rm -rf dist
|
||||
rm -rf gam-$1-linux-$(arch).tar.xz
|
||||
|
||||
pyinstaller --clean -F --distpath=gam linux-gam.spec
|
||||
cp LICENSE gam
|
||||
cp whatsnew.txt gam
|
||||
|
||||
tar cfJ gam-$1-linux-$(arch).tar.xz gam/
|
||||
26
src/linux-gam.spec
Normal file
26
src/linux-gam.spec
Normal file
@@ -0,0 +1,26 @@
|
||||
# -*- mode: python -*-
|
||||
a = Analysis(['gam.py'],
|
||||
hiddenimports=[],
|
||||
hookspath=None,
|
||||
excludes=['_tkinter'],
|
||||
runtime_hooks=None)
|
||||
for d in a.datas:
|
||||
if 'pyconfig' in d[0]:
|
||||
a.datas.remove(d)
|
||||
break
|
||||
a.datas += [('httplib2/cacerts.txt', 'httplib2\cacerts.txt', 'DATA')]
|
||||
a.datas += [('admin-settings-v2.json', 'admin-settings-v2.json', 'DATA')]
|
||||
a.datas += [('cloudprint-v2.json', 'cloudprint-v2.json', 'DATA')]
|
||||
a.datas += [('email-audit-v1.json', 'email-audit-v1.json', 'DATA')]
|
||||
a.datas += [('email-settings-v2.json', 'email-settings-v2.json', 'DATA')]
|
||||
pyz = PYZ(a.pure)
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
name='gam',
|
||||
debug=False,
|
||||
strip=None,
|
||||
upx=True,
|
||||
console=True )
|
||||
10
src/macos-build.sh
Executable file
10
src/macos-build.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
rmdir /q /s gam
|
||||
rmdir /q /s build
|
||||
rmdir /q /s dist
|
||||
rm -rf gam-$1-macos.tar.xz
|
||||
|
||||
pyinstaller --clean -F --distpath=gam macos-gam.spec
|
||||
cp LICENSE gam
|
||||
cp whatsnew.txt gam
|
||||
|
||||
tar cfJ gam-$1-macos.tar.xz gam/
|
||||
26
src/macos-gam.spec
Normal file
26
src/macos-gam.spec
Normal file
@@ -0,0 +1,26 @@
|
||||
# -*- mode: python -*-
|
||||
a = Analysis(['gam.py'],
|
||||
hiddenimports=[],
|
||||
hookspath=None,
|
||||
excludes=['_tkinter'],
|
||||
runtime_hooks=None)
|
||||
for d in a.datas:
|
||||
if 'pyconfig' in d[0]:
|
||||
a.datas.remove(d)
|
||||
break
|
||||
a.datas += [('httplib2/cacerts.txt', 'httplib2\cacerts.txt', 'DATA')]
|
||||
a.datas += [('admin-settings-v2.json', 'admin-settings-v2.json', 'DATA')]
|
||||
a.datas += [('cloudprint-v2.json', 'cloudprint-v2.json', 'DATA')]
|
||||
a.datas += [('email-audit-v1.json', 'email-audit-v1.json', 'DATA')]
|
||||
a.datas += [('email-settings-v2.json', 'email-settings-v2.json', 'DATA')]
|
||||
pyz = PYZ(a.pure)
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
name='gam',
|
||||
debug=False,
|
||||
strip=None,
|
||||
upx=True,
|
||||
console=True )
|
||||
@@ -1,3 +1,9 @@
|
||||
GAM 3.72
|
||||
- Chrome OS device actions, disable, re-enable and deprovision devices.
|
||||
- (beta) MSI Windows build
|
||||
- (beta) binary Linux and MacOS builds
|
||||
- Numerous fixes and updates by Ross
|
||||
|
||||
GAM 3.71
|
||||
- Fix update first / last name.
|
||||
- upgrade GAM versions of oauth2client, googleapiclient, RSA and six
|
||||
|
||||
24
src/windows-build.bat
Normal file
24
src/windows-build.bat
Normal file
@@ -0,0 +1,24 @@
|
||||
rmdir /q /s gam
|
||||
rmdir /q /s gam-64
|
||||
rmdir /q /s build
|
||||
rmdir /q /s dist
|
||||
del /q /f gam-%1-windows.zip
|
||||
del /q /f gam-%1-windows-x64.zip
|
||||
del /q /f gam-%1-windows-x64.msi
|
||||
del /q /f gam.wixobj
|
||||
del /q /f gam.wixpdb
|
||||
|
||||
c:\python27-32\scripts\pyinstaller --clean -F --distpath=gam windows-gam.spec
|
||||
xcopy LICENSE gam\
|
||||
xcopy whatsnew.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\
|
||||
"%ProgramFiles%\7-Zip\7z.exe" a -tzip gam-%1-windows-x64.zip gam-64\ -xr!.svn
|
||||
|
||||
set GAMVERSION=%1
|
||||
"%ProgramFiles(x86)%\WiX Toolset v3.10\bin\candle.exe" -arch x64 gam.wxs
|
||||
"%ProgramFiles(x86)%\WiX Toolset v3.10\bin\light.exe" -ext "%ProgramFiles(x86)%\WiX Toolset v3.10\bin\WixUIExtension.dll" gam.wixobj -o gam-%1-windows-x64.msi
|
||||
Reference in New Issue
Block a user