gam7 7.20.1__tar.gz → 7.20.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. {gam7-7.20.1 → gam7-7.20.3}/.github/workflows/build.yml +3 -3
  2. {gam7-7.20.1 → gam7-7.20.3}/PKG-INFO +1 -1
  3. {gam7-7.20.1 → gam7-7.20.3}/src/GamCommands.txt +14 -12
  4. {gam7-7.20.1 → gam7-7.20.3}/src/GamUpdate.txt +12 -0
  5. {gam7-7.20.1 → gam7-7.20.3}/src/gam/__init__.py +133 -91
  6. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glclargs.py +1 -0
  7. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glmsgs.py +1 -0
  8. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glskus.py +1 -1
  9. {gam7-7.20.1 → gam7-7.20.3}/wiki/Classroom-StudentGroups.md +58 -1
  10. {gam7-7.20.1 → gam7-7.20.3}/wiki/Collections-of-Items.md +2 -0
  11. {gam7-7.20.1 → gam7-7.20.3}/wiki/GamUpdates.md +19 -0
  12. {gam7-7.20.1 → gam7-7.20.3}/wiki/How-to-Upgrade-Legacy-GAM-to-GAM7.md +2 -2
  13. {gam7-7.20.1 → gam7-7.20.3}/wiki/Licenses.md +6 -6
  14. {gam7-7.20.1 → gam7-7.20.3}/wiki/Shared-Drives.md +44 -18
  15. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Chat.md +22 -5
  16. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Permissions.md +20 -0
  17. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Shared-Drives.md +43 -18
  18. {gam7-7.20.1 → gam7-7.20.3}/wiki/Version-and-Help.md +6 -6
  19. {gam7-7.20.1 → gam7-7.20.3}/.github/ISSUE_TEMPLATE/aa-question.md +0 -0
  20. {gam7-7.20.1 → gam7-7.20.3}/.github/ISSUE_TEMPLATE/za-bug-report.md +0 -0
  21. {gam7-7.20.1 → gam7-7.20.3}/.github/ISSUE_TEMPLATE/zz-feature-request.md +0 -0
  22. {gam7-7.20.1 → gam7-7.20.3}/.github/ISSUE_TEMPLATE.txt +0 -0
  23. {gam7-7.20.1 → gam7-7.20.3}/.github/actions/decrypt.sh +0 -0
  24. {gam7-7.20.1 → gam7-7.20.3}/.github/actions/entitlements.plist +0 -0
  25. {gam7-7.20.1 → gam7-7.20.3}/.github/actions/package_exclusions.txt +0 -0
  26. {gam7-7.20.1 → gam7-7.20.3}/.github/stale.yml +0 -0
  27. {gam7-7.20.1 → gam7-7.20.3}/.github/workflows/codeql-analysis.yml +0 -0
  28. {gam7-7.20.1 → gam7-7.20.3}/.github/workflows/get-cacerts.yml +0 -0
  29. {gam7-7.20.1 → gam7-7.20.3}/.github/workflows/pushwiki.yml +0 -0
  30. {gam7-7.20.1 → gam7-7.20.3}/.github/workflows/pypi.yml +0 -0
  31. {gam7-7.20.1 → gam7-7.20.3}/.pre-commit-config.yaml +0 -0
  32. {gam7-7.20.1 → gam7-7.20.3}/LICENSE +0 -0
  33. {gam7-7.20.1 → gam7-7.20.3}/README.md +0 -0
  34. {gam7-7.20.1 → gam7-7.20.3}/pyproject.toml +0 -0
  35. {gam7-7.20.1 → gam7-7.20.3}/src/.gitignore +0 -0
  36. {gam7-7.20.1 → gam7-7.20.3}/src/LICENSE +0 -0
  37. {gam7-7.20.1 → gam7-7.20.3}/src/README.md +0 -0
  38. {gam7-7.20.1 → gam7-7.20.3}/src/cacerts.pem +0 -0
  39. {gam7-7.20.1 → gam7-7.20.3}/src/callgam.py +0 -0
  40. {gam7-7.20.1 → gam7-7.20.3}/src/gam/__main__.py +0 -0
  41. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/__init__.py +0 -0
  42. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/auth.py +0 -0
  43. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/client.py +0 -0
  44. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/core.py +0 -0
  45. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/data.py +0 -0
  46. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/http.py +0 -0
  47. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/http_core.py +0 -0
  48. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/http_interface.py +0 -0
  49. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/mock_http.py +0 -0
  50. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/mock_http_core.py +0 -0
  51. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/mock_service.py +0 -0
  52. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/service.py +0 -0
  53. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/token_store.py +0 -0
  54. {gam7-7.20.1 → gam7-7.20.3}/src/gam/atom/url.py +0 -0
  55. {gam7-7.20.1 → gam7-7.20.3}/src/gam/cacerts.pem +0 -0
  56. {gam7-7.20.1 → gam7-7.20.3}/src/gam/cbcm-v1.1beta1.json +0 -0
  57. {gam7-7.20.1 → gam7-7.20.3}/src/gam/contactdelegation-v1.json +0 -0
  58. {gam7-7.20.1 → gam7-7.20.3}/src/gam/datastudio-v1.json +0 -0
  59. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/__init__.py +0 -0
  60. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glaction.py +0 -0
  61. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glapi.py +0 -0
  62. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glcfg.py +0 -0
  63. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glentity.py +0 -0
  64. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glgapi.py +0 -0
  65. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glgdata.py +0 -0
  66. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glglobals.py +0 -0
  67. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glindent.py +0 -0
  68. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/gluprop.py +0 -0
  69. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/glverlibs.py +0 -0
  70. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gamlib/yubikey.py +0 -0
  71. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/__init__.py +0 -0
  72. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/alt/__init__.py +0 -0
  73. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/alt/app_engine.py +0 -0
  74. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/alt/appengine.py +0 -0
  75. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/apps/__init__.py +0 -0
  76. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/apps/audit/__init__.py +0 -0
  77. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/apps/audit/service.py +0 -0
  78. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/apps/contacts/__init__.py +0 -0
  79. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/apps/contacts/service.py +0 -0
  80. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/apps/service.py +0 -0
  81. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/service.py +0 -0
  82. {gam7-7.20.1 → gam7-7.20.3}/src/gam/gdata/urlfetch.py +0 -0
  83. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/__init__.py +0 -0
  84. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/_auth.py +0 -0
  85. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/_helpers.py +0 -0
  86. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/channel.py +0 -0
  87. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/discovery.py +0 -0
  88. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/discovery_cache/__init__.py +0 -0
  89. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/discovery_cache/appengine_memcache.py +0 -0
  90. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/discovery_cache/base.py +0 -0
  91. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/discovery_cache/file_cache.py +0 -0
  92. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/errors.py +0 -0
  93. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/http.py +0 -0
  94. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/mimeparse.py +0 -0
  95. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/model.py +0 -0
  96. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/schema.py +0 -0
  97. {gam7-7.20.1 → gam7-7.20.3}/src/gam/googleapiclient/version.py +0 -0
  98. {gam7-7.20.1 → gam7-7.20.3}/src/gam/iso8601/__init__.py +0 -0
  99. {gam7-7.20.1 → gam7-7.20.3}/src/gam/iso8601/iso8601.py +0 -0
  100. {gam7-7.20.1 → gam7-7.20.3}/src/gam/meet-v2beta.json +0 -0
  101. {gam7-7.20.1 → gam7-7.20.3}/src/gam/serviceaccountlookup-v1.json +0 -0
  102. {gam7-7.20.1 → gam7-7.20.3}/src/gam/six.py +0 -0
  103. {gam7-7.20.1 → gam7-7.20.3}/src/gam-install.sh +0 -0
  104. {gam7-7.20.1 → gam7-7.20.3}/src/gam-setup.bat +0 -0
  105. {gam7-7.20.1 → gam7-7.20.3}/src/gam.exe.manifest +0 -0
  106. {gam7-7.20.1 → gam7-7.20.3}/src/gam.py +0 -0
  107. {gam7-7.20.1 → gam7-7.20.3}/src/gam.spec +0 -0
  108. {gam7-7.20.1 → gam7-7.20.3}/src/gam.wxs +0 -0
  109. {gam7-7.20.1 → gam7-7.20.3}/src/license.rtf +0 -0
  110. {gam7-7.20.1 → gam7-7.20.3}/src/requirements-dev.txt +0 -0
  111. {gam7-7.20.1 → gam7-7.20.3}/src/tools/a_atleast_b.py +0 -0
  112. {gam7-7.20.1 → gam7-7.20.3}/src/tools/gen-wix-xml-filelist.py +0 -0
  113. {gam7-7.20.1 → gam7-7.20.3}/src/tools/mkGamRef.py +0 -0
  114. {gam7-7.20.1 → gam7-7.20.3}/src/tools/openssl.props +0 -0
  115. {gam7-7.20.1 → gam7-7.20.3}/src/tools/ssd.mjs +0 -0
  116. {gam7-7.20.1 → gam7-7.20.3}/src/version_info.txt.in +0 -0
  117. {gam7-7.20.1 → gam7-7.20.3}/wiki/00scratch.md +0 -0
  118. {gam7-7.20.1 → gam7-7.20.3}/wiki/Addresses.md +0 -0
  119. {gam7-7.20.1 → gam7-7.20.3}/wiki/Administrators.md +0 -0
  120. {gam7-7.20.1 → gam7-7.20.3}/wiki/Alert-Center.md +0 -0
  121. {gam7-7.20.1 → gam7-7.20.3}/wiki/Aliases.md +0 -0
  122. {gam7-7.20.1 → gam7-7.20.3}/wiki/Authorization.md +0 -0
  123. {gam7-7.20.1 → gam7-7.20.3}/wiki/BNF-Syntax.md +0 -0
  124. {gam7-7.20.1 → gam7-7.20.3}/wiki/Basic-Items.md +0 -0
  125. {gam7-7.20.1 → gam7-7.20.3}/wiki/Bulk-Processing.md +0 -0
  126. {gam7-7.20.1 → gam7-7.20.3}/wiki/Business-Account-Management.md +0 -0
  127. {gam7-7.20.1 → gam7-7.20.3}/wiki/CSV-Input-Filtering.md +0 -0
  128. {gam7-7.20.1 → gam7-7.20.3}/wiki/CSV-Output-Filtering.md +0 -0
  129. {gam7-7.20.1 → gam7-7.20.3}/wiki/CSV-Special-Characters.md +0 -0
  130. {gam7-7.20.1 → gam7-7.20.3}/wiki/Calendars-Access.md +0 -0
  131. {gam7-7.20.1 → gam7-7.20.3}/wiki/Calendars-Events.md +0 -0
  132. {gam7-7.20.1 → gam7-7.20.3}/wiki/Calendars.md +0 -0
  133. {gam7-7.20.1 → gam7-7.20.3}/wiki/Chat-Bot-Setup-Use.md +0 -0
  134. {gam7-7.20.1 → gam7-7.20.3}/wiki/Chrome-AUE-Counts.md +0 -0
  135. {gam7-7.20.1 → gam7-7.20.3}/wiki/Chrome-Browser-Cloud-Management.md +0 -0
  136. {gam7-7.20.1 → gam7-7.20.3}/wiki/Chrome-Installed-Apps.md +0 -0
  137. {gam7-7.20.1 → gam7-7.20.3}/wiki/Chrome-Needs-Attention-Counts.md +0 -0
  138. {gam7-7.20.1 → gam7-7.20.3}/wiki/Chrome-Policies.md +0 -0
  139. {gam7-7.20.1 → gam7-7.20.3}/wiki/Chrome-Printers.md +0 -0
  140. {gam7-7.20.1 → gam7-7.20.3}/wiki/Chrome-Profile-Management.md +0 -0
  141. {gam7-7.20.1 → gam7-7.20.3}/wiki/Chrome-Version-Counts.md +0 -0
  142. {gam7-7.20.1 → gam7-7.20.3}/wiki/Chrome-Version-History.md +0 -0
  143. {gam7-7.20.1 → gam7-7.20.3}/wiki/ChromeOS-Devices.md +0 -0
  144. {gam7-7.20.1 → gam7-7.20.3}/wiki/Classroom-Courses.md +0 -0
  145. {gam7-7.20.1 → gam7-7.20.3}/wiki/Classroom-Guardians.md +0 -0
  146. {gam7-7.20.1 → gam7-7.20.3}/wiki/Classroom-Invitations.md +0 -0
  147. {gam7-7.20.1 → gam7-7.20.3}/wiki/Classroom-Membership.md +0 -0
  148. {gam7-7.20.1 → gam7-7.20.3}/wiki/Cloud-Channel.md +0 -0
  149. {gam7-7.20.1 → gam7-7.20.3}/wiki/Cloud-Identity-Devices.md +0 -0
  150. {gam7-7.20.1 → gam7-7.20.3}/wiki/Cloud-Identity-Groups-Membership.md +0 -0
  151. {gam7-7.20.1 → gam7-7.20.3}/wiki/Cloud-Identity-Groups.md +0 -0
  152. {gam7-7.20.1 → gam7-7.20.3}/wiki/Cloud-Identity-Policies.md +0 -0
  153. {gam7-7.20.1 → gam7-7.20.3}/wiki/Cloud-Storage.md +0 -0
  154. {gam7-7.20.1 → gam7-7.20.3}/wiki/Collections-of-ChromeOS-Devices.md +0 -0
  155. {gam7-7.20.1 → gam7-7.20.3}/wiki/Collections-of-Users.md +0 -0
  156. {gam7-7.20.1 → gam7-7.20.3}/wiki/Command-Data-From-Google-Docs-Sheets-Storage.md +0 -0
  157. {gam7-7.20.1 → gam7-7.20.3}/wiki/Command-Line-Parsing.md +0 -0
  158. {gam7-7.20.1 → gam7-7.20.3}/wiki/Command-Logging-Progress.md +0 -0
  159. {gam7-7.20.1 → gam7-7.20.3}/wiki/Context-Aware-Access-Levels.md +0 -0
  160. {gam7-7.20.1 → gam7-7.20.3}/wiki/Customer.md +0 -0
  161. {gam7-7.20.1 → gam7-7.20.3}/wiki/Domain-People-Contacts-Profiles.md +0 -0
  162. {gam7-7.20.1 → gam7-7.20.3}/wiki/Domain-SharedContacts.md +0 -0
  163. {gam7-7.20.1 → gam7-7.20.3}/wiki/Domains-Verification.md +0 -0
  164. {gam7-7.20.1 → gam7-7.20.3}/wiki/Domains.md +0 -0
  165. {gam7-7.20.1 → gam7-7.20.3}/wiki/Downloads-Installs.md +0 -0
  166. {gam7-7.20.1 → gam7-7.20.3}/wiki/Drive-File-Selection.md +0 -0
  167. {gam7-7.20.1 → gam7-7.20.3}/wiki/Drive-Items.md +0 -0
  168. {gam7-7.20.1 → gam7-7.20.3}/wiki/Drive-REST-API-v3.md +0 -0
  169. {gam7-7.20.1 → gam7-7.20.3}/wiki/Email-Audit-Monitor.md +0 -0
  170. {gam7-7.20.1 → gam7-7.20.3}/wiki/Find-File-Owner.md +0 -0
  171. {gam7-7.20.1 → gam7-7.20.3}/wiki/GAM-Public-Chat-Room.md +0 -0
  172. {gam7-7.20.1 → gam7-7.20.3}/wiki/GAM-Return-Codes.md +0 -0
  173. {gam7-7.20.1 → gam7-7.20.3}/wiki/GAM-with-minimal-GCP-rights.md +0 -0
  174. {gam7-7.20.1 → gam7-7.20.3}/wiki/GAM7-on-Android-Devices.md +0 -0
  175. {gam7-7.20.1 → gam7-7.20.3}/wiki/GAM7-on-Chrome-OS-Devices.md +0 -0
  176. {gam7-7.20.1 → gam7-7.20.3}/wiki/Global-Address-List.md +0 -0
  177. {gam7-7.20.1 → gam7-7.20.3}/wiki/Google-Data-Transfers.md +0 -0
  178. {gam7-7.20.1 → gam7-7.20.3}/wiki/Google-Network-Addresses.md +0 -0
  179. {gam7-7.20.1 → gam7-7.20.3}/wiki/Groups-Membership.md +0 -0
  180. {gam7-7.20.1 → gam7-7.20.3}/wiki/Groups.md +0 -0
  181. {gam7-7.20.1 → gam7-7.20.3}/wiki/HTTPS-Proxy.md +0 -0
  182. {gam7-7.20.1 → gam7-7.20.3}/wiki/Home.md +0 -0
  183. {gam7-7.20.1 → gam7-7.20.3}/wiki/How-to-Install-GAM7.md +0 -0
  184. {gam7-7.20.1 → gam7-7.20.3}/wiki/How-to-Uninstall-GAM7.md +0 -0
  185. {gam7-7.20.1 → gam7-7.20.3}/wiki/How-to-Update-GAM7.md +0 -0
  186. {gam7-7.20.1 → gam7-7.20.3}/wiki/How-to-Upgrade-GAMADV-XTD3-to-GAM7.md +0 -0
  187. {gam7-7.20.1 → gam7-7.20.3}/wiki/Inbound-SSO.md +0 -0
  188. {gam7-7.20.1 → gam7-7.20.3}/wiki/Install-GAM-as-Python-Library.md +0 -0
  189. {gam7-7.20.1 → gam7-7.20.3}/wiki/List-Items.md +0 -0
  190. {gam7-7.20.1 → gam7-7.20.3}/wiki/List.md +0 -0
  191. {gam7-7.20.1 → gam7-7.20.3}/wiki/Meta-Commands-and-File-Redirection.md +0 -0
  192. {gam7-7.20.1 → gam7-7.20.3}/wiki/Mobile-Devices.md +0 -0
  193. {gam7-7.20.1 → gam7-7.20.3}/wiki/Organizational-Units.md +0 -0
  194. {gam7-7.20.1 → gam7-7.20.3}/wiki/Other-Resources.md +0 -0
  195. {gam7-7.20.1 → gam7-7.20.3}/wiki/Permission-Matches.md +0 -0
  196. {gam7-7.20.1 → gam7-7.20.3}/wiki/Python-Regular-Expressions.md +0 -0
  197. {gam7-7.20.1 → gam7-7.20.3}/wiki/README.md +0 -0
  198. {gam7-7.20.1 → gam7-7.20.3}/wiki/Rclone.md +0 -0
  199. {gam7-7.20.1 → gam7-7.20.3}/wiki/Reports.md +0 -0
  200. {gam7-7.20.1 → gam7-7.20.3}/wiki/Reseller.md +0 -0
  201. {gam7-7.20.1 → gam7-7.20.3}/wiki/Resources.md +0 -0
  202. {gam7-7.20.1 → gam7-7.20.3}/wiki/Running-GAM7-securely-on-a-Google-Compute-Engine.md +0 -0
  203. {gam7-7.20.1 → gam7-7.20.3}/wiki/SSL-Root-CA-Certificates.md +0 -0
  204. {gam7-7.20.1 → gam7-7.20.3}/wiki/Schemas.md +0 -0
  205. {gam7-7.20.1 → gam7-7.20.3}/wiki/Scripts.md +0 -0
  206. {gam7-7.20.1 → gam7-7.20.3}/wiki/Send-Email.md +0 -0
  207. {gam7-7.20.1 → gam7-7.20.3}/wiki/Sites.md +0 -0
  208. {gam7-7.20.1 → gam7-7.20.3}/wiki/Tag-Replace.md +0 -0
  209. {gam7-7.20.1 → gam7-7.20.3}/wiki/Todrive.md +0 -0
  210. {gam7-7.20.1 → gam7-7.20.3}/wiki/Unmanaged-Accounts.md +0 -0
  211. {gam7-7.20.1 → gam7-7.20.3}/wiki/Upgrade-Benefits.md +0 -0
  212. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Analytics-Admin.md +0 -0
  213. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Application-Specific-Passwords.md +0 -0
  214. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Backup-Verification-Codes.md +0 -0
  215. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Calendars-Access.md +0 -0
  216. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Calendars-Events.md +0 -0
  217. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Calendars.md +0 -0
  218. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Classification-Labels.md +0 -0
  219. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Classroom-Profile.md +0 -0
  220. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Contacts-Delegates.md +0 -0
  221. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Contacts.md +0 -0
  222. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Deprovision.md +0 -0
  223. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Activity-Settings.md +0 -0
  224. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Cleanup.md +0 -0
  225. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Comments.md +0 -0
  226. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Copy-Move.md +0 -0
  227. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Files-Display.md +0 -0
  228. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Files-Manage.md +0 -0
  229. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Orphans.md +0 -0
  230. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Ownership.md +0 -0
  231. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Query.md +0 -0
  232. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Revisions.md +0 -0
  233. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Shortcuts.md +0 -0
  234. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Drive-Transfer.md +0 -0
  235. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Forms.md +0 -0
  236. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Gmail-CSE.md +0 -0
  237. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Gmail-Delegates.md +0 -0
  238. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Gmail-Filters.md +0 -0
  239. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Gmail-Forwarding.md +0 -0
  240. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Gmail-Labels.md +0 -0
  241. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Gmail-Messages-Threads.md +0 -0
  242. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Gmail-Profile.md +0 -0
  243. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Gmail-S-MIME.md +0 -0
  244. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Gmail-Send-As-Signature-Vacation.md +0 -0
  245. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Gmail-Settings.md +0 -0
  246. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Group-Membership.md +0 -0
  247. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Keep-Notes.md +0 -0
  248. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Looker-Studio.md +0 -0
  249. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Meet.md +0 -0
  250. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-People-Contacts-Profiles.md +0 -0
  251. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Photo.md +0 -0
  252. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Profile-Photo.md +0 -0
  253. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Profile-Sharing.md +0 -0
  254. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Signout-Turnoff2SV.md +0 -0
  255. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Spreadsheets.md +0 -0
  256. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Tag-Manager.md +0 -0
  257. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Tasks.md +0 -0
  258. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Tokens.md +0 -0
  259. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-Web-Resources-and-Sites.md +0 -0
  260. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users-YouTube.md +0 -0
  261. {gam7-7.20.1 → gam7-7.20.3}/wiki/Users.md +0 -0
  262. {gam7-7.20.1 → gam7-7.20.3}/wiki/Using-GAM7-with-a-YubiKey.md +0 -0
  263. {gam7-7.20.1 → gam7-7.20.3}/wiki/Using-GAM7-with-a-delegated-admin-service-account.md +0 -0
  264. {gam7-7.20.1 → gam7-7.20.3}/wiki/Vault-Takeout.md +0 -0
  265. {gam7-7.20.1 → gam7-7.20.3}/wiki/Verifying-a-GAM7-Build-is-Legitimate-and-Official.md +0 -0
  266. {gam7-7.20.1 → gam7-7.20.3}/wiki/_Sidebar.md +0 -0
  267. {gam7-7.20.1 → gam7-7.20.3}/wiki/gam.cfg.md +0 -0
  268. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-AdminSettingsExamples.md +0 -0
  269. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Android-Installation.md +0 -0
  270. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-BulkOperations.md +0 -0
  271. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-CalendarExamples.md +0 -0
  272. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Chat-Bot.md +0 -0
  273. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Chrome-Browser-Management.md +0 -0
  274. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Chrome-OS-Installation.md +0 -0
  275. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Chrome-Policy-Settings.md +0 -0
  276. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Cloud-Identity-Groups.md +0 -0
  277. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Command-Reference-Calendar-Resources.md +0 -0
  278. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Command-Reference-Calendars.md +0 -0
  279. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Command-Reference-Definitions.md +0 -0
  280. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Command-Reference-Drive.md +0 -0
  281. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Command-Reference-Email.md +0 -0
  282. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Command-Reference-Group-Attributes.md +0 -0
  283. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Command-Reference-Groups.md +0 -0
  284. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Command-Reference-Users.md +0 -0
  285. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Context-Aware-Access-Levels.md +0 -0
  286. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Creating-client_secrets.json-and-oauth2service.json.md +0 -0
  287. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-CreatingClientSecretsFile.md +0 -0
  288. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Custom-Schemas.md +0 -0
  289. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Data-Transfers.md +0 -0
  290. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-DomainVerification.md +0 -0
  291. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-ExamplesAccountAuditing.md +0 -0
  292. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-ExamplesCSV.md +0 -0
  293. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-ExamplesEmailSettings.md +0 -0
  294. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-ExamplesOrganizations.md +0 -0
  295. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-GAM-Discussion-Group.md +0 -0
  296. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-GAM-on-Android-and-Chrome-OS.md +0 -0
  297. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-GAM-options-files.md +0 -0
  298. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-GAM-with--minimal-GCP-rights.md +0 -0
  299. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-GAM3CSVListings.md +0 -0
  300. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-GAM3DirectoryCommands.md +0 -0
  301. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-GAM3GroupSettings.md +0 -0
  302. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-GAM7-FAQ.md +0 -0
  303. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Google-Vault---Takeout-Commands.md +0 -0
  304. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-GoogleDriveManagement.md +0 -0
  305. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Grouping-18-or-Older-Users.md +0 -0
  306. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Home.md +0 -0
  307. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-How-to-upgrade-from-Standard-GAM.md +0 -0
  308. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Inbound-SSO-Settings.md +0 -0
  309. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-LicenseExamples.md +0 -0
  310. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Managing-Admins.md +0 -0
  311. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Managing-CloudPrint-Printers.md +0 -0
  312. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Managing-Devices.md +0 -0
  313. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Managing-Google-Classroom.md +0 -0
  314. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-OAuthKeyManagement.md +0 -0
  315. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Printers.md +0 -0
  316. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-ResellerCommands.md +0 -0
  317. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Running-GAM-on-Google-Compute-Engine-(GCE)-Securely.md +0 -0
  318. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-SecurityExamples.md +0 -0
  319. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-UnmanagedUsersExamples.md +0 -0
  320. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Use-a-Yubikey.md +0 -0
  321. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-Using-GAM-with-a-delegated-admin-service-account-(DASA).md +0 -0
  322. {gam7-7.20.1 → gam7-7.20.3}/wiki/l-_Footer.md +0 -0
