gam7 7.9.7__tar.gz → 7.10.0__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 (318) hide show
  1. {gam7-7.9.7 → gam7-7.10.0}/PKG-INFO +1 -1
  2. {gam7-7.9.7 → gam7-7.10.0}/src/GamCommands.txt +20 -1
  3. {gam7-7.9.7 → gam7-7.10.0}/src/GamUpdate.txt +10 -0
  4. {gam7-7.9.7 → gam7-7.10.0}/src/gam/__init__.py +207 -9
  5. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glapi.py +6 -0
  6. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glclargs.py +5 -1
  7. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glentity.py +2 -0
  8. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glmsgs.py +1 -0
  9. {gam7-7.9.7 → gam7-7.10.0}/wiki/Basic-Items.md +3 -1
  10. {gam7-7.9.7 → gam7-7.10.0}/wiki/GamUpdates.md +14 -0
  11. {gam7-7.9.7 → gam7-7.10.0}/wiki/How-to-Upgrade-Legacy-GAM-to-GAM7.md +2 -2
  12. {gam7-7.9.7 → gam7-7.10.0}/wiki/Licenses.md +1 -1
  13. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Chat.md +76 -0
  14. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Files-Display.md +2 -1
  15. {gam7-7.9.7 → gam7-7.10.0}/wiki/Version-and-Help.md +6 -6
  16. {gam7-7.9.7 → gam7-7.10.0}/.github/ISSUE_TEMPLATE/aa-question.md +0 -0
  17. {gam7-7.9.7 → gam7-7.10.0}/.github/ISSUE_TEMPLATE/za-bug-report.md +0 -0
  18. {gam7-7.9.7 → gam7-7.10.0}/.github/ISSUE_TEMPLATE/zz-feature-request.md +0 -0
  19. {gam7-7.9.7 → gam7-7.10.0}/.github/ISSUE_TEMPLATE.txt +0 -0
  20. {gam7-7.9.7 → gam7-7.10.0}/.github/actions/decrypt.sh +0 -0
  21. {gam7-7.9.7 → gam7-7.10.0}/.github/actions/entitlements.plist +0 -0
  22. {gam7-7.9.7 → gam7-7.10.0}/.github/actions/package_exclusions.txt +0 -0
  23. {gam7-7.9.7 → gam7-7.10.0}/.github/stale.yml +0 -0
  24. {gam7-7.9.7 → gam7-7.10.0}/.github/workflows/build.yml +0 -0
  25. {gam7-7.9.7 → gam7-7.10.0}/.github/workflows/codeql-analysis.yml +0 -0
  26. {gam7-7.9.7 → gam7-7.10.0}/.github/workflows/get-cacerts.yml +0 -0
  27. {gam7-7.9.7 → gam7-7.10.0}/.github/workflows/pushwiki.yml +0 -0
  28. {gam7-7.9.7 → gam7-7.10.0}/.github/workflows/pypi.yml +0 -0
  29. {gam7-7.9.7 → gam7-7.10.0}/.pre-commit-config.yaml +0 -0
  30. {gam7-7.9.7 → gam7-7.10.0}/LICENSE +0 -0
  31. {gam7-7.9.7 → gam7-7.10.0}/README.md +0 -0
  32. {gam7-7.9.7 → gam7-7.10.0}/pyproject.toml +0 -0
  33. {gam7-7.9.7 → gam7-7.10.0}/src/.gitignore +0 -0
  34. {gam7-7.9.7 → gam7-7.10.0}/src/LICENSE +0 -0
  35. {gam7-7.9.7 → gam7-7.10.0}/src/cacerts.pem +0 -0
  36. {gam7-7.9.7 → gam7-7.10.0}/src/callgam.py +0 -0
  37. {gam7-7.9.7 → gam7-7.10.0}/src/gam/__main__.py +0 -0
  38. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/__init__.py +0 -0
  39. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/auth.py +0 -0
  40. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/client.py +0 -0
  41. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/core.py +0 -0
  42. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/data.py +0 -0
  43. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/http.py +0 -0
  44. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/http_core.py +0 -0
  45. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/http_interface.py +0 -0
  46. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/mock_http.py +0 -0
  47. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/mock_http_core.py +0 -0
  48. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/mock_service.py +0 -0
  49. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/service.py +0 -0
  50. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/token_store.py +0 -0
  51. {gam7-7.9.7 → gam7-7.10.0}/src/gam/atom/url.py +0 -0
  52. {gam7-7.9.7 → gam7-7.10.0}/src/gam/cacerts.pem +0 -0
  53. {gam7-7.9.7 → gam7-7.10.0}/src/gam/cbcm-v1.1beta1.json +0 -0
  54. {gam7-7.9.7 → gam7-7.10.0}/src/gam/contactdelegation-v1.json +0 -0
  55. {gam7-7.9.7 → gam7-7.10.0}/src/gam/datastudio-v1.json +0 -0
  56. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/__init__.py +0 -0
  57. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glaction.py +0 -0
  58. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glcfg.py +0 -0
  59. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glgapi.py +0 -0
  60. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glgdata.py +0 -0
  61. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glglobals.py +0 -0
  62. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glindent.py +0 -0
  63. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glskus.py +0 -0
  64. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/gluprop.py +0 -0
  65. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/glverlibs.py +0 -0
  66. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gamlib/yubikey.py +0 -0
  67. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/__init__.py +0 -0
  68. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/alt/__init__.py +0 -0
  69. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/alt/app_engine.py +0 -0
  70. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/alt/appengine.py +0 -0
  71. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/apps/__init__.py +0 -0
  72. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/apps/audit/__init__.py +0 -0
  73. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/apps/audit/service.py +0 -0
  74. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/apps/contacts/__init__.py +0 -0
  75. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/apps/contacts/service.py +0 -0
  76. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/apps/service.py +0 -0
  77. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/service.py +0 -0
  78. {gam7-7.9.7 → gam7-7.10.0}/src/gam/gdata/urlfetch.py +0 -0
  79. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/__init__.py +0 -0
  80. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/_auth.py +0 -0
  81. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/_helpers.py +0 -0
  82. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/channel.py +0 -0
  83. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/discovery.py +0 -0
  84. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/discovery_cache/__init__.py +0 -0
  85. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/discovery_cache/appengine_memcache.py +0 -0
  86. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/discovery_cache/base.py +0 -0
  87. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/discovery_cache/file_cache.py +0 -0
  88. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/errors.py +0 -0
  89. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/http.py +0 -0
  90. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/mimeparse.py +0 -0
  91. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/model.py +0 -0
  92. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/schema.py +0 -0
  93. {gam7-7.9.7 → gam7-7.10.0}/src/gam/googleapiclient/version.py +0 -0
  94. {gam7-7.9.7 → gam7-7.10.0}/src/gam/iso8601/__init__.py +0 -0
  95. {gam7-7.9.7 → gam7-7.10.0}/src/gam/iso8601/iso8601.py +0 -0
  96. {gam7-7.9.7 → gam7-7.10.0}/src/gam/meet-v2beta.json +0 -0
  97. {gam7-7.9.7 → gam7-7.10.0}/src/gam/serviceaccountlookup-v1.json +0 -0
  98. {gam7-7.9.7 → gam7-7.10.0}/src/gam/six.py +0 -0
  99. {gam7-7.9.7 → gam7-7.10.0}/src/gam-install.sh +0 -0
  100. {gam7-7.9.7 → gam7-7.10.0}/src/gam-setup.bat +0 -0
  101. {gam7-7.9.7 → gam7-7.10.0}/src/gam.exe.manifest +0 -0
  102. {gam7-7.9.7 → gam7-7.10.0}/src/gam.py +0 -0
  103. {gam7-7.9.7 → gam7-7.10.0}/src/gam.spec +0 -0
  104. {gam7-7.9.7 → gam7-7.10.0}/src/gam.wxs +0 -0
  105. {gam7-7.9.7 → gam7-7.10.0}/src/license.rtf +0 -0
  106. {gam7-7.9.7 → gam7-7.10.0}/src/requirements-dev.txt +0 -0
  107. {gam7-7.9.7 → gam7-7.10.0}/src/requirements.txt +0 -0
  108. {gam7-7.9.7 → gam7-7.10.0}/src/setup.cfg +0 -0
  109. {gam7-7.9.7 → gam7-7.10.0}/src/setup.py +0 -0
  110. {gam7-7.9.7 → gam7-7.10.0}/src/tools/a_atleast_b.py +0 -0
  111. {gam7-7.9.7 → gam7-7.10.0}/src/tools/gen-wix-xml-filelist.py +0 -0
  112. {gam7-7.9.7 → gam7-7.10.0}/src/tools/mkGamRef.py +0 -0
  113. {gam7-7.9.7 → gam7-7.10.0}/src/tools/openssl.props +0 -0
  114. {gam7-7.9.7 → gam7-7.10.0}/src/version_info.txt.in +0 -0
  115. {gam7-7.9.7 → gam7-7.10.0}/wiki/00scratch.md +0 -0
  116. {gam7-7.9.7 → gam7-7.10.0}/wiki/Addresses.md +0 -0
  117. {gam7-7.9.7 → gam7-7.10.0}/wiki/Administrators.md +0 -0
  118. {gam7-7.9.7 → gam7-7.10.0}/wiki/Alert-Center.md +0 -0
  119. {gam7-7.9.7 → gam7-7.10.0}/wiki/Aliases.md +0 -0
  120. {gam7-7.9.7 → gam7-7.10.0}/wiki/Authorization.md +0 -0
  121. {gam7-7.9.7 → gam7-7.10.0}/wiki/BNF-Syntax.md +0 -0
  122. {gam7-7.9.7 → gam7-7.10.0}/wiki/Bulk-Processing.md +0 -0
  123. {gam7-7.9.7 → gam7-7.10.0}/wiki/CSV-Input-Filtering.md +0 -0
  124. {gam7-7.9.7 → gam7-7.10.0}/wiki/CSV-Output-Filtering.md +0 -0
  125. {gam7-7.9.7 → gam7-7.10.0}/wiki/CSV-Special-Characters.md +0 -0
  126. {gam7-7.9.7 → gam7-7.10.0}/wiki/Calendars-Access.md +0 -0
  127. {gam7-7.9.7 → gam7-7.10.0}/wiki/Calendars-Events.md +0 -0
  128. {gam7-7.9.7 → gam7-7.10.0}/wiki/Calendars.md +0 -0
  129. {gam7-7.9.7 → gam7-7.10.0}/wiki/Chat-Bot.md +0 -0
  130. {gam7-7.9.7 → gam7-7.10.0}/wiki/Chrome-AUE-Counts.md +0 -0
  131. {gam7-7.9.7 → gam7-7.10.0}/wiki/Chrome-Browser-Cloud-Management.md +0 -0
  132. {gam7-7.9.7 → gam7-7.10.0}/wiki/Chrome-Installed-Apps.md +0 -0
  133. {gam7-7.9.7 → gam7-7.10.0}/wiki/Chrome-Needs-Attention-Counts.md +0 -0
  134. {gam7-7.9.7 → gam7-7.10.0}/wiki/Chrome-Policies.md +0 -0
  135. {gam7-7.9.7 → gam7-7.10.0}/wiki/Chrome-Printers.md +0 -0
  136. {gam7-7.9.7 → gam7-7.10.0}/wiki/Chrome-Profile-Management.md +0 -0
  137. {gam7-7.9.7 → gam7-7.10.0}/wiki/Chrome-Version-Counts.md +0 -0
  138. {gam7-7.9.7 → gam7-7.10.0}/wiki/Chrome-Version-History.md +0 -0
  139. {gam7-7.9.7 → gam7-7.10.0}/wiki/ChromeOS-Devices.md +0 -0
  140. {gam7-7.9.7 → gam7-7.10.0}/wiki/Classroom-Courses.md +0 -0
  141. {gam7-7.9.7 → gam7-7.10.0}/wiki/Classroom-Guardians.md +0 -0
  142. {gam7-7.9.7 → gam7-7.10.0}/wiki/Classroom-Invitations.md +0 -0
  143. {gam7-7.9.7 → gam7-7.10.0}/wiki/Classroom-Membership.md +0 -0
  144. {gam7-7.9.7 → gam7-7.10.0}/wiki/Cloud-Channel.md +0 -0
  145. {gam7-7.9.7 → gam7-7.10.0}/wiki/Cloud-Identity-Devices.md +0 -0
  146. {gam7-7.9.7 → gam7-7.10.0}/wiki/Cloud-Identity-Groups-Membership.md +0 -0
  147. {gam7-7.9.7 → gam7-7.10.0}/wiki/Cloud-Identity-Groups.md +0 -0
  148. {gam7-7.9.7 → gam7-7.10.0}/wiki/Cloud-Identity-Policies.md +0 -0
  149. {gam7-7.9.7 → gam7-7.10.0}/wiki/Cloud-Storage.md +0 -0
  150. {gam7-7.9.7 → gam7-7.10.0}/wiki/Collections-of-ChromeOS-Devices.md +0 -0
  151. {gam7-7.9.7 → gam7-7.10.0}/wiki/Collections-of-Items.md +0 -0
  152. {gam7-7.9.7 → gam7-7.10.0}/wiki/Collections-of-Users.md +0 -0
  153. {gam7-7.9.7 → gam7-7.10.0}/wiki/Command-Data-From-Google-Docs-Sheets-Storage.md +0 -0
  154. {gam7-7.9.7 → gam7-7.10.0}/wiki/Command-Line-Parsing.md +0 -0
  155. {gam7-7.9.7 → gam7-7.10.0}/wiki/Command-Logging-Progress.md +0 -0
  156. {gam7-7.9.7 → gam7-7.10.0}/wiki/Context-Aware-Access-Levels.md +0 -0
  157. {gam7-7.9.7 → gam7-7.10.0}/wiki/Customer.md +0 -0
  158. {gam7-7.9.7 → gam7-7.10.0}/wiki/Domain-People-Contacts-Profiles.md +0 -0
  159. {gam7-7.9.7 → gam7-7.10.0}/wiki/Domain-SharedContacts.md +0 -0
  160. {gam7-7.9.7 → gam7-7.10.0}/wiki/Domains-Verification.md +0 -0
  161. {gam7-7.9.7 → gam7-7.10.0}/wiki/Domains.md +0 -0
  162. {gam7-7.9.7 → gam7-7.10.0}/wiki/Downloads-Installs.md +0 -0
  163. {gam7-7.9.7 → gam7-7.10.0}/wiki/Drive-File-Selection.md +0 -0
  164. {gam7-7.9.7 → gam7-7.10.0}/wiki/Drive-Items.md +0 -0
  165. {gam7-7.9.7 → gam7-7.10.0}/wiki/Drive-REST-API-v3.md +0 -0
  166. {gam7-7.9.7 → gam7-7.10.0}/wiki/Email-Audit-Monitor.md +0 -0
  167. {gam7-7.9.7 → gam7-7.10.0}/wiki/Find-File-Owner.md +0 -0
  168. {gam7-7.9.7 → gam7-7.10.0}/wiki/GAM-Public-Chat-Room.md +0 -0
  169. {gam7-7.9.7 → gam7-7.10.0}/wiki/GAM-Return-Codes.md +0 -0
  170. {gam7-7.9.7 → gam7-7.10.0}/wiki/GAM-with-minimal-GCP-rights.md +0 -0
  171. {gam7-7.9.7 → gam7-7.10.0}/wiki/GAM7-on-Android-Devices.md +0 -0
  172. {gam7-7.9.7 → gam7-7.10.0}/wiki/GAM7-on-Chrome-OS-Devices.md +0 -0
  173. {gam7-7.9.7 → gam7-7.10.0}/wiki/Google-Data-Transfers.md +0 -0
  174. {gam7-7.9.7 → gam7-7.10.0}/wiki/Google-Network-Addresses.md +0 -0
  175. {gam7-7.9.7 → gam7-7.10.0}/wiki/Groups-Membership.md +0 -0
  176. {gam7-7.9.7 → gam7-7.10.0}/wiki/Groups.md +0 -0
  177. {gam7-7.9.7 → gam7-7.10.0}/wiki/HTTPS-Proxy.md +0 -0
  178. {gam7-7.9.7 → gam7-7.10.0}/wiki/Home.md +0 -0
  179. {gam7-7.9.7 → gam7-7.10.0}/wiki/How-to-Install-GAM7.md +0 -0
  180. {gam7-7.9.7 → gam7-7.10.0}/wiki/How-to-Uninstall-GAM7.md +0 -0
  181. {gam7-7.9.7 → gam7-7.10.0}/wiki/How-to-Update-GAM7.md +0 -0
  182. {gam7-7.9.7 → gam7-7.10.0}/wiki/How-to-Upgrade-GAMADV-XTD3-to-GAM7.md +0 -0
  183. {gam7-7.9.7 → gam7-7.10.0}/wiki/Inbound-SSO.md +0 -0
  184. {gam7-7.9.7 → gam7-7.10.0}/wiki/Install-GAM-as-Python-Library.md +0 -0
  185. {gam7-7.9.7 → gam7-7.10.0}/wiki/List-Items.md +0 -0
  186. {gam7-7.9.7 → gam7-7.10.0}/wiki/List.md +0 -0
  187. {gam7-7.9.7 → gam7-7.10.0}/wiki/Meta-Commands-and-File-Redirection.md +0 -0
  188. {gam7-7.9.7 → gam7-7.10.0}/wiki/Mobile-Devices.md +0 -0
  189. {gam7-7.9.7 → gam7-7.10.0}/wiki/Organizational-Units.md +0 -0
  190. {gam7-7.9.7 → gam7-7.10.0}/wiki/Other-Resources.md +0 -0
  191. {gam7-7.9.7 → gam7-7.10.0}/wiki/Permission-Matches.md +0 -0
  192. {gam7-7.9.7 → gam7-7.10.0}/wiki/Python-Regular-Expressions.md +0 -0
  193. {gam7-7.9.7 → gam7-7.10.0}/wiki/README.md +0 -0
  194. {gam7-7.9.7 → gam7-7.10.0}/wiki/Rclone.md +0 -0
  195. {gam7-7.9.7 → gam7-7.10.0}/wiki/Reports.md +0 -0
  196. {gam7-7.9.7 → gam7-7.10.0}/wiki/Reseller.md +0 -0
  197. {gam7-7.9.7 → gam7-7.10.0}/wiki/Resources.md +0 -0
  198. {gam7-7.9.7 → gam7-7.10.0}/wiki/Running-GAM7-securely-on-a-Google-Compute-Engine.md +0 -0
  199. {gam7-7.9.7 → gam7-7.10.0}/wiki/SSL-Root-CA-Certificates.md +0 -0
  200. {gam7-7.9.7 → gam7-7.10.0}/wiki/Schemas.md +0 -0
  201. {gam7-7.9.7 → gam7-7.10.0}/wiki/Scripts.md +0 -0
  202. {gam7-7.9.7 → gam7-7.10.0}/wiki/Send-Email.md +0 -0
  203. {gam7-7.9.7 → gam7-7.10.0}/wiki/Shared-Drives.md +0 -0
  204. {gam7-7.9.7 → gam7-7.10.0}/wiki/Sites.md +0 -0
  205. {gam7-7.9.7 → gam7-7.10.0}/wiki/Tag-Replace.md +0 -0
  206. {gam7-7.9.7 → gam7-7.10.0}/wiki/Todrive.md +0 -0
  207. {gam7-7.9.7 → gam7-7.10.0}/wiki/Unmanaged-Accounts.md +0 -0
  208. {gam7-7.9.7 → gam7-7.10.0}/wiki/Upgrade-Benefits.md +0 -0
  209. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Analytics-Admin.md +0 -0
  210. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Application-Specific-Passwords.md +0 -0
  211. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Backup-Verification-Codes.md +0 -0
  212. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Calendars-Access.md +0 -0
  213. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Calendars-Events.md +0 -0
  214. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Calendars.md +0 -0
  215. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Classification-Labels.md +0 -0
  216. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Classroom-Profile.md +0 -0
  217. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Contacts-Delegates.md +0 -0
  218. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Contacts.md +0 -0
  219. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Deprovision.md +0 -0
  220. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Activity-Settings.md +0 -0
  221. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Cleanup.md +0 -0
  222. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Comments.md +0 -0
  223. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Copy-Move.md +0 -0
  224. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Files-Manage.md +0 -0
  225. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Orphans.md +0 -0
  226. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Ownership.md +0 -0
  227. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Permissions.md +0 -0
  228. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Query.md +0 -0
  229. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Revisions.md +0 -0
  230. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Shortcuts.md +0 -0
  231. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Drive-Transfer.md +0 -0
  232. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Forms.md +0 -0
  233. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Gmail-CSE.md +0 -0
  234. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Gmail-Delegates.md +0 -0
  235. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Gmail-Filters.md +0 -0
  236. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Gmail-Forwarding.md +0 -0
  237. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Gmail-Labels.md +0 -0
  238. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Gmail-Messages-Threads.md +0 -0
  239. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Gmail-Profile.md +0 -0
  240. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Gmail-S-MIME.md +0 -0
  241. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Gmail-Send-As-Signature-Vacation.md +0 -0
  242. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Gmail-Settings.md +0 -0
  243. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Group-Membership.md +0 -0
  244. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Keep-Notes.md +0 -0
  245. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Looker-Studio.md +0 -0
  246. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Meet.md +0 -0
  247. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-People-Contacts-Profiles.md +0 -0
  248. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Photo.md +0 -0
  249. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Profile-Photo.md +0 -0
  250. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Profile-Sharing.md +0 -0
  251. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Shared-Drives.md +0 -0
  252. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Signout-Turnoff2SV.md +0 -0
  253. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Spreadsheets.md +0 -0
  254. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Tasks.md +0 -0
  255. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-Tokens.md +0 -0
  256. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users-YouTube.md +0 -0
  257. {gam7-7.9.7 → gam7-7.10.0}/wiki/Users.md +0 -0
  258. {gam7-7.9.7 → gam7-7.10.0}/wiki/Using-GAM7-with-a-YubiKey.md +0 -0
  259. {gam7-7.9.7 → gam7-7.10.0}/wiki/Using-GAM7-with-a-delegated-admin-service-account.md +0 -0
  260. {gam7-7.9.7 → gam7-7.10.0}/wiki/Vault-Takeout.md +0 -0
  261. {gam7-7.9.7 → gam7-7.10.0}/wiki/Verifying-a-GAM7-Build-is-Legitimate-and-Official.md +0 -0
  262. {gam7-7.9.7 → gam7-7.10.0}/wiki/_Sidebar.md +0 -0
  263. {gam7-7.9.7 → gam7-7.10.0}/wiki/gam.cfg.md +0 -0
  264. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-AdminSettingsExamples.md +0 -0
  265. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Android-Installation.md +0 -0
  266. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-BulkOperations.md +0 -0
  267. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-CalendarExamples.md +0 -0
  268. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Chat-Bot.md +0 -0
  269. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Chrome-Browser-Management.md +0 -0
  270. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Chrome-OS-Installation.md +0 -0
  271. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Chrome-Policy-Settings.md +0 -0
  272. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Cloud-Identity-Groups.md +0 -0
  273. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Command-Reference-Calendar-Resources.md +0 -0
  274. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Command-Reference-Calendars.md +0 -0
  275. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Command-Reference-Definitions.md +0 -0
  276. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Command-Reference-Drive.md +0 -0
  277. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Command-Reference-Email.md +0 -0
  278. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Command-Reference-Group-Attributes.md +0 -0
  279. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Command-Reference-Groups.md +0 -0
  280. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Command-Reference-Users.md +0 -0
  281. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Context-Aware-Access-Levels.md +0 -0
  282. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Creating-client_secrets.json-and-oauth2service.json.md +0 -0
  283. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-CreatingClientSecretsFile.md +0 -0
  284. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Custom-Schemas.md +0 -0
  285. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Data-Transfers.md +0 -0
  286. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-DomainVerification.md +0 -0
  287. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-ExamplesAccountAuditing.md +0 -0
  288. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-ExamplesCSV.md +0 -0
  289. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-ExamplesEmailSettings.md +0 -0
  290. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-ExamplesOrganizations.md +0 -0
  291. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-GAM-Discussion-Group.md +0 -0
  292. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-GAM-on-Android-and-Chrome-OS.md +0 -0
  293. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-GAM-options-files.md +0 -0
  294. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-GAM-with--minimal-GCP-rights.md +0 -0
  295. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-GAM3CSVListings.md +0 -0
  296. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-GAM3DirectoryCommands.md +0 -0
  297. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-GAM3GroupSettings.md +0 -0
  298. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-GAM7-FAQ.md +0 -0
  299. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Google-Vault---Takeout-Commands.md +0 -0
  300. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-GoogleDriveManagement.md +0 -0
  301. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Grouping-18-or-Older-Users.md +0 -0
  302. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Home.md +0 -0
  303. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-How-to-upgrade-from-Standard-GAM.md +0 -0
  304. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Inbound-SSO-Settings.md +0 -0
  305. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-LicenseExamples.md +0 -0
  306. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Managing-Admins.md +0 -0
  307. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Managing-CloudPrint-Printers.md +0 -0
  308. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Managing-Devices.md +0 -0
  309. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Managing-Google-Classroom.md +0 -0
  310. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-OAuthKeyManagement.md +0 -0
  311. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Printers.md +0 -0
  312. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-ResellerCommands.md +0 -0
  313. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Running-GAM-on-Google-Compute-Engine-(GCE)-Securely.md +0 -0
  314. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-SecurityExamples.md +0 -0
  315. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-UnmanagedUsersExamples.md +0 -0
  316. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Use-a-Yubikey.md +0 -0
  317. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-Using-GAM-with-a-delegated-admin-service-account-(DASA).md +0 -0
  318. {gam7-7.9.7 → gam7-7.10.0}/wiki/l-_Footer.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gam7
