mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-17 04:31:37 +00:00
Compare commits
3 Commits
20241105.2
...
20241114.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8f10dc72a | ||
|
|
98ef879a34 | ||
|
|
95b3a97925 |
25
.github/workflows/build.yml
vendored
25
.github/workflows/build.yml
vendored
@@ -68,31 +68,36 @@ jobs:
|
||||
goal: build
|
||||
arch: aarch64
|
||||
openssl_archs: darwin64-arm64
|
||||
- os: windows-2022
|
||||
- os: macos-15
|
||||
jid: 8
|
||||
goal: build
|
||||
arch: aarch64
|
||||
openssl_archs: darwin64-arm64
|
||||
- os: windows-2022
|
||||
jid: 9
|
||||
goal: build
|
||||
arch: Win64
|
||||
openssl_archs: VC-WIN64A
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.9"
|
||||
jid: 9
|
||||
arch: x86_64
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.10"
|
||||
jid: 10
|
||||
arch: x86_64
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.11"
|
||||
python: "3.10"
|
||||
jid: 11
|
||||
arch: x86_64
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.12"
|
||||
python: "3.11"
|
||||
jid: 12
|
||||
arch: x86_64
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.12"
|
||||
jid: 13
|
||||
arch: x86_64
|
||||
|
||||
steps:
|
||||
|
||||
@@ -115,7 +120,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
cache.tar.xz
|
||||
key: gam-${{ matrix.jid }}-20241022
|
||||
key: gam-${{ matrix.jid }}-20241114
|
||||
|
||||
- name: Untar Cache archive
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
|
||||
@@ -677,7 +682,7 @@ jobs:
|
||||
if: runner.os != 'Windows' && matrix.goal == 'build'
|
||||
run: |
|
||||
if [[ "${RUNNER_OS}" == "macOS" ]]; then
|
||||
GAM_ARCHIVE="${GITHUB_WORKSPACE}/gam-${GAMVERSION}-macos-${arch}.tar.xz"
|
||||
GAM_ARCHIVE="${GITHUB_WORKSPACE}/gam-${GAMVERSION}-macos${MACOSX_DEPLOYMENT_TARGET}-${arch}.tar.xz"
|
||||
elif [[ "${RUNNER_OS}" == "Linux" ]]; then
|
||||
if [[ "${staticx}" == "yes" ]]; then
|
||||
libver="legacy"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Cloud Identity Policies
|
||||
- [API documentation](#api-documentation)
|
||||
- [Notes](#notes)
|
||||
- [Python Regular Expressions](Python-Regular-Expressions) Match function
|
||||
- [Definitions](#definitions)
|
||||
- [Policies](#policies)
|
||||
- [Display Cloud Identity Policies](#display-cloud-identity-policies)
|
||||
@@ -322,8 +323,8 @@ gam info policies <CIPolicyEntity>
|
||||
|
||||
Select policies::
|
||||
* `polices/<String>` - A policy name, `policies/ahv4hg7qc24kvaghb7zihwf4riid4`
|
||||
* `settings/<String>` - A policy setting type, `settings/workspace_marketplace.apps_allowlist'
|
||||
* `<String>` - A policy setting type, `workspace_marketplace.apps_allowlist'
|
||||
* `settings/<String>` - A policy setting type, `settings/workspace_marketplace.apps_allowlist`
|
||||
* `<String>` - A policy setting type, `workspace_marketplace.apps_allowlist`
|
||||
|
||||
By default, policy warnings are displayed, use the 'nowarnings` option to suppress their display.
|
||||
|
||||
@@ -337,10 +338,13 @@ Display all or filtered policies.
|
||||
```
|
||||
gam show policies
|
||||
[filter <String>] [nowarnings] [noappnames]
|
||||
[group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
|
||||
[formatjson]
|
||||
```
|
||||
By default, all policies are displayed.
|
||||
* `filter <String>` - Display filtered policies, See https://cloud.google.com/identity/docs/reference/rest/v1beta1/policies/list
|
||||
* `group <RegularExpression>` - Only display policies whose group email address matches the `<RegularExpression>`
|
||||
* `ou|org|orgunit <RegularExpression> - Only display policies whose OU path matches the `<RegularExpression>`
|
||||
|
||||
By default, policy warnings are displayed, use the 'nowarnings` option to suppress their display.
|
||||
|
||||
@@ -353,10 +357,13 @@ By default, Gam displays the information as an indented list of keys and values.
|
||||
```
|
||||
gam print policies [todrive <ToDriveAttribute>*]
|
||||
[filter <String>] [nowarnings] [noappnames]
|
||||
[group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, all policies are displayed:
|
||||
* `filter <String>` - Display filtered policies, See https://cloud.google.com/identity/docs/reference/rest/v1beta1/policies/list
|
||||
* `group <RegularExpression>` - Only display policies whose group email address matches the `<RegularExpression>`
|
||||
* `ou|org|orgunit <RegularExpression> - Only display policies whose OU path matches the `<RegularExpression>`
|
||||
|
||||
By default, policy warnings are displayed, use the 'nowarnings` option to suppress their display.
|
||||
|
||||
@@ -371,3 +378,9 @@ the quote character itself, the column delimiter (comma by default) and new-line
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
### Examples
|
||||
Print all service status policies.
|
||||
```
|
||||
gam redirect csv ./ServiceStatusPolicies.csv print policies filter "setting.type.matches('.*service_status')"
|
||||
```
|
||||
|
||||
@@ -10,6 +10,20 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
||||
|
||||
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
|
||||
|
||||
### 7.00.38
|
||||
|
||||
Fixed logic flaw in `gam print|show policies` where non-matching policies were displayed.
|
||||
|
||||
### 7.00.37
|
||||
|
||||
Added options `group <RegularExpression>` and `ou|org|orgunit <RegularExpression>`
|
||||
to `gam print|show policies` that causes GAM to only display policies whose group email address
|
||||
or OU path match the `<RegularExpression>`.
|
||||
|
||||
Updated `gam get|update|delete contactphotos` to use the People API for domain shared contact photos
|
||||
as Google has deprecated the Domain Shared Contacts API for these commands. Unfortunately,
|
||||
the People API fails with `gam update|delete contactphotos`.
|
||||
|
||||
### 7.00.36
|
||||
|
||||
Updated `gam print chromeapps` to correct a trap caused by an API change.
|
||||
|
||||
@@ -251,7 +251,7 @@ writes the credentials into the file oauth2.txt.
|
||||
admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt
|
||||
admin@server:/Users/admin$ gam version
|
||||
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
|
||||
GAM 7.00.36 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.00.38 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.0 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
@@ -923,7 +923,7 @@ writes the credentials into the file oauth2.txt.
|
||||
C:\>del C:\GAMConfig\oauth2.txt
|
||||
C:\>gam version
|
||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
|
||||
GAM7 7.00.36 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM7 7.00.38 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.0 64-bit final
|
||||
Windows-10-10.0.17134 AMD64
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
- [Display calendar UI settings](#display-calendar-ui-settings)
|
||||
- [Manage calendars](#manage-calendars)
|
||||
- [Create and remove calendars](#create-and-remove-calendars)
|
||||
- [Display calendar settings](#display-calendar-settings)
|
||||
- [Modify calendar settings](#modify-calendar-settings)
|
||||
- [Display calendar settings](#display-calendar-settings)
|
||||
- [Manage calendar lists](#manage-calendar-lists)
|
||||
- [Display specific calendars from list](#display-specific-calendars-from-list)
|
||||
- [Display calendar lists](#display-calendar-lists)
|
||||
@@ -23,6 +23,8 @@
|
||||
<EmailAddress> ::= <String>@<DomainName>
|
||||
<CalendarItem> ::= <EmailAddress>
|
||||
<CalendarList> ::= "<CalendarItem>(,<CalendarItem>)*"
|
||||
<CalendarEntity> ::= <CalendarList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Collections-of-Items
|
||||
<CourseAlias> ::= <String>
|
||||
<CourseID> ::= <Number>|d:<CourseAlias>
|
||||
<CourseIDList> ::= "<CourseID>(,<CourseID>)*"
|
||||
@@ -38,6 +40,21 @@
|
||||
<CalendarACLRole> ::=
|
||||
editor|freebusy|freebusyreader|owner|reader|writer
|
||||
|
||||
<CalendarSettings> ::=
|
||||
(description <String>)|
|
||||
(location <String>)|
|
||||
(summary <String>)|
|
||||
(timezone <TimeZone>)
|
||||
|
||||
<CalendarSettingsField> ::=
|
||||
conferenceproperties|
|
||||
description|
|
||||
id|
|
||||
location|
|
||||
summary|
|
||||
timezone
|
||||
<CalendarSettingsFieldList> ::= "<CalendarSettingsField>(,<CalendarSettingsField>)*"
|
||||
|
||||
<CalendarSelectProperty> ::=
|
||||
minaccessrole <CalendarACLRole>|
|
||||
showdeleted|
|
||||
@@ -111,12 +128,6 @@
|
||||
(selected <Boolean>)|
|
||||
(summary <String>)
|
||||
|
||||
<CalendarSettings> ::=
|
||||
(description <String>)|
|
||||
(location <String>)|
|
||||
(summary <String>)|
|
||||
(timezone <TimeZone>)
|
||||
|
||||
<CalendarListField> ::=
|
||||
accessrole|
|
||||
backgroundcolor|
|
||||
@@ -189,18 +200,30 @@ gam <UserTypeEntity> create calendar <CalendarSettings>
|
||||
gam <UserTypeEntity> remove calendars <UserCalendarEntity>
|
||||
```
|
||||
|
||||
### Display calendar settings
|
||||
```
|
||||
gam <UserTypeEntity> info calendars <UserCalendarEntity> [formatjson]
|
||||
```
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
### Modify calendar settings
|
||||
```
|
||||
gam <UserTypeEntity> modify calendars <UserCalendarEntity> <CalendarSettings>
|
||||
```
|
||||
|
||||
### Display calendar settings
|
||||
```
|
||||
gam calendar <CalendarEntity> show settings
|
||||
[fields <CalendarSettingsFieldList>]
|
||||
[formatjson]
|
||||
```
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
```
|
||||
gam calendar <CalendarEntity> print settings [todrive <ToDriveAttribute>*]
|
||||
[fields <CalendarSettingsFieldList>]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
|
||||
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
## Manage calendar lists
|
||||
These commands manage a user's list of calendars.
|
||||
```
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAM 7.00.36 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.00.38 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.0 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
@@ -15,7 +15,7 @@ Time: 2023-06-02T21:10:00-07:00
|
||||
Print the current version of Gam with details and time offset information
|
||||
```
|
||||
gam version timeoffset
|
||||
GAM 7.00.36 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.00.38 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.0 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
@@ -27,7 +27,7 @@ Your system time differs from www.googleapis.com by less than 1 second
|
||||
Print the current version of Gam with extended details and SSL information
|
||||
```
|
||||
gam version extended
|
||||
GAM 7.00.36 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.00.38 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.0 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
@@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64
|
||||
Path: /Users/Admin/bin/gam7
|
||||
Version Check:
|
||||
Current: 5.35.08
|
||||
Latest: 7.00.36
|
||||
Latest: 7.00.38
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@@ -72,7 +72,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
7.00.36
|
||||
7.00.38
|
||||
```
|
||||
In Linux/MacOS you can do:
|
||||
```
|
||||
@@ -82,7 +82,7 @@ echo $VER
|
||||
Print the current version of Gam and address of this Wiki
|
||||
```
|
||||
gam help
|
||||
GAM 7.00.36 - https://github.com/GAM-team/GAM
|
||||
GAM 7.00.38 - https://github.com/GAM-team/GAM
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.0 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
|
||||
@@ -4075,9 +4075,11 @@ gam info policies <CIPolicyNameEntity>
|
||||
[formatjson]
|
||||
gam print policies [todrive <ToDriveAttribute>*]
|
||||
[filter <String>] [nowarnings] [noappnames]
|
||||
[group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
|
||||
[formatjson [quotechar <Character>]]
|
||||
gam show policies
|
||||
[filter <String>] [nowarnings] [noappnames]
|
||||
[group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
|
||||
[formatjson]
|
||||
|
||||
# Inbound SSO
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
7.00.38
|
||||
|
||||
Fixed logic flaw in `gam print|show policies` where non-matching policies were displayed.
|
||||
|
||||
7.00.37
|
||||
|
||||
Added options `group <RegularExpression>` and `ou|org|orgunit <RegularExpression>`
|
||||
to `gam print|show policies` that causes GAM to only display policies whose group email address
|
||||
or OU path match the `<RegularExpression>`.
|
||||
|
||||
Updated `gam get|update|delete contactphotos` to use the People API for domain shared contact photos
|
||||
as Google has deprecated the Domain Shared Contacts API for these commands. Unfortunately,
|
||||
the People API fails with `gam update|delete contactphotos`.
|
||||
|
||||
7.00.36
|
||||
|
||||
Updated `gam print chromeapps` to correct a trap caused by an API change.
|
||||
|
||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
||||
"""
|
||||
|
||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||
__version__ = '7.00.36'
|
||||
__version__ = '7.00.38'
|
||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
#pylint: disable=wrong-import-position
|
||||
@@ -2693,6 +2693,11 @@ def performActionNumItems(itemCount, itemType, i=0, count=0):
|
||||
[f'{Act.ToPerform()} {itemCount} {Ent.Choose(itemType, itemCount)}'],
|
||||
currentCountNL(i, count)))
|
||||
|
||||
def performActionModifierNumItems(modifier, itemCount, itemType, i=0, count=0):
|
||||
writeStdout(formatKeyValueList(Ind.Spaces(),
|
||||
[f'{Act.ToPerform()} {modifier} {itemCount} {Ent.Choose(itemType, itemCount)}'],
|
||||
currentCountNL(i, count)))
|
||||
|
||||
def actionPerformedNumItems(itemCount, itemType, i=0, count=0):
|
||||
writeStderr(formatKeyValueList(Ind.Spaces(),
|
||||
[f'{itemCount} {Ent.Choose(itemType, itemCount)} {Act.Performed()} '],
|
||||
@@ -20287,137 +20292,6 @@ def doPrintShowDomainContacts():
|
||||
def doPrintShowGAL():
|
||||
_printShowContacts(False)
|
||||
|
||||
def _processContactPhotos(function):
|
||||
def _makeFilenameFromPattern():
|
||||
filename = filenamePattern[:]
|
||||
if subForContactId:
|
||||
filename = filename.replace('#contactid#', contactId)
|
||||
if subForEmail:
|
||||
for email in fields.get('Emails', []):
|
||||
if email.get('primary', 'false') == 'true':
|
||||
filename = filename.replace('#email#', email['value'])
|
||||
break
|
||||
else:
|
||||
filename = filename.replace('#email#', contactId)
|
||||
return filename
|
||||
|
||||
entityType = Ent.DOMAIN
|
||||
contactsManager = ContactsManager()
|
||||
entityList, contactQuery, queriedContacts = _getContactEntityList(1, False)
|
||||
if function in {'ChangePhoto', 'GetPhoto'}:
|
||||
targetFolder = os.getcwd()
|
||||
filenamePattern = '#contactid#.jpg'
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'drivedir':
|
||||
targetFolder = GC.Values[GC.DRIVE_DIR]
|
||||
elif myarg in {'sourcefolder', 'targetfolder'}:
|
||||
targetFolder = os.path.expanduser(getString(Cmd.OB_FILE_PATH))
|
||||
if function == 'GetPhoto' and not os.path.isdir(targetFolder):
|
||||
os.makedirs(targetFolder)
|
||||
elif myarg == 'filename':
|
||||
filenamePattern = getString(Cmd.OB_PHOTO_FILENAME_PATTERN)
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
subForContactId = filenamePattern.find('#contactid#') != -1
|
||||
subForEmail = filenamePattern.find('#email#') != -1
|
||||
if not subForContactId and not subForEmail:
|
||||
filename = filenamePattern
|
||||
else: #elif function == 'DeletePhoto':
|
||||
checkForExtraneousArguments()
|
||||
user, contactsObject = getContactsObject(True)
|
||||
if queriedContacts:
|
||||
entityList = queryContacts(contactsObject, contactQuery)
|
||||
if entityList is None:
|
||||
return
|
||||
j = 0
|
||||
jcount = len(entityList)
|
||||
entityPerformActionModifierNumItems([entityType, user], Msg.MAXIMUM_OF, jcount, Ent.PHOTO)
|
||||
if jcount == 0:
|
||||
setSysExitRC(NO_ENTITIES_FOUND_RC)
|
||||
return
|
||||
Ind.Increment()
|
||||
for contact in entityList:
|
||||
j += 1
|
||||
try:
|
||||
if not queriedContacts:
|
||||
contactId = normalizeContactId(contact)
|
||||
contact = callGData(contactsObject, 'GetContact',
|
||||
throwErrors=[GDATA.NOT_FOUND, GDATA.BAD_REQUEST, GDATA.SERVICE_NOT_APPLICABLE, GDATA.FORBIDDEN, GDATA.NOT_IMPLEMENTED],
|
||||
retryErrors=[GDATA.INTERNAL_SERVER_ERROR],
|
||||
uri=contactsObject.GetContactFeedUri(contact_list=user, contactId=contactId))
|
||||
fields = contactsManager.ContactToFields(contact)
|
||||
else:
|
||||
contactId = contactsManager.GetContactShortId(contact)
|
||||
fields = contactsManager.ContactToFields(contact)
|
||||
if not localContactSelects(contactsManager, contactQuery, fields):
|
||||
continue
|
||||
except (GDATA.notFound, GDATA.badRequest) as e:
|
||||
entityActionFailedWarning([entityType, user, Ent.CONTACT, contactId], str(e), j, jcount)
|
||||
break
|
||||
except (GDATA.forbidden, GDATA.notImplemented):
|
||||
entityServiceNotApplicableWarning(entityType, user)
|
||||
break
|
||||
except GDATA.serviceNotApplicable:
|
||||
entityUnknownWarning(entityType, user)
|
||||
break
|
||||
try:
|
||||
if function == 'ChangePhoto':
|
||||
if subForContactId or subForEmail:
|
||||
filename = _makeFilenameFromPattern()
|
||||
filename = os.path.join(targetFolder, filename)
|
||||
callGData(contactsObject, function,
|
||||
throwErrors=[GDATA.NOT_FOUND, GDATA.BAD_REQUEST, GDATA.SERVICE_NOT_APPLICABLE, GDATA.FORBIDDEN, GDATA.NOT_IMPLEMENTED],
|
||||
retryErrors=[GDATA.INTERNAL_SERVER_ERROR],
|
||||
media=filename, contact_entry_or_url=contact,
|
||||
content_type='image/*', content_length=os.path.getsize(filename), extra_headers={'If-Match': '*'})
|
||||
entityActionPerformed([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename])
|
||||
elif function == 'GetPhoto':
|
||||
if subForContactId or subForEmail:
|
||||
filename = _makeFilenameFromPattern()
|
||||
filename = os.path.join(targetFolder, filename)
|
||||
photo_data = callGData(contactsObject, function,
|
||||
throwErrors=[GDATA.NOT_FOUND, GDATA.BAD_REQUEST, GDATA.SERVICE_NOT_APPLICABLE, GDATA.FORBIDDEN, GDATA.NOT_IMPLEMENTED],
|
||||
retryErrors=[GDATA.INTERNAL_SERVER_ERROR],
|
||||
contact_entry_or_url=contact)
|
||||
if photo_data:
|
||||
status, e = writeFileReturnError(filename, eval(photo_data), mode='wb') #pylint: disable=eval-used
|
||||
if status:
|
||||
entityActionPerformed([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename])
|
||||
else:
|
||||
entityActionFailedWarning([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename], str(e))
|
||||
else:
|
||||
entityDoesNotHaveItemWarning([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, ''])
|
||||
else: #elif function == 'DeletePhoto':
|
||||
filename = ''
|
||||
callGData(contactsObject, function,
|
||||
throwErrors=[GDATA.NOT_FOUND, GDATA.BAD_REQUEST, GDATA.SERVICE_NOT_APPLICABLE, GDATA.FORBIDDEN, GDATA.NOT_IMPLEMENTED],
|
||||
retryErrors=[GDATA.INTERNAL_SERVER_ERROR],
|
||||
contact_entry_or_url=contact, extra_headers={'If-Match': '*'})
|
||||
entityActionPerformed([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename])
|
||||
except GDATA.notFound as e:
|
||||
entityActionFailedWarning([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename], str(e), j, jcount)
|
||||
except (GDATA.badRequest, OSError, IOError) as e:
|
||||
entityActionFailedWarning([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename], str(e), j, jcount)
|
||||
except (GDATA.forbidden, GDATA.notImplemented):
|
||||
entityServiceNotApplicableWarning(entityType, user)
|
||||
break
|
||||
Ind.Decrement()
|
||||
|
||||
# gam update contactphotos <ContactEntity>|<ContactSelection>
|
||||
# [drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>]
|
||||
def doUpdateDomainContactPhoto():
|
||||
_processContactPhotos('ChangePhoto')
|
||||
|
||||
# gam get contactphotos <ContactEntity>|<ContactSelection>
|
||||
# [drivedir|(targetfolder <FilePath>)] [filename <FileNamePattern>]
|
||||
def doGetDomainContactPhoto():
|
||||
_processContactPhotos('GetPhoto')
|
||||
|
||||
# gam delete contactphotos <ContactEntity>|<ContactSelection>
|
||||
def doDeleteDomainContactPhoto():
|
||||
_processContactPhotos('DeletePhoto')
|
||||
|
||||
# Prople commands utilities
|
||||
#
|
||||
def normalizePeopleResourceName(resourceName):
|
||||
@@ -22634,9 +22508,16 @@ def _processPeopleContactPhotos(users, function):
|
||||
filename = filename.replace('#email#', resourceName.split('/')[1])
|
||||
return filename
|
||||
|
||||
entityType = Ent.USER
|
||||
peopleEntityType = Ent.PEOPLE_CONTACT
|
||||
sources = [PEOPLE_READ_SOURCES_CHOICE_MAP['contact']]
|
||||
if users is not None:
|
||||
entityType = Ent.USER
|
||||
peopleEntityType = Ent.PEOPLE_CONTACT
|
||||
sources = [PEOPLE_READ_SOURCES_CHOICE_MAP['contact']]
|
||||
else:
|
||||
users = [None]
|
||||
people = buildGAPIObject(API.PEOPLE_DIRECTORY)
|
||||
entityType = Ent.DOMAIN
|
||||
peopleEntityType = Ent.PEOPLE_CONTACT
|
||||
sources = [PEOPLE_READ_SOURCES_CHOICE_MAP['domaincontact']]
|
||||
entityList, resourceNameLists, contactQuery, queriedContacts = _getPeopleContactEntityList(entityType, 1)
|
||||
if function in {'updateContactPhoto', 'getContactPhoto'}:
|
||||
targetFolder = os.getcwd()
|
||||
@@ -22665,9 +22546,12 @@ def _processPeopleContactPhotos(users, function):
|
||||
i += 1
|
||||
if resourceNameLists:
|
||||
entityList = resourceNameLists[user]
|
||||
user, people = buildGAPIServiceObject(API.PEOPLE, user, i, count)
|
||||
if not people:
|
||||
continue
|
||||
if user is not None:
|
||||
user, people = buildGAPIServiceObject(API.PEOPLE, user, i, count)
|
||||
if not people:
|
||||
continue
|
||||
else:
|
||||
user = Ent.Singular(entityType)
|
||||
if contactQuery['contactGroupSelect']:
|
||||
groupId, _, contactGroupNames = validatePeopleContactGroup(people, contactQuery['contactGroupSelect'],
|
||||
None, None, entityType, user, i, count)
|
||||
@@ -22774,6 +22658,20 @@ def getUserPeopleContactPhoto(users):
|
||||
def deleteUserPeopleContactPhoto(users):
|
||||
_processPeopleContactPhotos(users, 'deleteContactPhoto')
|
||||
|
||||
# gam update contactphotos <PeopleResourceNameEntity>|<PeopleUserContactSelection>
|
||||
# [drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>]
|
||||
def doUpdateDomainContactPhoto():
|
||||
_processPeopleContactPhotos(None, 'updateContactPhoto')
|
||||
|
||||
# gam get contactphotos <PeopleResourceNameEntity>|<PeopleUserContactSelection>
|
||||
# [drivedir|(targetfolder <FilePath>)] [filename <FileNamePattern>]
|
||||
def doGetDomainContactPhoto():
|
||||
_processPeopleContactPhotos(None, 'getContactPhoto')
|
||||
|
||||
# gam delete contactphoto <PeopleResourceNameEntity>|<PeopleUserContactSelection>
|
||||
def doDeleteDomainContactPhoto():
|
||||
_processPeopleContactPhotos(None, 'deleteContactPhoto')
|
||||
|
||||
# gam <UserTypeEntity> create contactgroup <ContactGroupAttribute>+
|
||||
# [(csv [todrive <ToDriveAttribute>*] (addcsvdata <FieldName> <String>)*))| returnidonly]
|
||||
def createUserPeopleContactGroup(users):
|
||||
@@ -32648,6 +32546,8 @@ def infoGroups(entityList):
|
||||
getCloudIdentity = True
|
||||
cifields = getFieldsFromFieldsList(groupFieldsLists['ci'])
|
||||
ci = buildGAPIObject(API.CLOUDIDENTITY_GROUPS)
|
||||
else:
|
||||
cifields = None
|
||||
i = 0
|
||||
count = len(entityList)
|
||||
for group in entityList:
|
||||
@@ -35131,7 +35031,9 @@ def _getPolicyAppNameFromId(httpObj, app):
|
||||
if a:
|
||||
app['applicationName'] = a.group(1)
|
||||
|
||||
def _cleanPolicy(policy, add_warnings, no_appnames, cd, groups_ci):
|
||||
def _cleanPolicy(policy, add_warnings, no_appnames,
|
||||
groupEmailPattern, orgUnitPathPattern,
|
||||
cd, groups_ci):
|
||||
# convert any wordlists into spaced strings to reduce output complexity
|
||||
if policy['setting']['type'] == 'settings/detector.word_list':
|
||||
policy['setting']['value']['wordList'] = ' '.join(policy['setting']['value']['wordList']['words'])
|
||||
@@ -35147,8 +35049,17 @@ def _cleanPolicy(policy, add_warnings, no_appnames, cd, groups_ci):
|
||||
_, _, policy['policyQuery']['groupEmail'] = convertGroupCloudIDToEmail(groups_ci, groupId)
|
||||
# all groups are in the root OU so the orgUnit attribute is useless
|
||||
policy['policyQuery'].pop('orgUnit', None)
|
||||
if groupEmailPattern is not None:
|
||||
return groupEmailPattern.match(policy['policyQuery']['groupEmail'])
|
||||
if orgUnitPathPattern is not None:
|
||||
return False
|
||||
elif orgId := policy['policyQuery'].get('orgUnit'):
|
||||
policy['policyQuery']['orgUnitPath'] = convertOrgUnitIDtoPath(cd, orgId)
|
||||
if orgUnitPathPattern is not None:
|
||||
return orgUnitPathPattern.match(policy['policyQuery']['orgUnitPath'])
|
||||
if groupEmailPattern is not None:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _showPolicy(policy, FJQC, i=0, count=0):
|
||||
if FJQC is not None and FJQC.formatJSON:
|
||||
@@ -35163,15 +35074,22 @@ def _showPolicy(policy, FJQC, i=0, count=0):
|
||||
printBlankLine()
|
||||
Ind.Decrement()
|
||||
|
||||
def _showPolicies(policies, FJQC, add_warnings, no_appnames, cd, groups_ci):
|
||||
def _showPolicies(policies, FJQC, add_warnings, no_appnames,
|
||||
groupEmailPattern, orgUnitPathPattern,
|
||||
cd, groups_ci):
|
||||
count = len(policies)
|
||||
performActionNumItems(count, Ent.POLICY)
|
||||
if groupEmailPattern is None and orgUnitPathPattern is None:
|
||||
performActionNumItems(count, Ent.POLICY)
|
||||
else:
|
||||
performActionModifierNumItems(Msg.MAXIMUM_OF, count, Ent.POLICY)
|
||||
Ind.Increment()
|
||||
i = 0
|
||||
for policy in policies:
|
||||
i += 1
|
||||
_cleanPolicy(policy, add_warnings, no_appnames, cd, groups_ci)
|
||||
_showPolicy(policy, FJQC, i, count)
|
||||
if _cleanPolicy(policy, add_warnings, no_appnames,
|
||||
groupEmailPattern, orgUnitPathPattern,
|
||||
cd, groups_ci):
|
||||
_showPolicy(policy, FJQC, i, count)
|
||||
Ind.Decrement()
|
||||
|
||||
# gam info policies <CIPolicyNameEntity>
|
||||
@@ -35213,13 +35131,16 @@ def doInfoCIPolicies():
|
||||
ifilter = f"setting.type.matches('{pname}')"
|
||||
printGettingAllAccountEntities(Ent.POLICY, ifilter)
|
||||
policies = _filterPolicies(ci, getPageMessage(), ifilter)
|
||||
_showPolicies(policies, FJQC, add_warnings, no_appnames, cd, groups_ci)
|
||||
_showPolicies(policies, FJQC, add_warnings, no_appnames,
|
||||
None, None, cd, groups_ci)
|
||||
|
||||
# gam print policies [todrive <ToDriveAttribute>*]
|
||||
# [filter <String>] [nowarnings] [noappnames]
|
||||
# [group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
# gam show policies
|
||||
# [filter <String>] [nowarnings] [noappnames]
|
||||
# [group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
|
||||
# [formatjson]
|
||||
def doPrintShowCIPolicies():
|
||||
|
||||
@@ -35241,6 +35162,7 @@ def doPrintShowCIPolicies():
|
||||
ifilter = None
|
||||
add_warnings = True
|
||||
no_appnames = False
|
||||
groupEmailPattern = orgUnitPathPattern = None
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
@@ -35250,17 +35172,25 @@ def doPrintShowCIPolicies():
|
||||
elif myarg == 'nowarnings':
|
||||
add_warnings = False
|
||||
elif myarg == 'noappnames':
|
||||
no_appnames=True
|
||||
no_appnames = True
|
||||
elif myarg == 'group':
|
||||
groupEmailPattern = getREPattern(re.IGNORECASE)
|
||||
elif myarg in {'ou', 'org', 'orgunit'}:
|
||||
orgUnitPathPattern = getREPattern(re.IGNORECASE)
|
||||
else:
|
||||
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
||||
printGettingAllAccountEntities(Ent.POLICY, ifilter)
|
||||
policies = _filterPolicies(ci, getPageMessage(), ifilter)
|
||||
if not csvPF:
|
||||
_showPolicies(policies, FJQC, add_warnings, no_appnames, cd, groups_ci)
|
||||
_showPolicies(policies, FJQC, add_warnings, no_appnames,
|
||||
groupEmailPattern, orgUnitPathPattern,
|
||||
cd, groups_ci)
|
||||
else:
|
||||
for policy in policies:
|
||||
_cleanPolicy(policy, add_warnings, no_appnames, cd, groups_ci)
|
||||
_printPolicy(policy)
|
||||
if _cleanPolicy(policy, add_warnings, no_appnames,
|
||||
groupEmailPattern, orgUnitPathPattern,
|
||||
cd, groups_ci):
|
||||
_printPolicy(policy)
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Policies')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user