@@ -30,7 +30,7 @@ env:
30
30
  PYTHON_SOURCE_PATH: ${{ github.workspace }}/src/cpython
31
31
  CRYPTOGRAPHY_BUILD_OPENSSL_NO_LEGACY: 1
32
32
  CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
33
- WINDOWS_CODESIGN_CERT_HASH: 590dc5bb10dfb31dbff38c0e2f9c35ef0f6d0e9e
33
+ WINDOWS_CODESIGN_CERT_HASH: 3B11D9340A45CF078FF7FD984F1C3E30DA82FD05
34
34
 
35
35
  jobs:
36
36
  build:
@@ -655,7 +655,7 @@ jobs:
655
655
  write-Host "Signing ${env:gam}...."
656
656
  # Always explicitely use x64 version os signtool.exe, arm64 version apparently can't
657
657
  # see Certum certs since SimplySignDesktop is x64-only today.
658
- Start-Process -Wait -NoNewWindow -ErrorAction Continue -FilePath 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' -ArgumentList "sign", "/sha1", "590dc5bb10dfb31dbff38c0e2f9c35ef0f6d0e9e", "/tr", "http://time.certum.pl", "/td", "SHA256", "/fd", "SHA256", "/v", "$env:gam"
658
+ Start-Process -Wait -NoNewWindow -ErrorAction Continue -FilePath 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' -ArgumentList "sign", "/sha1", "$env:WINDOWS_CODESIGN_CERT_HASH", "/tr", "http://time.certum.pl", "/td", "SHA256", "/fd", "SHA256", "/v", "$env:gam"
659
659
  write-Host "Verifying signature of ${env:gam}...."