3
- Version: 7.9.7
3
+ Version: 7.10.0
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
@@ -1,4 +1,4 @@
1
- This document describes the GAM command line syntax in modified BNF, see https://en.wikipedia.org/wiki/Backus-Naur_Form
1
+ his document describes the GAM command line syntax in modified BNF, see https://en.wikipedia.org/wiki/Backus-Naur_Form
2
2
  Skip the History section and start reading at Introduction.
3
3
 
4
4
  Items on the command line are space separated, when an actual space character is required, it will be indicated by <Space>.
@@ -380,6 +380,8 @@ If an item contains spaces, it should be surrounded by ".
380
380
  domain:<DomainName>|domain|default
381
381
  <CalendarItem> ::= <EmailAddress>
382
382
  <ChannelCustomerID> ::= <String>
383
+ <ChatEmojiName> ::= :<String>:
384
+ <ChatEmoji> ::= emojiname <ChatEmojiName> | customemojis/<String>
383
385
  <ChatMember> ::= spaces/<String>/members/<String>
384
386
  <ChatMessage> ::= spaces/<String>/messages/<String>
385
387
  <ChatSpace> ::= spaces/<String> | space <String> | space spaces/<String>
@@ -664,6 +666,7 @@ If an item contains spaces, it should be surrounded by ".
664
666
  (gdoc|ghtml <UserGoogleDoc>)|