660
660
  # verify signature. If we failed to sign we should fail to verify and die.
661
661
  & 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' verify /pa /v "$env:gam"
@@ -727,7 +727,7 @@ jobs:
727
727
  write-Host "Signing ${env:MSI_FILENAME}...."
728
728
  # Always explicitely use x64 version os signtool.exe, arm64 version apparently can't
729
729
  # see Certum certs since SimplySignDesktop is x64-only today.
730
- Start-Process -Wait -NoNewWindow -ErrorAction Continue -FilePath 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' -ArgumentList "sign", "/sha1", "590dc5bb10dfb31dbff38c0e2f9c35ef0f6d0e9e", "/tr", "http://time.certum.pl", "/td", "SHA256", "/fd", "SHA256", "/v", "$env:MSI_FILENAME"
730
+ Start-Process -Wait -NoNewWindow -ErrorAction Continue -FilePath 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' -ArgumentList "sign", "/sha1", "$env:WINDOWS_CODESIGN_CERT_HASH", "/tr", "http://time.certum.pl", "/td", "SHA256", "/fd", "SHA256", "/v", "$env:MSI_FILENAME"
731
731
  write-Host "Verifying signature of ${env:MSI_FILENAME}...."
732
732
  # verify signature. If we failed to sign we should fail to verify and die.
733
733
  & 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' verify /pa /v "$env:MSI_FILENAME"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gam7
3
- Version: 7.20.1
3
+ Version: 7.20.3
4
4
  Summary: CLI tool to manage Google Workspace
5
5
  Project-URL: Homepage, https://github.com/GAM-team/GAM
6
6
  Project-URL: Issues, https://github.com/GAM-team/GAM/issues
@@ -266,7 +266,7 @@ If an item contains spaces, it should be surrounded by ".
266
266
  appsheetstandard | appsheetenterprisestandard | 1010380002 | AppSheet Enterprise Standard |
267
267
  appsheetplus | appsheetenterpriseplus | 1010380003 | AppSheet Enterprise Plus |
268
268
  assuredcontrols | 1010390001 | Assured Controls |
269
- assuredcontrolsplus | 1010390002 | Assured Controls Plus |
269
+ assuredcontrolsplus | 1010390002 | Assured Controls Plus |
270
270
  bce | beyondcorp | beyondcorpenterprise | cep | chromeenterprisepremium | 1010400001 | Chrome Enterprise Premium |
271
271
  cdm | chrome | googlechromedevicemanagement | Google-Chrome-Device-Management |
272
272
  cloudidentity | identity | 1010010001 | Cloud Identity |
@@ -275,8 +275,8 @@ If an item contains spaces, it should be surrounded by ".
275
275
  colabpro | 1010500001 | Colab Pro |
276
276
  colabpro+ | colabproplus | 1010500002 | Colab Pro+ |
277
277
  eeu | 1010490001 | SKU Endpoint Education Upgrade |
278
+ gaiproedu | geminiedu | 1010470004 | Google AI Pro for Education |
278
279
  geminibiz | 1010470003 | Gemini Business |
279
- geminiedu | 1010470004 | Gemini Education |
280
280
  geminiedupremium| 1010470005 | Gemini Education Premium |
281
281
  geminient| duetai | 1010470001 | Gemini Enterprise |
282
282
  geminiultra | 1010470008 | Google AI Ultra for Business |