665
667
  (gcsdoc|gcshtml <StorageBucketObjectName>)
666
668
  <YouTubeChannelID> ::= <String>
669
+
667
670
  ## Lists of basic items
668
671
 
669
672
  <APIScopeURLList> ::= "<APIScopeURL>(,<APIScopeURL>)*"
@@ -6436,6 +6439,22 @@ gam <UserTypeEntity> print chatevents [todrive <ToDriveAttribute>*]
6436
6439
  filter <String>
6437
6440
  [formatjson [quotechar <Character>]]
6438
6441
 
6442
+ <ChatEmojiName> ::= :[0-9a-z_-]+:
6443
+ <ChatEmoji> ::= emojiname <ChatEmojiName> | customemojis/<String>
6444
+
6445
+ gam <UserTypeEntity> create chatemoji <ChatEmojiName>
6446
+ ([drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>])
6447
+ [formatjson]
6448
+ gam <UserTypeEntity> delete chatemoji <ChatEmoji>
6449
+ gam <UserTypeEntity> info chatemoji <ChatEmoji>
6450
+ [formatjson]
6451
+ gam <UserTypeEntity> show chatemojis
6452
+ [showcreatedby any|me|others]
6453
+ [formatjson]
6454
+ gam <UserTypeEntity> print chatemojis [todrive <ToDriveAttribute>*]
6455
+ [showcreatedby any|me|others]
6456
+ [formatjson [quotechar <Character>]]
6457
+
6439
6458
  # Users - Drive