@@ -316,12 +316,12 @@ If an item contains spaces, it should be surrounded by ".
316
316
  wsbizstarter | workspacebusinessstarter | wsbizstart | 1010020027 | Google Workspace Business Starter |
317
317
  wsbizstarterarchived | workspacebusinessstarterarchived | 1010340005 | Google Workspace Business Starter - Archived User |
318
318
  wsentess | workspaceenterpriseessentials | 1010060003 | Google Workspace Enterprise Essentials |
319
- wsentplus | workspaceenterpriseplus | gae | gse | enterprise | gsuiteenterprise | 1010020020 | Google Workspace Enterprise Plus |
319
+ wsentplus | workspaceenterpriseplus | gae | gse | enterprise | gsuiteenterprise | 1010020020 | Google Workspace Enterprise Plus (formerly G Suite Enterprise) |
320
320
  wsentstan | workspaceenterprisestandard | 1010020026 | Google Workspace Enterprise Standard |
321
321
  wsentstanarchived | workspaceenterprisestandardarchived | 1010340004 | Google Workspace Enterprise Standard - Archived User |
322
322
  wsentstarter | workspaceenterprisestarter | wes | 1010020029 | Workspace Enterprise Starter |
323
- wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 | Google Workspace Essentials |
324
- wsessplus | workspaceessentialsplus | 1010060005 | Google Workspace Essentials Plus |
323
+ wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 | Google Workspace Essentials (formerly G Suite Essentials) |
324
+ wsessplus | workspaceessentialsplus | 1010060005 | Google Workspace Enterprise Essentials Plus |
325
325
  wsflw | workspacefrontline | workspacefrontlineworker | 1010020030 | Google Workspace Frontline Starter |
326
326
  wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031 | Google Workspace Frontline Standard |
327
327
  wsflwplus | workspacefrontlineplus | workspacefrontlineworkerplus | 1010020034 | Google Workspace Frontline Plus
@@ -1246,6 +1246,8 @@ Specify a collection of items by directly specifying them; the item type is dete
1246
1246
  <SiteACLScopeList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
1247
1247
  <SiteEntity> ::=
1248
1248
  <SiteList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
1249
+ <StringEntity> ::=
1250
+ <StringList> | <FileSelector> | <CSVFileSelector>
1249
1251
  <StudentGroupEntity> ::=
1250
1252
  <StudentGroupIDList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector>
1251
1253
  <TagManagerAccountPathEntity> ::=
@@ -3396,7 +3398,7 @@ gam print course-works [todrive <ToDriveAttribute>*]
3396
3398
 
3397
3399
  gam create course-studentgroups
3398
3400
  (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
3399
- title <String>
3401
+ ((title <String>)|(select <StringEntity))+
3400
3402
  [csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]]
3401
3403
  gam update course-studentgroups <CourseID> <StudentGroupID> title <String>
3402
3404
  gam delete course-studentgroups <CourseID> <StudentGroupIDEntity>
@@ -5094,7 +5096,7 @@ gam create|add drivefileacl <SharedDriveEntityAdmin>
5094
5096
  anyone|(user <UserItem>)|(group <GroupItem>)|(domain <DomainName>)
5095
5097
  (role <DriveFileACLRole>) [withlink|(allowfilediscovery|discoverable [<Boolean>])]
5096
5098
  (mappermissionsdomain <DomainName> <DomainName>)*
5097
- [expiration <Time>] [sendemail] [emailmessage <String>]
5099
+ [expiration <Time>] [sendemail|sendnotification] [emailmessage <String>]
5098
5100
  [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
5099
5101
  gam update drivefileacl <SharedDriveEntityAdmin> <DriveFilePermissionIDorEmail>
5100
5102
  (role <DriveFileACLRole>) [expires|expiration <Time>] [removeexpiration [<Boolean>]]
@@ -5121,7 +5123,7 @@ gam print drivefileacls <SharedDriveEntityAdmin> [todrive <ToDriveAttribute>*]
5121
5123
  (orderby <DriveFileOrderByFieldName> [ascending|descending])*
5122
5124
  [formatjson [quotechar <Character>]]
5123
5125
  gam create|add permissions <SharedDriveEntityAdmin> <DriveFilePermissionEntity>
5124
- [expires|expiration <Time>] [sendemail] [emailmessage <String>]
5126
+ [expires|expiration <Time>] [sendemail|sendnotification] [emailmessage <String>]
5125
5127
  <PermissionMatch>* [<PermissionMatchAction>]
5126
5128
  gam delete permissions <SharedDriveEntityAdmin> <DriveFilePermissionIDEntity>
5127
5129
  <PermissionMatch>* [<PermissionMatchAction>]
@@ -5134,7 +5136,7 @@ gam <UserTypeEntity> create|add drivefileacl <SharedDriveEntityAdmin>
5134
5136
  (role <DriveFileACLRole>) [withlink|(allowfilediscovery|discoverable [<Boolean>])]
5135
5137
  (mappermissionsdomain <DomainName> <DomainName>)*
5136
5138
  [movetonewownersroot [<Boolean>]]
5137
- [expiration <Time>] [sendemail] [emailmessage <String>]
5139
+ [expiration <Time>] [sendemail|sendnotification] [emailmessage <String>]
5138
5140
  [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
5139
5141
  adminaccess
5140
5142
  gam <UserTypeEntity> update drivefileacl <SharedDriveEntityAdmin> <DriveFilePermissionIDorEmail>
@@ -5165,7 +5167,7 @@ gam <UserTypeEntity> print drivefileacls <SharedDriveEntityAdmin> [todrive <ToDr
5165
5167
  (orderby <DriveFileOrderByFieldName> [ascending|descending])*
5166
5168
  [formatjson [quotechar <Character>]]
5167
5169
  gam <UserTypeEntity> create|add permissions <SharedDriveEntityAdmin> <DriveFilePermissionEntity>
5168
- [expires|expiration <Time>] [sendemail] [emailmessage <String>] adminaccess
5170
+ [expires|expiration <Time>] [sendemail|sendnotification] [emailmessage <String>] adminaccess
5169
5171
  <PermissionMatch>* [<PermissionMatchAction>]
5170
5172
  gam <UserTypeEntity> delete permissions <SharedDriveEntityAdmin> <DriveFilePermissionIDEntity> adminaccess
5171
5173
  <PermissionMatch>* [<PermissionMatchAction>]
@@ -6894,7 +6896,7 @@ gam <UserTypeEntity> create|add drivefileacl <DriveFileEntity> [adminaccess|asad
6894
6896
  anyone|(user <UserItem>)|(group <GroupItem>)|(domain <DomainName>) (role <DriveFileACLRole>)
6895
6897
  [withlink|(allowfilediscovery|discoverable [<Boolean>])] [expiration <Time>]
6896
6898
  [moveToNewOwnersRoot [<Boolean>]]
6897
- [sendemail] [emailmessage <String>]
6899
+ [sendemail|sendnotification] [emailmessage <String>]
6898
6900
  [updatesheetprotectedranges [<Boolean>]]
6899
6901
  [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
6900
6902
  gam <UserTypeEntity> update drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail>
@@ -6920,7 +6922,7 @@ gam <UserTypeEntity> print drivefileacls <DriveFileEntity> [todrive <ToDriveAttr
6920
6922
  (orderby <DriveFileOrderByFieldName> [ascending|descending])*
6921
6923
  [formatjson [quotechar <Character>]]
6922
6924
  gam <UserTypeEntity> create|add permissions <DriveFileEntity> <DriveFilePermissionEntity>
6923
- [expires|expiration <Time>] [sendemail] [emailmessage <String>]
6925
+ [expires|expiration <Time>] [sendemail|sendnotification] [emailmessage <String>]
6924
6926
  [movetonewownersroot [<Boolean>]]
6925
6927
  <PermissionMatch>* [<PermissionMatchAction>]
6926
6928
  gam <UserTypeEntity> delete permissions <DriveFileEntity> <DriveFilePermissionIDEntity>
@@ -1,3 +1,15 @@
1
+ 7.20.03
2
+
3
+ Rebranded license SKU `1010470004` from `Gemini Education` to `Google AI Pro for Education`.
4
+
5
+ Additional updates to student groups in Google Classroom.
6
+
7
+ 7.20.02
8
+
9
+ Upgraded `gam create course-studentgroups` to allow specification of multiple student group titles;
10
+ multiple student groups can be created in a single command.
11
+ * `((title <String>)|(select <StringEntity))+`
12
+
1
13
  7.20.01
2
14
 
3
15
  Added option `showaccesssettings` to `gam [<UserTypeEntity>] print|show chatspaces`. When listing
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
25
25
  """
26
26
 
27
27
  __author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
28
- __version__ = '7.20.01'
28
+ __version__ = '7.20.03'
29
29
  __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
30
30
 
31
31
  #pylint: disable=wrong-import-position
@@ -51233,7 +51233,7 @@ def printShowClassroomProfile(users):
51233
51233
 
51234
51234
  # gam create course-studentgroups
51235
51235
  # (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
51236
- # title <String>
51236
+ # ((title <String>)|(select <StringEntity))+
51237
51237
  # [csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]]
51238
51238
  def doCreateCourseStudentGroups():
51239
51239
  croom = buildGAPIObject(API.CLASSROOM)
@@ -51243,10 +51243,13 @@ def doCreateCourseStudentGroups():
51243
51243
  courseShowProperties = _initCourseShowProperties(['name'])
51244
51244
  useOwnerAccess = GC.Values[GC.USE_COURSE_OWNER_ACCESS]
51245
51245
  kwargs = {'courseId': None, 'body': {}}
51246
+ titles = []
51246
51247
  while Cmd.ArgumentsRemaining():
51247
51248
  myarg = getArgument()
51248
51249
  if myarg == 'title':
51249
- kwargs['body']['title'] = getString(Cmd.OB_STRING)
51250
+ titles.append(getString(Cmd.OB_STRING, maxLen=100))
51251
+ elif myarg == 'select':
51252
+ titles.extend(getEntityList(Cmd.OB_STRING_ENTITY, shlexSplit=True))
51250
51253
  elif _getCourseSelectionParameters(myarg, courseSelectionParameters):
51251
51254
  pass
51252
51255
  elif myarg == 'csv':
@@ -51256,8 +51259,9 @@ def doCreateCourseStudentGroups():
51256
51259
  csvPF.GetTodriveParameters()
51257
51260
  else:
51258
51261
  FJQC.GetFormatJSONQuoteChar(myarg, True)
51259
- if 'title' not in kwargs['body']:
51262
+ if not titles:
51260
51263
  missingArgumentExit('title')
51264
+ jcount = len(titles)
51261
51265
  if csvPF and FJQC.formatJSON:
51262
51266
  csvPF.SetJSONTitles(['courseId', 'courseName', 'JSON'])
51263
51267
  coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties, useOwnerAccess)
@@ -51272,29 +51276,36 @@ def doCreateCourseStudentGroups():
51272
51276
  if not ocroom:
51273
51277
  continue
51274
51278
  kwargs['courseId'] = courseId
51275
- kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, None]
51276
- try:
51277
- studentGroup = callGAPI(ocroom.courses().studentGroups(), 'create',
51278
- throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE, GAPI.NOT_IMPLEMENTED,
51279
- GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
51280
- retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
51281
- previewVersion='V1_20250630_PREVIEW',
51282
- **kwargs)
51283
- kvList[-1] = f"{studentGroup['title']}({studentGroup['id']})"
51284
- if not csvPF:
51285
- entityActionPerformed(kvList, i, count)
51286
- elif not FJQC.formatJSON:
51287
- csvPF.WriteRow({'courseId': courseId, 'courseName': course['name'],
51288
- 'studentGroupId': studentGroup['id'], 'studentGroupTitle': studentGroup['title']})
51289
- else:
51290
- csvPF.WriteRowNoFilter({'courseId': courseId, 'courseName': course['name'],
51291
- 'JSON': json.dumps(cleanJSON(studentGroup), ensure_ascii=False, sort_keys=True)})
51292
- except GAPI.notFound as e:
51293
- entityActionFailedWarning(kvList, str(e), i, count)
51294
- except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
51295
- entityActionFailedExit([Ent.COURSE, courseId], str(e), i, count)
51296
- except (GAPI.forbidden, GAPI.permissionDenied) as e:
51297
- ClientAPIAccessDeniedExit(str(e))
51279
+ entityPerformActionNumItems([Ent.COURSE, courseId], jcount, Ent.COURSE_STUDENTGROUP, i, count)
51280
+ Ind.Increment()
51281
+ j = 0
51282
+ for title in titles:
51283
+ j += 1
51284
+ kwargs['body']['title'] = title
51285
+ kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, None]
51286
+ try:
51287
+ studentGroup = callGAPI(ocroom.courses().studentGroups(), 'create',
51288
+ throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE, GAPI.NOT_IMPLEMENTED,
51289
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
51290
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
51291
+ previewVersion='V1_20250630_PREVIEW',
51292
+ **kwargs)
51293
+ kvList[-1] = f"{studentGroup['title']}({studentGroup['id']})"
51294
+ if not csvPF:
51295
+ entityActionPerformed(kvList, j, jcount)
51296
+ elif not FJQC.formatJSON:
51297
+ csvPF.WriteRow({'courseId': courseId, 'courseName': course['name'],
51298
+ 'studentGroupId': studentGroup['id'], 'studentGroupTitle': studentGroup['title']})
51299
+ else:
51300
+ csvPF.WriteRowNoFilter({'courseId': courseId, 'courseName': course['name'],
51301
+ 'JSON': json.dumps(cleanJSON(studentGroup), ensure_ascii=False, sort_keys=True)})
51302
+ except GAPI.notFound as e:
51303
+ entityActionFailedWarning(kvList, str(e), j, jcount)
51304
+ except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
51305
+ entityActionFailedExit([Ent.COURSE, courseId], str(e), j, jcount)
51306
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
51307
+ ClientAPIAccessDeniedExit(str(e))
51308
+ Ind.Decrement()
51298
51309
  if csvPF:
51299
51310
  csvPF.writeCSVfile('Course Student Groups')
51300
51311
 
@@ -51439,8 +51450,26 @@ def doClearCourseStudentGroups():
51439
51450
  # (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
51440
51451
  # [showitemcountonly] [formatjson [quotechar <Character>]]
51441
51452
  def doPrintCourseStudentGroups(showMembers=False):
51453
+ def _getCourseStudents():
51454
+ studentIdEmailMap = {}
51455
+ try:
51456
+ students = callGAPIpages(ocroom.courses().students(), 'list', 'students',
51457
+ throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
51458
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
51459
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
51460
+ courseId=courseId, fields='nextPageToken,students(profile(id,emailAddress))',
51461
+ pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
51462
+ for student in students:
51463
+ studentIdEmailMap[student['profile']['id']] = student['profile']['emailAddress']
51464
+ except GAPI.notFound:
51465
+ pass
51466
+ except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
51467
+ entityActionFailedExit([Ent.COURSE, courseId], str(e))
51468
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
51469
+ ClientAPIAccessDeniedExit(str(e))
51470
+ return studentIdEmailMap
51471
+
51442
51472
  croom = buildGAPIObject(API.CLASSROOM)
51443
- cd = buildGAPIObject(API.DIRECTORY)
51444
51473
  csvPF = CSVPrintFile(['courseId', 'courseName', 'studentGroupId', 'studentGroupTitle'])
51445
51474
  FJQC = FormatJSONQuoteChar(csvPF)
51446
51475
  courseSelectionParameters = _initCourseSelectionParameters()
@@ -51492,6 +51521,8 @@ def doPrintCourseStudentGroups(showMembers=False):
51492
51521
  if not showMembers and showItemCountOnly:
51493
51522
  itemCount += len(studentGroups)
51494
51523
  continue
51524
+ if showMembers:
51525
+ studentIdEmailMap = _getCourseStudents()
51495
51526
  for studentGroup in studentGroups:
51496
51527
  studentGroupId = studentGroup['id']
51497
51528
  if not showMembers:
@@ -51504,7 +51535,7 @@ def doPrintCourseStudentGroups(showMembers=False):
51504
51535
  row['JSON'] = json.dumps(cleanJSON(studentGroup), ensure_ascii=False, sort_keys=False)
51505
51536
  csvPF.WriteRowTitles(row)
51506
51537
  continue
51507
- printGettingEntityItemForWhom(Ent.USER, formatKeyValueList('', [Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId],
51538
+ printGettingEntityItemForWhom(Ent.STUDENT, formatKeyValueList('', [Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId],
51508
51539
  currentCount(i, count)))
51509
51540
  pageMessage = getPageMessage()
51510
51541
  try:
@@ -51519,7 +51550,7 @@ def doPrintCourseStudentGroups(showMembers=False):
51519
51550
  itemCount += len(students)
51520
51551
  continue
51521
51552
  for member in students:
51522
- member['userEmail'] = convertUIDtoEmailAddress(f"id:{member['userId']}", cd=cd, emailTypes=['user'])
51553
+ member['userEmail'] = studentIdEmailMap.get(member['userId'], member['userId'])
51523
51554
  except GAPI.notFound as e:
51524
51555
  entityActionFailedWarning([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], str(e))
51525
51556
  continue
@@ -51551,8 +51582,29 @@ def doPrintCourseStudentGroups(showMembers=False):
51551
51582
  # gam sync course-studentgroup-members <CourseID> <StudentGroupID> <UserTypeEntity>
51552
51583
  # gam clear course-studentgroup-members <CourseID> <StudentGroupID>
51553
51584
  def doProcessCourseStudentGroupMembers():
51554
- def _getCurrentStudents():
51555
- printGettingEntityItemForWhom(Ent.USER, Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId)
51585
+ def _getCourseStudents():
51586
+ studentIdEmailMap = {}
51587
+ studentEmailIdMap = {}
51588
+ try:
51589
+ students = callGAPIpages(ocroom.courses().students(), 'list', 'students',
51590
+ throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
51591
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
51592
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
51593
+ courseId=courseId, fields='nextPageToken,students(profile(id,emailAddress))',
51594
+ pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
51595
+ for student in students:
51596
+ studentIdEmailMap[student['profile']['id']] = student['profile']['emailAddress'].lower()
51597
+ studentEmailIdMap[student['profile']['emailAddress'].lower()] = student['profile']['id']
51598
+ return (studentIdEmailMap, studentEmailIdMap)
51599
+ except GAPI.notFound as e:
51600
+ entityActionFailedExit([Ent.COURSE, courseId], str(e))
51601
+ except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
51602
+ entityActionFailedExit([Ent.COURSE, courseId], str(e))
51603
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
51604
+ ClientAPIAccessDeniedExit(str(e))
51605
+
51606
+ def _getGroupCurrentStudents():
51607
+ printGettingEntityItemForWhom(Ent.STUDENT, formatKeyValueList('', [Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId], ''))
51556
51608
  pageMessage = getPageMessage()
51557
51609
  try:
51558
51610
  return callGAPIpages(ocroom.courses().studentGroups().studentGroupMembers(), 'list', 'studentGroupMembers',
@@ -51570,18 +51622,24 @@ def doProcessCourseStudentGroupMembers():
51570
51622
  except (GAPI.forbidden, GAPI.permissionDenied) as e:
51571
51623
  ClientAPIAccessDeniedExit(str(e))
51572
51624
 
51573
- def _getStudentUserId(kvList, student, i, count):
51574
- normalizedEmailAddressOrUID = normalizeEmailAddressOrUID(student)
51575
- if normalizedEmailAddressOrUID.find('@') == -1:
51576
- return normalizedEmailAddressOrUID
51577
- try:
51578
- return callGAPI(cd.users(), 'get',
51579
- throwReasons=GAPI.USER_GET_THROW_REASONS,
51580
- userKey=normalizedEmailAddressOrUID, fields='id')['id']
51581
- except (GAPI.userNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
51582
- GAPI.badRequest, GAPI.backendError, GAPI.systemError) as e:
51583
- entityActionFailedWarning(kvList, str(e), i, count)
51584
- return None
51625
+ def _validateClStudents(clStudents):
51626
+ status = True
51627
+ clStudentIds = []
51628
+ count = len(clStudents)
51629
+ i = 0
51630
+ kvList = [Ent.COURSE, courseId, Ent.STUDENT, '']
51631
+ for student in clStudents:
51632
+ i += 1
51633
+ student = normalizeEmailAddressOrUID(student)
51634
+ if student in studentIdEmailMap:
51635
+ clStudentIds.append(student)
51636
+ elif student in studentEmailIdMap:
51637
+ clStudentIds.append(studentEmailIdMap[student])
51638
+ else:
51639
+ kvList[-1] = student
51640
+ entityActionFailedWarning(kvList, Msg.STUDENT_NOT_IN_COURSE, i, count)
51641
+ status = False
51642
+ return clStudentIds if status else None
51585
51643
 
51586
51644
  def _processStudent(function, kvList, kwargs, i, count):
51587
51645
  try:
@@ -51600,85 +51658,69 @@ def doProcessCourseStudentGroupMembers():
51600
51658
  except (GAPI.forbidden, GAPI.permissionDenied) as e:
51601
51659
  ClientAPIAccessDeniedExit(str(e))
51602
51660
 
51603
- def _addStudents(students, getUserIds):
51661
+ def _addStudents(students):
51604
51662
  count = len(students)
51605
51663
  i = 0
51606
- entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.USER)
51607
- kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.USER, '']
51664
+ entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.STUDENT)
51665
+ kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.STUDENT, '']
51608
51666
  kwargs = {'courseId': courseId, 'studentGroupId': studentGroupId, 'body': {'userId': ''}}
51667
+ Ind.Increment()
51609
51668
  for student in students:
51610
51669
  i += 1
51611
- if getUserIds:
51612
- userId = _getStudentUserId(kvList, student, i, count)
51613
- if userId is None:
51614
- continue
51615
- kvList[-1] = student
51616
- else:
51617
- userId = student
51618
- kvList[-1] = convertUIDtoEmailAddress(f"id:{userId}", cd=cd, emailTypes=['user'])
51619
- kwargs['body']['userId'] = userId
51670
+ kvList[-1] = studentIdEmailMap[student]
51671
+ kwargs['body']['userId'] = student
51620
51672
  _processStudent('create', kvList, kwargs, i, count)
51673
+ Ind.Decrement()
51621
51674
 
51622
- def _removeStudents(students, getUserIds):
51675
+ def _removeStudents(students):
51623
51676
  count = len(students)
51624
51677
  i = 0
51625
- entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.USER)
51626
- kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.USER, '']
51678
+ entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.STUDENT)
51679
+ kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.STUDENT, '']
51627
51680
  kwargs = {'courseId': courseId, 'studentGroupId': studentGroupId, 'userId': ''}
51681
+ Ind.Increment()
51628
51682
  for student in students:
51629
51683
  i += 1
51630
- if getUserIds:
51631
- userId = _getStudentUserId(kvList, student, i, count)
51632
- if userId is None:
51633
- continue
51634
- kvList[-1] = student
51635
- else:
51636
- userId = student
51637
- kvList[-1] = convertUIDtoEmailAddress(f"id:{userId}", cd=cd, emailTypes=['user'])
51638
- kwargs['userId'] = userId
51684
+ kvList[-1] = studentIdEmailMap[student]
51685
+ kwargs['userId'] = student
51639
51686
  _processStudent('delete', kvList, kwargs, i, count)
51687
+ Ind.Decrement()
51640
51688
 
51641
51689
  croom = buildGAPIObject(API.CLASSROOM)
51642
- cd = buildGAPIObject(API.DIRECTORY)
51643
51690
  action = Act.Get()
51644
51691
  courseId = getString(Cmd.OB_COURSE_ID)
51645
51692
  studentGroupId = getString(Cmd.OB_STUDENTGROUP_ID)
51646
51693
  if action != Act.CLEAR:
51647
51694
  _, clStudents = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS, groupMemberType=Ent.TYPE_USER)
51648
- clStudents = [normalizeEmailAddressOrUID(student) for student in clStudents]
51695
+ clStudentIds = []
51649
51696
  checkForExtraneousArguments()
51650
51697
  _, count, coursesInfo = _getCoursesOwnerInfo(croom, [courseId], GC.Values[GC.USE_COURSE_OWNER_ACCESS])
51651
51698
  if count == 0:
51652
51699
  return
51653
51700
  ocroom = coursesInfo[courseId]['croom']
51654
51701
  courseId = coursesInfo[courseId]['id']
51702
+ studentIdEmailMap, studentEmailIdMap = _getCourseStudents()
51655
51703
  if action in {Act.SYNC, Act.CLEAR}:
51656
- currentStudents = [student['userId'] for student in _getCurrentStudents()]
51704
+ currentStudents = [student['userId'] for student in _getGroupCurrentStudents()]
51705
+ if action != Act.CLEAR:
51706
+ clStudentIds = _validateClStudents(clStudents)
51707
+ if clStudentIds is None:
51708
+ return
51657
51709
  if action == Act.CLEAR:
51658
- _removeStudents(currentStudents, False)
51710
+ _removeStudents(currentStudents)
51659
51711
  elif action == Act.DELETE:
51660
- _removeStudents(clStudents, True)
51712
+ _removeStudents(clStudentIds)
51661
51713
  elif action in {Act.ADD, Act.CREATE}:
51662
- _addStudents(clStudents, True)
51714
+ _addStudents(clStudentIds)
51663
51715
  else: # elif action == Act.SYNC:
51664
51716
  currentMembersSet = set(currentStudents)
51665
- syncMembersSet = set()
51666
- count = len(clStudents)
51667
- i = 0
51668
- kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.USER, '']
51669
- for student in clStudents:
51670
- i += 1
51671
- kvList[-1] = student
51672
- userId = _getStudentUserId(kvList, student, i, count)
51673
- if userId is None:
51674
- continue
51675
- syncMembersSet.add(userId)
51717
+ syncMembersSet = set(clStudentIds)
51676
51718
  removeStudentsSet = currentMembersSet-syncMembersSet
51677
51719
  addStudentsSet = syncMembersSet-currentMembersSet
51678
51720
  Act.Set(Act.DELETE)
51679
- _removeStudents(removeStudentsSet, False)
51721
+ _removeStudents(removeStudentsSet)
51680
51722
  Act.Set(Act.ADD)
51681
- _addStudents(addStudentsSet, False)
51723
+ _addStudents(addStudentsSet)
51682
51724
 
51683
51725
  # gam print course-studentgroup-members [todrive <ToDriveAttribute>*]
51684
51726
  # (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
@@ -65062,7 +65104,7 @@ def _checkFileIdEntityDomainAccess(fileIdEntity, useDomainAdminAccess):
65062
65104
  # (mappermissionsdomain <DomainName> <DomainName>)*
65063
65105
  # [moveToNewOwnersRoot [<Boolean>]]
65064
65106
  # [updatesheetprotectedranges [<Boolean>]]
65065
- # [sendemail] [emailmessage <String>]
65107
+ # [sendemail|sendnotification] [emailmessage <String>]
65066
65108
  # [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
65067
65109
  def createDriveFileACL(users, useDomainAdminAccess=False):
65068
65110
  moveToNewOwnersRoot = False
@@ -65106,7 +65148,7 @@ def createDriveFileACL(users, useDomainAdminAccess=False):
65106
65148
  elif myarg in {'expiration', 'expires'}:
65107
65149
  expirationLocation = Cmd.Location()
65108
65150
  body['expirationTime'] = getTimeOrDeltaFromNow()
65109
- elif myarg == 'sendemail':
65151
+ elif myarg in {'sendemail', 'sendnotification'}:
65110
65152
  sendNotificationEmail = True
65111
65153
  elif myarg == 'emailmessage':
65112
65154
  sendNotificationEmail = True
@@ -65362,7 +65404,7 @@ def doUpdateDriveFileACLs():
65362
65404
  updateDriveFileACLs([_getAdminEmail()], True)
65363
65405
 
65364
65406
  # gam [<UserTypeEntity>] create permissions <DriveFileEntity> <DriveFilePermissionsEntity> [asadmin]
65365
- # [expiration <Time>] [sendmail] [emailmessage <String>]
65407
+ # [expiration <Time>] [sendemail|sendnotification] [emailmessage <String>]
65366
65408
  # [moveToNewOwnersRoot [<Boolean>]]
65367
65409
  # <PermissionMatch>* [<PermissionMatchAction>]
65368
65410
  def createDriveFilePermissions(users, useDomainAdminAccess=False):
@@ -65480,7 +65522,7 @@ def createDriveFilePermissions(users, useDomainAdminAccess=False):
65480
65522
  moveToNewOwnersRoot = getBoolean()
65481
65523
  elif myarg in {'expiration', 'expires'}:
65482
65524
  expiration = getTimeOrDeltaFromNow()
65483
- elif myarg == 'sendemail':
65525
+ elif myarg in {'sendemail', 'sendnotification'}:
65484
65526
  sendNotificationEmail = True
65485
65527
  elif myarg == 'emailmessage':
65486
65528
  sendNotificationEmail = True
@@ -1057,6 +1057,7 @@ class GamCLArgs():
1057
1057
  OB_SPREADSHEET_RANGE_LIST = 'SpreadsheetRangeList'
1058
1058
  OB_STATE_NAME_LIST = "StateNameList"
1059
1059
  OB_STRING = 'String'
1060
+ OB_STRING_ENTITY = 'StringEntity'
1060
1061
  OB_STRING_LIST = 'StringList'
1061
1062
  OB_STUDENTGROUP_ID = 'StudentGroupID'
1062
1063
  OB_STUDENTGROUP_ID_ENTITY = 'StudentGroupIDEntity'
@@ -499,6 +499,7 @@ STATISTICS_MOVE_FILE = 'Total: {0}, Moved: {1}, Shortcut created {2}, Shortcut e
499
499
  STATISTICS_MOVE_FOLDER = 'Total: {0}, Moved: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Merged: {5}, Move Failed: {6}, Not writable: {7}'
500
500
  STATISTICS_USER_NOT_ORGANIZER = 'User not organizer: {0}'
501
501
  STRING_LENGTH = 'string length'
502
+ STUDENT_NOT_IN_COURSE = 'Student not in course'
502
503
  SUBKEY_FIELD_MISMATCH = 'subkeyfield {0} does not match saved subkeyfield {1}'
503
504
  SUBSCRIPTION_NOT_FOUND = 'Could not find subscription'
504
505
  SUFFIX_NOT_ALLOWED_WITH_CUSTOMLANGUAGE = 'Suffix {0} not allowed with customLanguage {1}'
@@ -100,7 +100,7 @@ _SKUS = {
100
100
  '1010470003': {
101
101
  'product': '101047', 'aliases': ['geminibiz'], 'displayName': 'Gemini Business'},
102
102
  '1010470004': {
103
- 'product': '101047', 'aliases': ['geminiedu'], 'displayName': 'Gemini Education'},
103
+ 'product': '101047', 'aliases': ['gaiproedu', 'geminiedu'], 'displayName': 'Google AI Pro for Education'},
104
104
  '1010470005': {
105
105
  'product': '101047', 'aliases': ['geminiedupremium'], 'displayName': 'Gemini Education Premium'},
106
106
  '1010470006': {