6440
6459
 
6441
6460
  <DriveFileOrderByFieldName> ::=
@@ -1,3 +1,13 @@
1
+ 7.10.00
2
+
3
+ Added commands to manage/display Chat Custom Emojis.
4
+
5
+ * See: https://github.com/GAM-team/GAM/wiki/Users-Chat#manage-chat-emojis
6
+ * See: https://github.com/GAM-team/GAM/wiki/Users-Chat#display-chat-emojis
7
+
8
+ Updated `gam <UserItem> print|show chatspaces|chatmembers asadmin` to display
9
+ the spaces in ascending display name order.
10
+
1
11
  7.09.07
2
12
 
3
13
  Added `webviewlink` to `<FileTreeFieldName>` for use in `gam <UserTypeEntity> print|show filetree`.
@@ -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.09.07'
28
+ __version__ = '7.10.00'
29
29
  __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
30
30
 
31
31
  #pylint: disable=wrong-import-position
@@ -22786,7 +22786,7 @@ def _processPeopleContactPhotos(users, function):
22786
22786
  if function == 'GetContactPhoto' and not os.path.isdir(targetFolder):
22787
22787
  os.makedirs(targetFolder)
22788
22788
  elif myarg == 'filename':
22789
- filenamePattern = getString(Cmd.OB_PHOTO_FILENAME_PATTERN)
22789
+ filenamePattern = getString(Cmd.OB_FILE_NAME_PATTERN)
22790
22790
  else:
22791
22791
  unknownArgumentExit()
22792
22792
  subForContactId = filenamePattern.find('#contactid#') != -1
@@ -25990,6 +25990,8 @@ def _printChatItem(user, citem, parent, entityType, csvPF, FJQC, addCSVData=None
25990
25990
  if entityType == Ent.CHAT_SPACE:
25991
25991
  _cleanChatSpace(citem)
25992
25992
  baserow = {'User': user} if user is not None else {}
25993
+ elif entityType == Ent.CHAT_EMOJI:
25994
+ baserow = {'User': user, 'name': citem['name'], 'emojiName': citem['emojiName']}
25993
25995
  else:
25994
25996
  if user is not None:
25995
25997
  baserow = {'User': user, 'space.name': parent['name'], 'space.displayName': parent['displayName']}
@@ -26009,6 +26011,190 @@ def _printChatItem(user, citem, parent, entityType, csvPF, FJQC, addCSVData=None
26009
26011
  'JSON': json.dumps(cleanJSON(citem, timeObjects=CHAT_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)})
26010
26012
  csvPF.WriteRowNoFilter(row)
26011
26013
 
26014
+ def _getValidateEmojiName():
26015
+ name = getString(Cmd.OB_CHAT_EMOJI_NAME)
26016
+ if re.match(r'^:[0-9a-z_-]+:$', name):
26017
+ return name
26018
+ Cmd.Backup()
26019
+ usageErrorExit(Msg.INVALID_EMOJI_NAME.format(name))
26020
+
26021
+ # gam <UserTypeEntity> create chatemoji <ChatEmojiName>
26022
+ # ([drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>])
26023
+ # [formatjson]
26024
+ def createChatEmoji(users):
26025
+ FJQC = FormatJSONQuoteChar()
26026
+ name = _getValidateEmojiName()
26027
+ body = {'emojiName': name, 'payload': {'filename': '', 'fileContent': ''}}
26028
+ sourceFolder = os.getcwd()
26029
+ filenamePattern = '#email#.jpg'
26030
+ while Cmd.ArgumentsRemaining():
26031
+ myarg = getArgument()
26032
+ if myarg == 'drivedir':
26033
+ sourceFolder = GC.Values[GC.DRIVE_DIR]
26034
+ elif myarg == 'sourcefolder':
26035
+ sourceFolder = os.path.expanduser(getString(Cmd.OB_FILE_PATH))
26036
+ if not os.path.isdir(sourceFolder):
26037
+ entityDoesNotExistExit(Ent.DIRECTORY, sourceFolder)
26038
+ elif myarg == 'filename':
26039
+ filenamePattern = getString(Cmd.OB_FILE_NAME_PATTERN)
26040
+ else:
26041
+ FJQC.GetFormatJSON(myarg)
26042
+ i, count, users = getEntityArgument(users)
26043
+ for user in users:
26044
+ i += 1
26045
+ user, chat, kvList = buildChatServiceObject(API.CHAT_CUSTOM_EMOJIS, user, i, count, [Ent.CHAT_EMOJI, name])
26046
+ if not chat:
26047
+ continue
26048
+ user, userName, _ = splitEmailAddressOrUID(user)
26049
+ filename = _substituteForUser(filenamePattern, user, userName)
26050
+ if sourceFolder is not None:
26051
+ filename = os.path.join(sourceFolder, filename)
26052
+ filename = os.path.expanduser(filename)
26053
+ try:
26054
+ with open(filename, 'rb') as f:
26055
+ image_data = f.read()
26056
+ except (OSError, IOError) as e:
26057
+ entityActionFailedWarning([Ent.USER, user, Ent.CHAT_EMOJI, filename], str(e), i, count)
26058
+ continue
26059
+ body['payload'] = {'filename': os.path.basename(filename),
26060
+ 'fileContent':base64.urlsafe_b64encode(image_data).decode(UTF8)}
26061
+ try:
26062
+ emoji = callGAPI(chat.customEmojis(), 'create',
26063
+ throwReasons=[GAPI.ALREADY_EXISTS, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
26064
+ body=body)
26065
+ _showChatItem(emoji, Ent.CHAT_EMOJI, FJQC, i, count)
26066
+ except (GAPI.alreadyExists, GAPI.invalidArgument, GAPI.permissionDenied) as e:
26067
+ exitIfChatNotConfigured(chat, kvList, str(e), i, count)
26068
+ except GAPI.failedPrecondition:
26069
+ userChatServiceNotEnabledWarning(user, i, count)
26070
+
26071
+ def getEmojiName(myarg):
26072
+ if myarg == 'emojiname':
26073
+ name = _getValidateEmojiName()
26074
+ return 'customEmojis/'+name
26075
+ _, chatEmoji = Cmd.Previous().split('/', 1)
26076
+ return 'customEmojis/'+chatEmoji
26077
+
26078
+ # gam <UserTypeEntity> delete chatemoji <ChatEmoji>
26079
+ def deleteChatEmoji(users):
26080
+ name = None
26081
+ while Cmd.ArgumentsRemaining():
26082
+ myarg = getArgument()
26083
+ if myarg == 'emojiname':
26084
+ name = getEmojiName(myarg)
26085
+ elif myarg.startswith('customemojis/'):
26086
+ name = getEmojiName(myarg)
26087
+ else:
26088
+ unknownArgumentExit()
26089
+ if not name:
26090
+ missingArgumentExit('ChatEmoji')
26091
+ i, count, users = getEntityArgument(users)
26092
+ for user in users:
26093
+ i += 1
26094
+ user, chat, kvList = buildChatServiceObject(API.CHAT_CUSTOM_EMOJIS, user, i, count, [Ent.CHAT_EMOJI, name])
26095
+ if not chat:
26096
+ continue
26097
+ try:
26098
+ callGAPI(chat.customEmojis(), 'delete',
26099
+ throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
26100
+ name=name)
26101
+ entityActionPerformed(kvList, i, count)
26102
+ except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
26103
+ exitIfChatNotConfigured(chat, kvList, str(e), i, count)
26104
+ except GAPI.failedPrecondition:
26105
+ userChatServiceNotEnabledWarning(user, i, count)
26106
+
26107
+ # gam <UserTypeEntity> info chatemoji <ChatEmoji>
26108
+ # [formatjson]
26109
+ def infoChatEmoji(users):
26110
+ FJQC = FormatJSONQuoteChar()
26111
+ name = None
26112
+ while Cmd.ArgumentsRemaining():
26113
+ myarg = getArgument()
26114
+ if myarg == 'emojiname':
26115
+ name = getEmojiName(myarg)
26116
+ elif myarg.startswith('customemojis/'):
26117
+ name = getEmojiName(myarg)
26118
+ else:
26119
+ FJQC.GetFormatJSON(myarg)
26120
+ if not name:
26121
+ missingArgumentExit('ChatEmoji')
26122
+ i, count, users = getEntityArgument(users)
26123
+ for user in users:
26124
+ i += 1
26125
+ user, chat, kvList = buildChatServiceObject(API.CHAT_CUSTOM_EMOJIS, user, i, count, [Ent.CHAT_EMOJI, name])
26126
+ if not chat:
26127
+ continue
26128
+ try:
26129
+ emoji = callGAPI(chat.customEmojis(), 'get',
26130
+ throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
26131
+ name=name)
26132
+ if not FJQC.formatJSON:
26133
+ entityPerformAction(kvList, i, count)
26134
+ _showChatItem(emoji, Ent.CHAT_EMOJI, FJQC, i, count)
26135
+ except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
26136
+ exitIfChatNotConfigured(chat, kvList, str(e), i, count)
26137
+ except GAPI.failedPrecondition:
26138
+ userChatServiceNotEnabledWarning(user, i, count)
26139
+
26140
+ CHAT_EMOJI_SHOW_CREATED_BY_CHOICE_MAP = {
26141
+ 'any': None,
26142
+ 'me': 'creator("users/me")',
26143
+ 'others': 'NOT creator("users/me")'
26144
+ }
26145
+
26146
+ # gam <UserTypeEntity> show chatemojis
26147
+ # [showcreatedby any|me|others]
26148
+ # [formatjson]
26149
+ # gam <UserTypeEntity> print chatemojis [todrive <ToDriveAttribute>*]
26150
+ # [showcreatedby any|me|others]
26151
+ # [formatjson [quotechar <Character>]]
26152
+ def printShowChatEmojis(users):
26153
+ csvPF = CSVPrintFile(['User', 'name', 'emojiName']) if Act.csvFormat() else None
26154
+ FJQC = FormatJSONQuoteChar(csvPF)
26155
+ pfilter = CHAT_EMOJI_SHOW_CREATED_BY_CHOICE_MAP['me']
26156
+ while Cmd.ArgumentsRemaining():
26157
+ myarg = getArgument()
26158
+ if csvPF and myarg == 'todrive':
26159
+ csvPF.GetTodriveParameters()
26160
+ elif myarg =='showcreatedby':
26161
+ pfilter = getChoice(CHAT_EMOJI_SHOW_CREATED_BY_CHOICE_MAP, mapChoice=True)
26162
+ else:
26163
+ FJQC.GetFormatJSONQuoteChar(myarg, True)
26164
+ i, count, users = getEntityArgument(users)
26165
+ for user in users:
26166
+ i += 1
26167
+ user, chat, kvList = buildChatServiceObject(API.CHAT_CUSTOM_EMOJIS, user, i, count, [Ent.CHAT_EMOJI, None])
26168
+ if not chat:
26169
+ continue
26170
+ try:
26171
+ emojis = callGAPIpages(chat.customEmojis(), 'list', 'customEmojis',
26172
+ pageMessage=_getChatPageMessage(Ent.CHAT_EMOJI, user, i, count, pfilter),
26173
+ throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
26174
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
26175
+ pageSize=CHAT_PAGE_SIZE, filter=pfilter)
26176
+ except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
26177
+ exitIfChatNotConfigured(chat, kvList, str(e), i, count)
26178
+ continue
26179
+ except GAPI.failedPrecondition:
26180
+ userChatServiceNotEnabledWarning(user, i, count)
26181
+ break
26182
+ if not csvPF:
26183
+ jcount = len(emojis)
26184
+ if not FJQC.formatJSON:
26185
+ entityPerformActionNumItems(kvList, jcount, Ent.CHAT_EMOJI, i, count)
26186
+ Ind.Increment()
26187
+ j = 0
26188
+ for emoji in sorted(emojis, key=lambda k: k['emojiName']):
26189
+ j += 1
26190
+ _showChatItem(emoji, Ent.CHAT_EMOJI, FJQC, j, jcount)
26191
+ Ind.Decrement()
26192
+ else:
26193
+ for emoji in sorted(emojis, key=lambda k: k['emojiName']):
26194
+ _printChatItem(user, emoji, '', Ent.CHAT_EMOJI, csvPF, FJQC)
26195
+ if csvPF:
26196
+ csvPF.writeCSVfile('Chat Custom Emojis')
26197
+
26012
26198
  # gam setup chat
26013
26199
  def doSetupChat():
26014
26200
  checkForExtraneousArguments()
@@ -26472,6 +26658,9 @@ def printShowChatSpaces(users):
26472
26658
  substituteQueryTimes(queries, queryTimes)
26473
26659
  pfilter = kwargsCS['query'] = queries[0]
26474
26660
  kwargsCS['useAdminAccess'] = True
26661
+ sortName = 'displayName'
26662
+ else:
26663
+ sortName = 'name'
26475
26664
  for user in users:
26476
26665
  i += 1
26477
26666
  user, chat, kvList = buildChatServiceObject(api, user, i, count, None, useAdminAccess)
@@ -26499,12 +26688,12 @@ def printShowChatSpaces(users):
26499
26688
  entityPerformActionNumItems(kvList, jcount, Ent.CHAT_SPACE, i, count)
26500
26689
  Ind.Increment()
26501
26690
  j = 0
26502
- for space in spaces:
26691
+ for space in sorted(spaces, key=lambda k: k[sortName]):
26503
26692
  j += 1
26504
26693
  _showChatItem(space, Ent.CHAT_SPACE, FJQC, j, jcount)
26505
26694
  Ind.Decrement()
26506
26695
  else:
26507
- for space in spaces:
26696
+ for space in sorted(spaces, key=lambda k: k[sortName]):
26508
26697
  _printChatItem(user, space, None, Ent.CHAT_SPACE, csvPF, FJQC)
26509
26698
  if csvPF:
26510
26699
  csvPF.writeCSVfile('Chat Spaces')
@@ -27139,6 +27328,9 @@ def printShowChatMembers(users):
27139
27328
  i, count, users = getEntityArgument(users)
27140
27329
  if useAdminAccess:
27141
27330
  _chkChatAdminAccess(count)
27331
+ sortName = 'displayName'
27332
+ else:
27333
+ sortName = 'name'
27142
27334
  for user in users:
27143
27335
  i += 1
27144
27336
  user, chat, kvList = buildChatServiceObject(api, user, i, count, [Ent.CHAT_SPACE, None], useAdminAccess)
@@ -27161,7 +27353,7 @@ def printShowChatMembers(users):
27161
27353
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
27162
27354
  fields="nextPageToken,spaces(name,displayName,spaceType,membershipCount)", pageSize=CHAT_PAGE_SIZE,
27163
27355
  **kwargsCS)
27164
- for space in spaces:
27356
+ for space in sorted(spaces, key=lambda k: k[sortName]):
27165
27357
  if space['spaceType'] == 'SPACE' and 'membershipCount' in space:
27166
27358
  parentList.append({'name': space['name'], 'displayName': space.get('displayName', 'None')})
27167
27359
  except (GAPI.notFound, GAPI.invalidArgument, GAPI.internalError,
@@ -27178,7 +27370,7 @@ def printShowChatMembers(users):
27178
27370
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
27179
27371
  fields="nextPageToken,spaces(name,displayName,spaceType,membershipCount)", pageSize=CHAT_PAGE_SIZE,
27180
27372
  **kwargsCS)
27181
- for space in spaces:
27373
+ for space in sorted(spaces, key=lambda k: k[sortName]):
27182
27374
  # if 'membershipCount' in space:
27183
27375
  # parentList.append({'name': space['name'], 'displayName': space.get('displayName', 'None')})
27184
27376
  parentList.append({'name': space['name'], 'displayName': space.get('displayName', 'None')})
@@ -67871,7 +68063,7 @@ def updatePhoto(users):
67871
68063
  baseFileIdEntity = drive = owner = None
67872
68064
  sourceFolder = os.getcwd()
67873
68065
  if Cmd.NumArgumentsRemaining() == 1:
67874
- filenamePattern = getString(Cmd.OB_PHOTO_FILENAME_PATTERN)
68066
+ filenamePattern = getString(Cmd.OB_FILE_NAME_PATTERN)
67875
68067
  else:
67876
68068
  filenamePattern = '#email#.jpg'
67877
68069
  while Cmd.ArgumentsRemaining():
@@ -67883,7 +68075,7 @@ def updatePhoto(users):
67883
68075
  if not os.path.isdir(sourceFolder):
67884
68076
  entityDoesNotExistExit(Ent.DIRECTORY, sourceFolder)
67885
68077
  elif myarg == 'filename':
67886
- filenamePattern = getString(Cmd.OB_PHOTO_FILENAME_PATTERN)
68078
+ filenamePattern = getString(Cmd.OB_FILE_NAME_PATTERN)
67887
68079
  elif myarg == 'gphoto':
67888
68080
  owner, drive = buildGAPIServiceObject(API.DRIVE3, getEmailAddress())
67889
68081
  if not drive:
@@ -67984,7 +68176,7 @@ def getPhoto(users, profileMode):
67984
68176
  if not os.path.isdir(targetFolder):
67985
68177
  os.makedirs(targetFolder)
67986
68178
  elif myarg == 'filename':
67987
- filenamePattern = getString(Cmd.OB_PHOTO_FILENAME_PATTERN)
68179
+ filenamePattern = getString(Cmd.OB_FILE_NAME_PATTERN)
67988
68180
  elif myarg == 'nofile':
67989
68181
  writeFileData = False
67990
68182
  elif myarg == 'noshow':
@@ -76983,6 +77175,7 @@ USER_ADD_CREATE_FUNCTIONS = {
76983
77175
  Cmd.ARG_CALENDAR: addCreateCalendars,
76984
77176
  Cmd.ARG_GROUP: addUserToGroups,
76985
77177
  Cmd.ARG_CALENDARACL: createCalendarACLs,
77178
+ Cmd.ARG_CHATEMOJI: createChatEmoji,
76986
77179
  Cmd.ARG_CHATMEMBER: createChatMember,
76987
77180
  Cmd.ARG_CHATMESSAGE: createChatMessage,
76988
77181
  Cmd.ARG_CHATSPACE: createChatSpace,
@@ -77099,6 +77292,7 @@ USER_COMMANDS_WITH_OBJECTS = {
77099
77292
  Cmd.ARG_BACKUPCODE: deleteBackupCodes,
77100
77293
  Cmd.ARG_CALENDAR: deleteCalendars,
77101
77294
  Cmd.ARG_CALENDARACL: deleteCalendarACLs,
77295
+ Cmd.ARG_CHATEMOJI: deleteChatEmoji,
77102
77296
  Cmd.ARG_CHATMEMBER: deleteUpdateChatMember,
77103
77297
  Cmd.ARG_CHATMESSAGE: deleteChatMessage,
77104
77298
  Cmd.ARG_CHATSPACE: deleteChatSpace,
@@ -77203,6 +77397,7 @@ USER_COMMANDS_WITH_OBJECTS = {
77203
77397
  (Act.INFO,
77204
77398
  {Cmd.ARG_CALENDAR: infoCalendars,
77205
77399
  Cmd.ARG_CALENDARACL: infoCalendarACLs,
77400
+ Cmd.ARG_CHATEMOJI: infoChatEmoji,
77206
77401
  Cmd.ARG_CHATEVENT: infoChatEvent,
77207
77402
  Cmd.ARG_CHATMEMBER: infoChatMember,
77208
77403
  Cmd.ARG_CHATMESSAGE: infoChatMessage,
@@ -77275,6 +77470,7 @@ USER_COMMANDS_WITH_OBJECTS = {
77275
77470
  Cmd.ARG_CALENDAR: printShowCalendars,
77276
77471
  Cmd.ARG_CALENDARACL: printShowCalendarACLs,
77277
77472
  Cmd.ARG_CALSETTINGS: printShowCalSettings,
77473
+ Cmd.ARG_CHATEMOJI: printShowChatEmojis,
77278
77474
  Cmd.ARG_CHATEVENT: printShowChatEvents,
77279
77475
  Cmd.ARG_CHATMEMBER: printShowChatMembers,
77280
77476
  Cmd.ARG_CHATMESSAGE: printShowChatMessages,
@@ -77382,6 +77578,7 @@ USER_COMMANDS_WITH_OBJECTS = {
77382
77578
  Cmd.ARG_CALENDAR: printShowCalendars,
77383
77579
  Cmd.ARG_CALENDARACL: printShowCalendarACLs,
77384
77580
  Cmd.ARG_CALSETTINGS: printShowCalSettings,
77581
+ Cmd.ARG_CHATEMOJI: printShowChatEmojis,
77385
77582
  Cmd.ARG_CHATEVENT: printShowChatEvents,
77386
77583
  Cmd.ARG_CHATMEMBER: printShowChatMembers,
77387
77584
  Cmd.ARG_CHATMESSAGE: printShowChatMessages,
@@ -77598,6 +77795,7 @@ USER_COMMANDS_OBJ_ALIASES = {
77598
77795
  Cmd.ARG_CLASSIFICATIONLABELPERMISSION: Cmd.ARG_DRIVELABELPERMISSION,
77599
77796
  Cmd.ARG_CLASSIFICATIONLABELPERMISSIONS: Cmd.ARG_DRIVELABELPERMISSION,
77600
77797
  Cmd.ARG_CLASSROOMINVITATIONS: Cmd.ARG_CLASSROOMINVITATION,
77798
+ Cmd.ARG_CHATEMOJIS: Cmd.ARG_CHATEMOJI,
77601
77799
  Cmd.ARG_CHATEVENTS: Cmd.ARG_CHATEVENT,
77602
77800
  Cmd.ARG_CHATMEMBERS: Cmd.ARG_CHATMEMBER,
77603
77801
  Cmd.ARG_CHATMESSAGES: Cmd.ARG_CHATMESSAGE,
@@ -26,6 +26,7 @@ ANALYTICS_ADMIN = 'analyticsadmin'
26
26
  CALENDAR = 'calendar'
27
27
  CBCM = 'cbcm'
28
28
  CHAT = 'chat'
29
+ CHAT_CUSTOM_EMOJIS = 'chatcustomemojis'
29
30
  CHAT_EVENTS = 'chatevents'
30
31
  CHAT_MEMBERSHIPS = 'chatmemberships'
31
32
  CHAT_MEMBERSHIPS_ADMIN = 'chatmembershipsadmin'
@@ -210,6 +211,7 @@ _INFO = {
210
211
  CALENDAR: {'name': 'Calendar API', 'version': 'v3', 'v2discovery': True, 'mappedAPI': 'calendar-json'},
211
212
  CBCM: {'name': 'Chrome Browser Cloud Management API', 'version': 'v1.1beta1', 'v2discovery': True, 'localjson': True},
212
213
  CHAT: {'name': 'Chat API', 'version': 'v1', 'v2discovery': True},
214
+ CHAT_CUSTOM_EMOJIS: {'name': 'Chat API - Custom Emojis', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
213
215
  CHAT_EVENTS: {'name': 'Chat API - Events', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
214
216
  CHAT_MEMBERSHIPS: {'name': 'Chat API - Memberships', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
215
217
  CHAT_MEMBERSHIPS_ADMIN: {'name': 'Chat API - Memberships Admin', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
@@ -544,6 +546,10 @@ _SVCACCT_SCOPES = [
544
546
  'api': CALENDAR,
545
547
  'subscopes': READONLY,
546
548
  'scope': 'https://www.googleapis.com/auth/calendar'},
549
+ {'name': 'Chat API - Custom Emojis',
550
+ 'api': CHAT_CUSTOM_EMOJIS,
551
+ 'subscopes': READONLY,
552
+ 'scope': 'https://www.googleapis.com/auth/chat.customemojis'},
547
553
  {'name': 'Chat API - Memberships',
548
554
  'api': CHAT_MEMBERSHIPS,
549
555
  'subscopes': READONLY,
@@ -461,6 +461,8 @@ class GamCLArgs():
461
461
  ARG_CHANNELSKU = 'channelsku'
462
462
  ARG_CHANNELSKUS = 'channelskus'
463
463
  ARG_CHAT = 'chat'
464
+ ARG_CHATEMOJI = 'chatemoji'
465
+ ARG_CHATEMOJIS = 'chatemojis'
464
466
  ARG_CHATEVENT = 'chatevent'
465
467
  ARG_CHATEVENTS = 'chatevents'
466
468
  ARG_CHATMEMBER = 'chatmember'
@@ -843,6 +845,8 @@ class GamCLArgs():
843
845
  OB_CHARACTER = 'Character'
844
846
  OB_CHAR_SET = 'CharacterSet'
845
847
  OG_CHAT_ATTACHMENT = 'ChatAttachment'
848
+ OB_CHAT_EMOJI = 'ChatEmoji'
849
+ OB_CHAT_EMOJI_NAME = 'ChatEmojiName'
846
850
  OB_CHAT_EVENT = 'ChatEvent'
847
851
  OB_CHAT_MEMBER = 'ChatMember'
848
852
  OB_CHAT_MESSAGE = 'ChatMessage'
@@ -930,6 +934,7 @@ class GamCLArgs():
930
934
  OB_FILE_NAME = 'FileName'
931
935
  OB_FILE_NAME_FIELD_NAME = OB_FILE_NAME+'(:'+OB_FIELD_NAME+')+'
932
936
  OB_FILE_NAME_OR_URL = 'FileName|URL'
937
+ OB_FILE_NAME_PATTERN = 'FileNamePattern'
933
938
  OB_FILE_PATH = 'FilePath'
934
939
  OB_FILTER_ID_ENTITY = 'FilterIDEntity'
935
940
  OB_FORMAT_LIST = 'FormatList'
@@ -975,7 +980,6 @@ class GamCLArgs():
975
980
  OB_PERMISSION_ID_LIST = 'PermissionIDList'
976
981
  OB_PERMISSION_ROLE_LIST = 'PermissionRoleList'
977
982
  OB_PERMISSION_TYPE_LIST = 'PermissionTypeList'
978
- OB_PHOTO_FILENAME_PATTERN = 'FilenameNamePattern'
979
983
  OB_PRINTER_ID = 'PrinterID'
980
984
  OB_PRIVILEGE_LIST = 'PrivilegeList'
981
985
  OB_PRODUCT_ID = 'ProductID'
@@ -86,6 +86,7 @@ class GamEntity():
86
86
  CHANNEL_SKU = 'chsk'
87
87
  CHAT_BOT = 'chbo'
88
88
  CHAT_ADMIN = 'chad'
89
+ CHAT_EMOJI = 'chem'
89
90
  CHAT_EVENT = 'chev'
90
91
  CHAT_MANAGER_USER = 'chgu'
91
92
  CHAT_MEMBER = 'chme'
@@ -436,6 +437,7 @@ class GamEntity():
436
437
  CHANNEL_SKU: ['Channel SKUs', 'Channel SKU'],
437
438
  CHAT_BOT: ['Chat BOTs', 'Chat BOT'],
438
439
  CHAT_ADMIN: ['Chat Admins', 'Chat Admin'],
440
+ CHAT_EMOJI: ['Chat Emojis', 'Chat Emoji'],
439
441
  CHAT_EVENT: ['Chat Events', 'Chat Event'],
440
442
  CHAT_MANAGER_USER: ['Chat User Managers', 'Chat User Manager'],
441
443
  CHAT_MESSAGE: ['Chat Messages', 'Chat Message'],
@@ -309,6 +309,7 @@ INVALID_ALIAS = 'Invalid Alias'
309
309
  INVALID_ATTENDEE_CHANGE = 'Invalid attendee change "{0}"'
310
310
  INVALID_CHARSET = 'Invalid charset "{0}"'
311
311
  INVALID_DATE_TIME_RANGE = '{0} {1} must be greater than/equal to {2} {3}'
312
+ INVALID_EMOJI_NAME = '{0} does not match pattern :[0-9a-z_-]:'
312
313
  INVALID_ENTITY = 'Invalid {0}, {1}'
313
314
  INVALID_EVENT_TIMERANGE = '{0} {1} must be less than {2}'
314
315
  INVALID_FILE_SELECTION_WITH_ADMIN_ACCESS = 'Invalid file selection with adminaccess|asadmin'
@@ -96,7 +96,7 @@
96
96
  banana|basil|blueberry|flamingo|graphite|grape|
97
97
  lavender|peacock|sage|tangerine|tomato
98
98
  <FileFormat> ::=
99
- csv|doc|dot|docx|dotx|epub|html|jpeg|jpg|mht|odp|ods|odt|
99
+ csv|doc|dot|docx|dotx|epub|html|jpeg|jpg|json|mht|odp|ods|odt|
100
100
  pdf|png|ppt|pot|potx|pptx|rtf|svg|tsv|txt|xls|xlt|xlsx|xltx|zip|
101
101
  ms|microsoft|openoffice|
102
102
  <LabelColorHex> ::=
@@ -278,6 +278,8 @@
278
278
  domain:<DomainName>|domain|default
279
279
  <CalendarItem> ::= <EmailAddress>
280
280
  <ChannelCustomerID> ::= <String>
281
+ <ChatEmojiName> ::= :[0-9a-z_-]+:
282
+ <ChatEmoji> ::= emojiname <ChatEmojiName> | customemojis/<String>
281
283
  <ChatMember> ::= spaces/<String>/members/<String>
282
284
  <ChatMessage> ::= spaces/<String>/messages/<String>
283
285
  <ChatSpace> ::= spaces/<String> | space <String> | space spaces/<String>
@@ -10,6 +10,20 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
10
10
 
11
11
  See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
12
12
 
13
+ ### 7.10.00
14
+
15
+ Added commands to manage/display Chat Custom Emojis.
16
+
17
+ * See: https://github.com/GAM-team/GAM/wiki/Users-Chat#manage-chat-emojis
18
+ * See: https://github.com/GAM-team/GAM/wiki/Users-Chat#display-chat-emojis
19
+
20
+ Updated `gam <UserItem> print|show chatspaces|chatmembers asadmin` to display
21
+ the spaces in ascending display name order.
22
+
23
+ ### 7.09.07
24
+
25
+ Added `webviewlink` to `<FileTreeFieldName>` for use in `gam <UserTypeEntity> print|show filetree`.
26
+
13
27
  ### 7.09.06
14
28
 
15
29
  Upddated `gam print|show shareddrives`, `gam print|show shareddriveacls`, `gam print shareddriveorganizers`
@@ -251,7 +251,7 @@ writes the credentials into the file oauth2.txt.
251
251
  admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt
252
252
  admin@server:/Users/admin$ gam version
253
253
  WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
254
- GAM 7.09.06 - https://github.com/GAM-team/GAM - pyinstaller
254
+ GAM 7.10.00 - https://github.com/GAM-team/GAM - pyinstaller
255
255
  GAM Team <google-apps-manager@googlegroups.com>
256
256
  Python 3.13.5 64-bit final
257
257
  MacOS Sequoia 15.5 x86_64
@@ -989,7 +989,7 @@ writes the credentials into the file oauth2.txt.
989
989
  C:\>del C:\GAMConfig\oauth2.txt
990
990
  C:\>gam version
991
991
  WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
992
- GAM 7.09.06 - https://github.com/GAM-team/GAM - pythonsource
992
+ GAM 7.10.00 - https://github.com/GAM-team/GAM - pythonsource
993
993
  GAM Team <google-apps-manager@googlegroups.com>
994
994
  Python 3.13.5 64-bit final
995
995
  Windows-10-10.0.17134 AMD64
@@ -11,7 +11,7 @@
11
11
  - [Synchronize licenses](#synchronize-licenses)
12
12
 
13
13
  ## API documentation
14
- * [License Manager API](https://developers.google.com/admin-sdk/licensing/rest/v1/licenseAssignments)
14
+ * [License Manager API](https://developers.google.com/workspace/admin/licensing/reference/rest/v1/licenseAssignments)
15
15
 
16
16
  ## License Products and SKUs
17
17
  * [Product and SKU IDs](https://developers.google.com/admin-sdk/licensing/v1/how-tos/products)