mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-28 09:51:36 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9e28e966a | ||
|
|
89970bbf0d | ||
|
|
0b16bded50 | ||
|
|
2ea6f773cd | ||
|
|
bb922dcff6 | ||
|
|
b38bf3e9bb | ||
|
|
39e5a45d72 | ||
|
|
d0b7ac80da | ||
|
|
320827b76e |
20
.github/workflows/get-cacerts.yml
vendored
20
.github/workflows/get-cacerts.yml
vendored
@@ -20,8 +20,24 @@ jobs:
|
|||||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
|
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
|
||||||
fetch-depth: 0 # otherwise, you will failed to push refs to dest repo
|
fetch-depth: 0 # otherwise, you will failed to push refs to dest repo
|
||||||
|
|
||||||
- name: Check for updates
|
- name: Get Current cacerts.pem hash
|
||||||
run: curl -o ./cacerts.pem -vvvv https://pki.goog/roots.pem
|
run: |
|
||||||
|
export CURRENT_HASH=$(sha256sum ./cacerts.pem)
|
||||||
|
echo "Current hash is: ${CURRENT_HASH}"
|
||||||
|
echo "CURRENT_HASH=${CURRENT_HASH}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Get latest cacerts.pem file from Google
|
||||||
|
run: |
|
||||||
|
curl -o ./cacerts.pem -vvvv https://pki.goog/roots.pem
|
||||||
|
|
||||||
|
- name: Compare hashes
|
||||||
|
run: |
|
||||||
|
export NEW_HASH=$(sha256sum ./cacerts.pem)
|
||||||
|
if [ "$NEW_HASH" == "$CURRENT_HASH" ]; then
|
||||||
|
echo "Same file."
|
||||||
|
else
|
||||||
|
echo "New file content. Was ${CURRENT_HASH} and now is ${NEW_HASH}"
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Commit file
|
- name: Commit file
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ If an item contains spaces, it should be surrounded by ".
|
|||||||
<ChatThread> ::= spaces/<String>/threads/<String>
|
<ChatThread> ::= spaces/<String>/threads/<String>
|
||||||
<GIGroupAlias> ::= <EmailAddress>
|
<GIGroupAlias> ::= <EmailAddress>
|
||||||
<GIGroupItem> ::= <EmailAddress>|<UniqueID>|groups/<String>
|
<GIGroupItem> ::= <EmailAddress>|<UniqueID>|groups/<String>
|
||||||
<CIGroupType> ::= customer|group|other|serviceaccount|user
|
<CIGroupMemberType> ::= cbcmbrowser|chromeosdevice|customer|group|other|serviceaccount|user
|
||||||
<CIPolicyName> ::= policies/<String>|settings/<String>|<String>
|
<CIPolicyName> ::= policies/<String>|settings/<String>|<String>
|
||||||
<ClassificationLabelID> ::= <String>
|
<ClassificationLabelID> ::= <String>
|
||||||
<ClassificationLabelFieldID> ::= <String>
|
<ClassificationLabelFieldID> ::= <String>
|
||||||
@@ -468,7 +468,7 @@ If an item contains spaces, it should be surrounded by ".
|
|||||||
<FloorName> ::= <String>
|
<FloorName> ::= <String>
|
||||||
<GroupItem> ::= <EmailAddress>|<UniqueID>|<String>
|
<GroupItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||||
<GroupRole> ::= owner|manager|member
|
<GroupRole> ::= owner|manager|member
|
||||||
<GroupType> ::= customer|group|user
|
<GroupMemberType> ::= customer|group|user
|
||||||
<GuardianItem> ::= <EmailAddress>|<UniqueID>|<String>
|
<GuardianItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||||
<GuardianInvitationID> ::= <String>
|
<GuardianInvitationID> ::= <String>
|
||||||
<HoldItem> ::= <UniqueID>|<String>
|
<HoldItem> ::= <UniqueID>|<String>
|
||||||
@@ -664,7 +664,7 @@ If an item contains spaces, it should be surrounded by ".
|
|||||||
<CalendarList> ::= "<CalendarItem>(,<CalendarItem>)*"
|
<CalendarList> ::= "<CalendarItem>(,<CalendarItem>)*"
|
||||||
<ChatSpaceList> ::= "<ChatSpace>(,<ChatSpace>)*"
|
<ChatSpaceList> ::= "<ChatSpace>(,<ChatSpace>)*"
|
||||||
<CIGroupAliasList> ::= "<CIGroupAlias>(,<CIGroupAlias>)*"
|
<CIGroupAliasList> ::= "<CIGroupAlias>(,<CIGroupAlias>)*"
|
||||||
<CIGroupTypeList> ::= "<CIGroupType>(,<CIGroupType>)*"
|
<CIGroupMemberTypeList> ::= "<CIGroupMemberType>(,<CIGroupMemberType>)*"
|
||||||
<CIPolicyNameList> ::= "<CIPolicyName>(,<CIPolicyName>)*"
|
<CIPolicyNameList> ::= "<CIPolicyName>(,<CIPolicyName>)*"
|
||||||
<ClassroomInvitationIDList> ::= "<ClassroomInvitationID>(,<ClassroomInvitationID>)*"
|
<ClassroomInvitationIDList> ::= "<ClassroomInvitationID>(,<ClassroomInvitationID>)*"
|
||||||
<ContactGroupList> ::= "<ContactGroupItem>(,<ContactGroupItem>)*"
|
<ContactGroupList> ::= "<ContactGroupItem>(,<ContactGroupItem>)*"
|
||||||
@@ -707,7 +707,7 @@ If an item contains spaces, it should be surrounded by ".
|
|||||||
<GuardianInvitationIDList> ::= "<GuardianInvitationID>(,<GuardianInvitationID>)*"
|
<GuardianInvitationIDList> ::= "<GuardianInvitationID>(,<GuardianInvitationID>)*"
|
||||||
<GroupList> ::= "<GroupItem>(,<GroupItem>)*"
|
<GroupList> ::= "<GroupItem>(,<GroupItem>)*"
|
||||||
<GroupRoleList> ::= "<GroupRole>(,<GroupRole>)*"
|
<GroupRoleList> ::= "<GroupRole>(,<GroupRole>)*"
|
||||||
<GroupTypeList> ::= "<GroupType>(,<GroupType>)*"
|
<GroupMemberTypeList> ::= "<GroupMemberType>(,<GroupMemberType>)*"
|
||||||
<LabelIDList> ::= "<LabelID>(,<LabelID>)*"
|
<LabelIDList> ::= "<LabelID>(,<LabelID>)*"
|
||||||
<LabelNameList> ::= "'<LabelName>'(,'<LabelName>')*"
|
<LabelNameList> ::= "'<LabelName>'(,'<LabelName>')*"
|
||||||
<LanguageList> ::= "<Language>(,<Language>)*"
|
<LanguageList> ::= "<Language>(,<Language>)*"
|
||||||
@@ -3829,8 +3829,9 @@ gam info group|groups <GroupEntity>
|
|||||||
[basic] <GroupFieldName>* [fields <GroupFieldNameList>] [nodeprecated]
|
[basic] <GroupFieldName>* [fields <GroupFieldNameList>] [nodeprecated]
|
||||||
[ciallfields|(cifields <CIGroupFieldNameList>)]
|
[ciallfields|(cifields <CIGroupFieldNameList>)]
|
||||||
[members] [managers] [owners]
|
[members] [managers] [owners]
|
||||||
|
[internal] [internaldomains <DomainNameList>] [external]
|
||||||
[notsuspended|suspended] [notarchived|archived]
|
[notsuspended|suspended] [notarchived|archived]
|
||||||
[types <GroupTypeList>]
|
[types <GroupMemberTypeList>]
|
||||||
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
||||||
[formatjson]
|
[formatjson]
|
||||||
gam print groups [todrive <ToDriveAttribute>*]
|
gam print groups [todrive <ToDriveAttribute>*]
|
||||||
@@ -3845,9 +3846,10 @@ gam print groups [todrive <ToDriveAttribute>*]
|
|||||||
[nodeprecated]
|
[nodeprecated]
|
||||||
[roles <GroupRoleList>]
|
[roles <GroupRoleList>]
|
||||||
[members|memberscount] [managers|managerscount] [owners|ownerscount] [totalcount] [countsonly]
|
[members|memberscount] [managers|managerscount] [owners|ownerscount] [totalcount] [countsonly]
|
||||||
|
[internal] [internaldomains <DomainNameList>] [external]
|
||||||
[includederivedmembership]
|
[includederivedmembership]
|
||||||
[notsuspended|suspended] [notarchived|archived]
|
[notsuspended|suspended] [notarchived|archived]
|
||||||
[types <GroupTypeList>]
|
[types <GroupMemberTypeList>]
|
||||||
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
||||||
[convertcrnl] [delimiter <Character>] [sortheaders]
|
[convertcrnl] [delimiter <Character>] [sortheaders]
|
||||||
[formatjson [quotechar <Character>]]
|
[formatjson [quotechar <Character>]]
|
||||||
@@ -3880,10 +3882,11 @@ gam print group-members [todrive <ToDriveAttribute>*]
|
|||||||
[descriptionmatchpattern [not] <RegularExpression>]
|
[descriptionmatchpattern [not] <RegularExpression>]
|
||||||
[admincreatedmatch <Boolean>]
|
[admincreatedmatch <Boolean>]
|
||||||
[roles <GroupRoleList>] [members] [managers] [owners]
|
[roles <GroupRoleList>] [members] [managers] [owners]
|
||||||
|
[internal] [internaldomains <DomainNameList>] [external]
|
||||||
[membernames] [showdeliverysettings]
|
[membernames] [showdeliverysettings]
|
||||||
<MembersFieldName>* [fields <MembersFieldNameList>]
|
<MembersFieldName>* [fields <MembersFieldNameList>]
|
||||||
[notsuspended|suspended] [notarchived|archived]
|
[notsuspended|suspended] [notarchived|archived]
|
||||||
[types <GroupTypeList>]
|
[types <GroupMemberTypeList>]
|
||||||
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
||||||
[userfields <UserFieldNameList>]
|
[userfields <UserFieldNameList>]
|
||||||
[allschemas|(schemas|custom|customschemas <SchemaNameList>)]
|
[allschemas|(schemas|custom|customschemas <SchemaNameList>)]
|
||||||
@@ -3891,7 +3894,7 @@ gam print group-members [todrive <ToDriveAttribute>*]
|
|||||||
[peoplelookup|(peoplelookupuser <EmailAddress>)]
|
[peoplelookup|(peoplelookupuser <EmailAddress>)]
|
||||||
[unknownname <String>] [cachememberinfo [Boolean]]
|
[unknownname <String>] [cachememberinfo [Boolean]]
|
||||||
[formatjson [quotechar <Character>]]
|
[formatjson [quotechar <Character>]]
|
||||||
gam show group-members
|
`gam show group-members
|
||||||
[([domain|domains <DomainNameEntity>] ([member|showownedby <EmailItem>]|[(query <QueryGroup>)|(queries <QueryGroupList>)]))|
|
[([domain|domains <DomainNameEntity>] ([member|showownedby <EmailItem>]|[(query <QueryGroup>)|(queries <QueryGroupList>)]))|
|
||||||
(group|group_ns|group_susp <GroupItem>)|
|
(group|group_ns|group_susp <GroupItem>)|
|
||||||
(select <GroupEntity>)]
|
(select <GroupEntity>)]
|
||||||
@@ -3899,8 +3902,9 @@ gam show group-members
|
|||||||
[descriptionmatchpattern [not] <RegularExpression>]
|
[descriptionmatchpattern [not] <RegularExpression>]
|
||||||
[admincreatedmatch <Boolean>]
|
[admincreatedmatch <Boolean>]
|
||||||
[roles <GroupRoleList>] [members] [managers] [owners] [depth <Number>]
|
[roles <GroupRoleList>] [members] [managers] [owners] [depth <Number>]
|
||||||
|
[internal] [internaldomains <DomainNameList>] [external]
|
||||||
[notsuspended|suspended] [notarchived|archived]
|
[notsuspended|suspended] [notarchived|archived]
|
||||||
[types <GroupTypeList>]
|
[types <GroupMemberTypeList>]
|
||||||
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
||||||
[includederivedmembership]
|
[includederivedmembership]
|
||||||
|
|
||||||
@@ -3925,6 +3929,7 @@ gam update cigroup <GroupEntity> [copyfrom <GroupItem>] <GroupAttribute>
|
|||||||
[security|makesecuritygroup|
|
[security|makesecuritygroup|
|
||||||
dynamicsecurity|makedynamicsecuritygroup|
|
dynamicsecurity|makedynamicsecuritygroup|
|
||||||
lockedsecurity|makelockedsecuritygroup]
|
lockedsecurity|makelockedsecuritygroup]
|
||||||
|
[locked|unlocked]
|
||||||
[dynamic <QueryDynamicGroup>]
|
[dynamic <QueryDynamicGroup>]
|
||||||
[memberrestrictions <QueryMemberRestrictions>]
|
[memberrestrictions <QueryMemberRestrictions>]
|
||||||
gam update cigroups <GroupEntity> create|add [<GroupRole>]
|
gam update cigroups <GroupEntity> create|add [<GroupRole>]
|
||||||
@@ -3958,7 +3963,8 @@ gam info cigroups <GroupEntity>
|
|||||||
[nosecurity|nosecuritysettings]
|
[nosecurity|nosecuritysettings]
|
||||||
[allfields|<CIGroupFieldName>*|(fields <CIGroupFieldNameList>)]
|
[allfields|<CIGroupFieldName>*|(fields <CIGroupFieldNameList>)]
|
||||||
[roles <GroupRoleList>] [members] [managers] [owners]
|
[roles <GroupRoleList>] [members] [managers] [owners]
|
||||||
[types <CIGroupTypeList>]
|
[internal] [internaldomains <DomainNameList>] [external]
|
||||||
|
[types <CIGroupMemberTypeList>]
|
||||||
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
||||||
[formatjson]
|
[formatjson]
|
||||||
gam print cigroups [todrive <ToDriveAttribute>*]
|
gam print cigroups [todrive <ToDriveAttribute>*]
|
||||||
@@ -3969,7 +3975,8 @@ gam print cigroups [todrive <ToDriveAttribute>*]
|
|||||||
[basic|allfields|(<CIGroupFieldName>* [fields <CIGroupFieldNameList>])]
|
[basic|allfields|(<CIGroupFieldName>* [fields <CIGroupFieldNameList>])]
|
||||||
[roles <GroupRoleList>] [memberrestrictions]
|
[roles <GroupRoleList>] [memberrestrictions]
|
||||||
[members|memberscount] [managers|managerscount] [owners|ownerscount] [totalcount] [countsonly]
|
[members|memberscount] [managers|managerscount] [owners|ownerscount] [totalcount] [countsonly]
|
||||||
[types <CIGroupTypeList>]
|
[internal] [internaldomains <DomainNameList>] [external]
|
||||||
|
[types <CIGroupMemberTypeList>]
|
||||||
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
||||||
[convertcrnl] [delimiter <Character>]
|
[convertcrnl] [delimiter <Character>]
|
||||||
[formatjson [quotechar <Character>]]
|
[formatjson [quotechar <Character>]]
|
||||||
@@ -3994,7 +4001,7 @@ gam print cigroup-members [todrive <ToDriveAttribute>*]
|
|||||||
[emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>]
|
[emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>]
|
||||||
[descriptionmatchpattern [not] <RegularExpression>]
|
[descriptionmatchpattern [not] <RegularExpression>]
|
||||||
[roles <GroupRoleList>] [members] [managers] [owners]
|
[roles <GroupRoleList>] [members] [managers] [owners]
|
||||||
[types <CIGroupTypeList>]
|
[types <CIGroupMemberTypeList>]
|
||||||
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
||||||
<CIGroupMembersFieldName>* [fields <CIGroupMembersFieldNameList>]
|
<CIGroupMembersFieldName>* [fields <CIGroupMembersFieldNameList>]
|
||||||
[(recursive [noduplicates])includederivedmembership] [nogroupeemail]
|
[(recursive [noduplicates])includederivedmembership] [nogroupeemail]
|
||||||
@@ -4005,7 +4012,7 @@ gam show cigroup-members
|
|||||||
[emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>]
|
[emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>]
|
||||||
[descriptionmatchpattern [not] <RegularExpression>]
|
[descriptionmatchpattern [not] <RegularExpression>]
|
||||||
[roles <GroupRoleList>] [members] [managers] [owners] [depth <Number>]
|
[roles <GroupRoleList>] [members] [managers] [owners] [depth <Number>]
|
||||||
[types <CIGroupTypeList>]
|
[types <CIGroupMemberTypeList>]
|
||||||
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
||||||
|
|
||||||
# Cloud Identity Devices
|
# Cloud Identity Devices
|
||||||
@@ -7814,7 +7821,8 @@ gam <UserTypeEntity> delete noteacl <NotesNameEntity>
|
|||||||
# Users - Licenses
|
# Users - Licenses
|
||||||
|
|
||||||
gam <UserTypeEntity> create|add license <SKUIDList> [product|productid <ProductID>] [preview] [actioncsv]
|
gam <UserTypeEntity> create|add license <SKUIDList> [product|productid <ProductID>] [preview] [actioncsv]
|
||||||
gam <UserTypeEntity> update license <SKUID> [product|productid <ProductID>] [from] <SKUID> [preview] [actioncsv]
|
gam <UserTypeEntity> update license <NewSKUID> [product|productid <ProductID>] [from] <OldSKUID>
|
||||||
|
[preview|archive] [actioncsv]
|
||||||
gam <UserTypeEntity> delete license <SKUIDList> [product|productid <ProductID>] [preview] [actioncsv]
|
gam <UserTypeEntity> delete license <SKUIDList> [product|productid <ProductID>] [preview] [actioncsv]
|
||||||
gam <UserTypeEntity> sync license <SKUIDList> [product|productid <ProductID>] [addonly|removeonly] [allskus|onesku] [preview] [actioncsv]
|
gam <UserTypeEntity> sync license <SKUIDList> [product|productid <ProductID>] [addonly|removeonly] [allskus|onesku] [preview] [actioncsv]
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,44 @@
|
|||||||
|
7.02.03
|
||||||
|
|
||||||
|
Added option `archive` to `gam <UserTypeEntity> update license <NewSKUID> from <OldSKUID>` that causes GAM
|
||||||
|
to archive `<UserTypeEntity>` after updating their license to `<NewSKUID>`. This will be used when you want to
|
||||||
|
archive a user with a non-archivable license. The `<NewSKUID>` license is assigned to the user and it then converts
|
||||||
|
to the equivalent Archived User license when the user is archived.
|
||||||
|
|
||||||
|
`<NewSKUID>` must be one of the following SKUs:
|
||||||
|
```
|
||||||
|
Google-Apps-Unlimited - G Suite Business
|
||||||
|
1010020020 - Google Workspace Enterprise Plus
|
||||||
|
1010020025 - Google Workspace Business Plus
|
||||||
|
1010020026 - Google Workspace Enterprise Standard
|
||||||
|
1010020027 - Google Workspace Business Starter
|
||||||
|
1010020028 - Google Workspace Business Standard
|
||||||
|
```
|
||||||
|
|
||||||
|
7.02.02
|
||||||
|
|
||||||
|
Updated `gam <UserTypeEntity> archive messages <GroupItem>` to retry the following unexpected error
|
||||||
|
that occurs after many messages have been successfully archived.
|
||||||
|
`ERROR: 404: notFound - Unable to lookup group`
|
||||||
|
|
||||||
|
7.02.01
|
||||||
|
|
||||||
|
Added options `locked` and `unlocked` to `gam update cigroups` that allow locking/unlocking groups.
|
||||||
|
|
||||||
|
* See: https://workspaceupdates.googleblog.com/2024/12/locked-groups-open-beta.html
|
||||||
|
|
||||||
|
You'll have to do a `gam oauth create` and enable the following scope to use these options:
|
||||||
|
```
|
||||||
|
[*] 22) Cloud Identity Groups API Beta (Enables group locking/unlocking)
|
||||||
|
```
|
||||||
|
|
||||||
|
7.02.00
|
||||||
|
|
||||||
|
Improved the error message displayed for user service account access commands when:
|
||||||
|
* The API is not enabled
|
||||||
|
* The user does not exist
|
||||||
|
* The user exists but is in a OU where the service is disabled
|
||||||
|
|
||||||
7.01.04
|
7.01.04
|
||||||
|
|
||||||
Admin role assignments are now in the v1 stable API, use that and remove custom local workaround for the beta. #1724
|
Admin role assignments are now in the v1 stable API, use that and remove custom local workaround for the beta. #1724
|
||||||
@@ -22,13 +63,13 @@ By default, when listing group members, GAM does not take the domain of the memb
|
|||||||
* `internal external internaldomains <DomainNameList>` - Display all members, indicate their category: internal or external
|
* `internal external internaldomains <DomainNameList>` - Display all members, indicate their category: internal or external
|
||||||
* `internaldomains <DomainNameList>` - Defaults to value of `domain` in `gam.cfg`
|
* `internaldomains <DomainNameList>` - Defaults to value of `domain` in `gam.cfg`
|
||||||
|
|
||||||
Members without an email address, e.g. `customer`, `chrome-os-device` and `cbcm-browser` are considered internal.
|
Members without an email address, e.g. `customer`, `chromeosdevice` and `cbcmbrowser` are considered internal.
|
||||||
|
|
||||||
Updated to Python 3.13.1.
|
Updated to Python 3.13.1.
|
||||||
|
|
||||||
7.01.03
|
7.01.03
|
||||||
|
|
||||||
Fixed bug in `gam update cigroups <GroupEntity> delete|sync|update` where `cbcm-browser` and `chrome-os_device`
|
Fixed bug in `gam update cigroups <GroupEntity> delete|sync|update` where `cbcmbrowser` and `chromeosdevice`
|
||||||
addresses were not properly handled.
|
addresses were not properly handled.
|
||||||
|
|
||||||
7.01.02
|
7.01.02
|
||||||
|
|||||||
@@ -97,13 +97,6 @@ else
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
reverse() {
|
|
||||||
for (( i = ${#*}; i > 0; i-- ))
|
|
||||||
{
|
|
||||||
echo ${!i}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ "$gamversion" == "latest" ]; then
|
if [ "$gamversion" == "latest" ]; then
|
||||||
release_url="https://api.github.com/repos/GAM-team/GAM/releases/latest"
|
release_url="https://api.github.com/repos/GAM-team/GAM/releases/latest"
|
||||||
elif [ "$gamversion" == "prerelease" -o "$gamversion" == "draft" ]; then
|
elif [ "$gamversion" == "prerelease" -o "$gamversion" == "draft" ]; then
|
||||||
@@ -126,9 +119,16 @@ release_json=$(curl \
|
|||||||
-H "Accept: application/vnd.github+json" \
|
-H "Accept: application/vnd.github+json" \
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||||
"$release_url" \
|
"$release_url" \
|
||||||
2>&1 /dev/null)
|
--fail-with-body)
|
||||||
|
curl_exit_code=$?
|
||||||
|
if [ $curl_exit_code -ne 0 ]; then
|
||||||
|
echo_red "ERROR retrieving URL: ${release_json}"
|
||||||
|
exit
|
||||||
|
else
|
||||||
|
echo_green "done"
|
||||||
|
fi
|
||||||
|
|
||||||
echo_yellow "Getting file and download URL..."
|
echo_yellow "Calculating download URL for this device..."
|
||||||
# Python is sadly the nearest to universal way to safely handle JSON with Bash
|
# Python is sadly the nearest to universal way to safely handle JSON with Bash
|
||||||
# At least this code should be compatible with just about any Python version ever
|
# At least this code should be compatible with just about any Python version ever
|
||||||
# unlike GAM itself. If some users don't have Python we can try grep / sed / etc
|
# unlike GAM itself. If some users don't have Python we can try grep / sed / etc
|
||||||
@@ -487,4 +487,3 @@ echo_green "GAM installation and setup complete!"
|
|||||||
if [ "$update_profile" = true ]; then
|
if [ "$update_profile" = true ]; then
|
||||||
echo_green "Please restart your terminal shell or to get started right away run:\n\n$alias_line"
|
echo_green "Please restart your terminal shell or to get started right away run:\n\n$alias_line"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
1349
src/gam/__init__.py
1349
src/gam/__init__.py
File diff suppressed because it is too large
Load Diff
@@ -45,10 +45,11 @@ CLASSROOM = 'classroom'
|
|||||||
CLOUDCHANNEL = 'cloudchannel'
|
CLOUDCHANNEL = 'cloudchannel'
|
||||||
CLOUDIDENTITY_DEVICES = 'cloudidentitydevices'
|
CLOUDIDENTITY_DEVICES = 'cloudidentitydevices'
|
||||||
CLOUDIDENTITY_GROUPS = 'cloudidentitygroups'
|
CLOUDIDENTITY_GROUPS = 'cloudidentitygroups'
|
||||||
|
CLOUDIDENTITY_GROUPS_BETA = 'cloudidentitygroupsbeta'
|
||||||
CLOUDIDENTITY_INBOUND_SSO = 'cloudidentityinboundsso'
|
CLOUDIDENTITY_INBOUND_SSO = 'cloudidentityinboundsso'
|
||||||
CLOUDIDENTITY_ORGUNITS = 'cloudidentityorgunits'
|
CLOUDIDENTITY_ORGUNITS = 'cloudidentityorgunits'
|
||||||
CLOUDIDENTITY_POLICY = 'cloudidentitypolicy'
|
|
||||||
CLOUDIDENTITY_ORGUNITS_BETA = 'cloudidentityorgunitsbeta'
|
CLOUDIDENTITY_ORGUNITS_BETA = 'cloudidentityorgunitsbeta'
|
||||||
|
CLOUDIDENTITY_POLICY = 'cloudidentitypolicy'
|
||||||
CLOUDIDENTITY_USERINVITATIONS = 'cloudidentityuserinvitations'
|
CLOUDIDENTITY_USERINVITATIONS = 'cloudidentityuserinvitations'
|
||||||
CLOUDRESOURCEMANAGER = 'cloudresourcemanager'
|
CLOUDRESOURCEMANAGER = 'cloudresourcemanager'
|
||||||
CONTACTS = 'contacts'
|
CONTACTS = 'contacts'
|
||||||
@@ -224,6 +225,7 @@ _INFO = {
|
|||||||
CLOUDCHANNEL: {'name': 'Channel Channel API', 'version': 'v1', 'v2discovery': True},
|
CLOUDCHANNEL: {'name': 'Channel Channel API', 'version': 'v1', 'v2discovery': True},
|
||||||
CLOUDIDENTITY_DEVICES: {'name': 'Cloud Identity Devices API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
CLOUDIDENTITY_DEVICES: {'name': 'Cloud Identity Devices API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||||
CLOUDIDENTITY_GROUPS: {'name': 'Cloud Identity Groups API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
CLOUDIDENTITY_GROUPS: {'name': 'Cloud Identity Groups API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||||
|
CLOUDIDENTITY_GROUPS_BETA: {'name': 'Cloud Identity Groups API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||||
CLOUDIDENTITY_INBOUND_SSO: {'name': 'Cloud Identity Inbound SSO API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
CLOUDIDENTITY_INBOUND_SSO: {'name': 'Cloud Identity Inbound SSO API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||||
CLOUDIDENTITY_ORGUNITS: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
CLOUDIDENTITY_ORGUNITS: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||||
CLOUDIDENTITY_ORGUNITS_BETA: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
CLOUDIDENTITY_ORGUNITS_BETA: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||||
@@ -361,6 +363,10 @@ _CLIENT_SCOPES = [
|
|||||||
'api': CLOUDIDENTITY_GROUPS,
|
'api': CLOUDIDENTITY_GROUPS,
|
||||||
'subscopes': READONLY,
|
'subscopes': READONLY,
|
||||||
'scope': 'https://www.googleapis.com/auth/cloud-identity.groups'},
|
'scope': 'https://www.googleapis.com/auth/cloud-identity.groups'},
|
||||||
|
{'name': 'Cloud Identity Groups API Beta (Enables group locking/unlocking)',
|
||||||
|
'api': CLOUDIDENTITY_GROUPS_BETA,
|
||||||
|
'subscopes': [],
|
||||||
|
'scope': 'https://www.googleapis.com/auth/cloud-identity.groups'},
|
||||||
{'name': 'Cloud Identity - Inbound SSO Settings',
|
{'name': 'Cloud Identity - Inbound SSO Settings',
|
||||||
'api': CLOUDIDENTITY_INBOUND_SSO,
|
'api': CLOUDIDENTITY_INBOUND_SSO,
|
||||||
'subscopes': READONLY,
|
'subscopes': READONLY,
|
||||||
|
|||||||
@@ -116,7 +116,6 @@ LABEL_MUTATION_ILLEGAL_SELECTION = 'labelMutationIllegalSelection'
|
|||||||
LABEL_MUTATION_UNKNOWN_FIELD = 'labelMutationUnknownField'
|
LABEL_MUTATION_UNKNOWN_FIELD = 'labelMutationUnknownField'
|
||||||
LIMIT_EXCEEDED = 'limitExceeded'
|
LIMIT_EXCEEDED = 'limitExceeded'
|
||||||
LOGIN_REQUIRED = 'loginRequired'
|
LOGIN_REQUIRED = 'loginRequired'
|
||||||
MAIL_SERVICE_NOT_ENABLED = 'mailServiceNotEnabled'
|
|
||||||
MALFORMED_WORKING_LOCATION_EVENT = 'malformedWorkingLocationEvent'
|
MALFORMED_WORKING_LOCATION_EVENT = 'malformedWorkingLocationEvent'
|
||||||
MEMBER_NOT_FOUND = 'memberNotFound'
|
MEMBER_NOT_FOUND = 'memberNotFound'
|
||||||
MYDRIVE_HIERARCHY_DEPTH_LIMIT_EXCEEDED = 'myDriveHierarchyDepthLimitExceeded'
|
MYDRIVE_HIERARCHY_DEPTH_LIMIT_EXCEEDED = 'myDriveHierarchyDepthLimitExceeded'
|
||||||
@@ -185,7 +184,7 @@ DEFAULT_RETRY_REASONS = [QUOTA_EXCEEDED, RATE_LIMIT_EXCEEDED, SHARING_RATE_LIMIT
|
|||||||
BACKEND_ERROR, BAD_GATEWAY, GATEWAY_TIMEOUT, INTERNAL_ERROR, TRANSIENT_ERROR]
|
BACKEND_ERROR, BAD_GATEWAY, GATEWAY_TIMEOUT, INTERNAL_ERROR, TRANSIENT_ERROR]
|
||||||
SERVICE_NOT_AVAILABLE_RETRY_REASONS = [SERVICE_NOT_AVAILABLE]
|
SERVICE_NOT_AVAILABLE_RETRY_REASONS = [SERVICE_NOT_AVAILABLE]
|
||||||
ACTIVITY_THROW_REASONS = [SERVICE_NOT_AVAILABLE, BAD_REQUEST]
|
ACTIVITY_THROW_REASONS = [SERVICE_NOT_AVAILABLE, BAD_REQUEST]
|
||||||
ALERT_THROW_REASONS = [SERVICE_NOT_AVAILABLE, AUTH_ERROR]
|
ALERT_THROW_REASONS = [SERVICE_NOT_AVAILABLE, AUTH_ERROR, PERMISSION_DENIED]
|
||||||
CALENDAR_THROW_REASONS = [SERVICE_NOT_AVAILABLE, AUTH_ERROR, NOT_A_CALENDAR_USER]
|
CALENDAR_THROW_REASONS = [SERVICE_NOT_AVAILABLE, AUTH_ERROR, NOT_A_CALENDAR_USER]
|
||||||
CIGROUP_CREATE_THROW_REASONS = [SERVICE_NOT_AVAILABLE, ALREADY_EXISTS, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, INVALID, INVALID_ARGUMENT, PERMISSION_DENIED, FAILED_PRECONDITION]
|
CIGROUP_CREATE_THROW_REASONS = [SERVICE_NOT_AVAILABLE, ALREADY_EXISTS, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, INVALID, INVALID_ARGUMENT, PERMISSION_DENIED, FAILED_PRECONDITION]
|
||||||
CIGROUP_GET_THROW_REASONS = [SERVICE_NOT_AVAILABLE, NOT_FOUND, GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, BAD_REQUEST, INVALID, SYSTEM_ERROR, PERMISSION_DENIED]
|
CIGROUP_GET_THROW_REASONS = [SERVICE_NOT_AVAILABLE, NOT_FOUND, GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, BAD_REQUEST, INVALID, SYSTEM_ERROR, PERMISSION_DENIED]
|
||||||
@@ -269,7 +268,7 @@ GROUP_SETTINGS_THROW_REASONS = [NOT_FOUND, GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DO
|
|||||||
GROUP_SETTINGS_RETRY_REASONS = [INVALID, SERVICE_LIMIT, SERVICE_NOT_AVAILABLE]
|
GROUP_SETTINGS_RETRY_REASONS = [INVALID, SERVICE_LIMIT, SERVICE_NOT_AVAILABLE]
|
||||||
GROUP_LIST_THROW_REASONS = [RESOURCE_NOT_FOUND, DOMAIN_NOT_FOUND, FORBIDDEN, BAD_REQUEST]
|
GROUP_LIST_THROW_REASONS = [RESOURCE_NOT_FOUND, DOMAIN_NOT_FOUND, FORBIDDEN, BAD_REQUEST]
|
||||||
GROUP_LIST_USERKEY_THROW_REASONS = GROUP_LIST_THROW_REASONS+[INVALID_MEMBER, INVALID_INPUT]
|
GROUP_LIST_USERKEY_THROW_REASONS = GROUP_LIST_THROW_REASONS+[INVALID_MEMBER, INVALID_INPUT]
|
||||||
KEEP_THROW_REASONS = [SERVICE_NOT_AVAILABLE, BAD_REQUEST, PERMISSION_DENIED, INVALID_ARGUMENT, NOT_FOUND]
|
KEEP_THROW_REASONS = [AUTH_ERROR, BAD_REQUEST, PERMISSION_DENIED, INVALID_ARGUMENT, NOT_FOUND]
|
||||||
LOOKERSTUDIO_THROW_REASONS = [INVALID_ARGUMENT, SERVICE_NOT_AVAILABLE, BAD_REQUEST, NOT_FOUND, PERMISSION_DENIED, INTERNAL_ERROR]
|
LOOKERSTUDIO_THROW_REASONS = [INVALID_ARGUMENT, SERVICE_NOT_AVAILABLE, BAD_REQUEST, NOT_FOUND, PERMISSION_DENIED, INTERNAL_ERROR]
|
||||||
MEMBERS_THROW_REASONS = [GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, INVALID, FORBIDDEN, SERVICE_NOT_AVAILABLE]
|
MEMBERS_THROW_REASONS = [GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, INVALID, FORBIDDEN, SERVICE_NOT_AVAILABLE]
|
||||||
MEMBERS_RETRY_REASONS = [SYSTEM_ERROR, SERVICE_NOT_AVAILABLE]
|
MEMBERS_RETRY_REASONS = [SYSTEM_ERROR, SERVICE_NOT_AVAILABLE]
|
||||||
@@ -278,8 +277,8 @@ PEOPLE_ACCESS_THROW_REASONS = [SERVICE_NOT_AVAILABLE, FORBIDDEN, PERMISSION_DENI
|
|||||||
RESELLER_THROW_REASONS = [BAD_REQUEST, RESOURCE_NOT_FOUND, FORBIDDEN, INVALID]
|
RESELLER_THROW_REASONS = [BAD_REQUEST, RESOURCE_NOT_FOUND, FORBIDDEN, INVALID]
|
||||||
SHEETS_ACCESS_THROW_REASONS = DRIVE_USER_THROW_REASONS+[NOT_FOUND, PERMISSION_DENIED, FORBIDDEN, INTERNAL_ERROR, INSUFFICIENT_FILE_PERMISSIONS,
|
SHEETS_ACCESS_THROW_REASONS = DRIVE_USER_THROW_REASONS+[NOT_FOUND, PERMISSION_DENIED, FORBIDDEN, INTERNAL_ERROR, INSUFFICIENT_FILE_PERMISSIONS,
|
||||||
BAD_REQUEST, INVALID, INVALID_ARGUMENT, FAILED_PRECONDITION]
|
BAD_REQUEST, INVALID, INVALID_ARGUMENT, FAILED_PRECONDITION]
|
||||||
TASK_THROW_REASONS = [SERVICE_NOT_AVAILABLE, BAD_REQUEST, PERMISSION_DENIED, INVALID, NOT_FOUND, ACCESS_NOT_CONFIGURED]
|
TASK_THROW_REASONS = [BAD_REQUEST, PERMISSION_DENIED, INVALID, NOT_FOUND, ACCESS_NOT_CONFIGURED]
|
||||||
TASKLIST_THROW_REASONS = [SERVICE_NOT_AVAILABLE, BAD_REQUEST, PERMISSION_DENIED, INVALID, NOT_FOUND, ACCESS_NOT_CONFIGURED]
|
TASKLIST_THROW_REASONS = [BAD_REQUEST, PERMISSION_DENIED, INVALID, NOT_FOUND, ACCESS_NOT_CONFIGURED]
|
||||||
USER_GET_THROW_REASONS = [USER_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, BAD_REQUEST, SYSTEM_ERROR]
|
USER_GET_THROW_REASONS = [USER_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, BAD_REQUEST, SYSTEM_ERROR]
|
||||||
YOUTUBE_THROW_REASONS = [SERVICE_NOT_AVAILABLE, AUTH_ERROR, UNSUPPORTED_SUPERVISED_ACCOUNT, UNSUPPORTED_LANGUAGE_CODE, CONTENT_OWNER_ACCOUNT_NOT_FOUND]
|
YOUTUBE_THROW_REASONS = [SERVICE_NOT_AVAILABLE, AUTH_ERROR, UNSUPPORTED_SUPERVISED_ACCOUNT, UNSUPPORTED_LANGUAGE_CODE, CONTENT_OWNER_ACCOUNT_NOT_FOUND]
|
||||||
|
|
||||||
@@ -537,8 +536,6 @@ class limitExceeded(Exception):
|
|||||||
pass
|
pass
|
||||||
class loginRequired(Exception):
|
class loginRequired(Exception):
|
||||||
pass
|
pass
|
||||||
class mailServiceNotEnabled(Exception):
|
|
||||||
pass
|
|
||||||
class malformedWorkingLocationEvent(Exception):
|
class malformedWorkingLocationEvent(Exception):
|
||||||
pass
|
pass
|
||||||
class memberNotFound(Exception):
|
class memberNotFound(Exception):
|
||||||
@@ -756,7 +753,6 @@ REASON_EXCEPTION_MAP = {
|
|||||||
LABEL_MUTATION_UNKNOWN_FIELD: labelMutationUnknownField,
|
LABEL_MUTATION_UNKNOWN_FIELD: labelMutationUnknownField,
|
||||||
LIMIT_EXCEEDED: limitExceeded,
|
LIMIT_EXCEEDED: limitExceeded,
|
||||||
LOGIN_REQUIRED: loginRequired,
|
LOGIN_REQUIRED: loginRequired,
|
||||||
MAIL_SERVICE_NOT_ENABLED: mailServiceNotEnabled,
|
|
||||||
MALFORMED_WORKING_LOCATION_EVENT: malformedWorkingLocationEvent,
|
MALFORMED_WORKING_LOCATION_EVENT: malformedWorkingLocationEvent,
|
||||||
MEMBER_NOT_FOUND: memberNotFound,
|
MEMBER_NOT_FOUND: memberNotFound,
|
||||||
NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE: noListTeamDrivesAdministratorPrivilege,
|
NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE: noListTeamDrivesAdministratorPrivilege,
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ ALREADY_EXISTS_USE_MERGE_ARGUMENT = 'Already exists; use the "merge" argument to
|
|||||||
API_ACCESS_DENIED = 'API access Denied'
|
API_ACCESS_DENIED = 'API access Denied'
|
||||||
API_CALLS_RETRY_DATA = 'API calls retry data\n'
|
API_CALLS_RETRY_DATA = 'API calls retry data\n'
|
||||||
API_CHECK_CLIENT_AUTHORIZATION = 'Please make sure the Client ID: {0} is authorized for the appropriate API or scopes:\n{1}\n\nRun: gam oauth create\n'
|
API_CHECK_CLIENT_AUTHORIZATION = 'Please make sure the Client ID: {0} is authorized for the appropriate API or scopes:\n{1}\n\nRun: gam oauth create\n'
|
||||||
API_CHECK_SVCACCT_AUTHORIZATION = 'Please make sure the Service Account Client name: {0} is authorized for the appropriate API or scopes:\n{1}\n\nRun: gam user {2} update serviceaccount\n'
|
API_CHECK_SVCACCT_AUTHORIZATION = 'Please make sure the Service Account Client ID: {0} is authorized for the appropriate API or scopes:\n{1}\n\nRun: gam user {2} update serviceaccount\n'
|
||||||
API_ERROR_SETTINGS = 'API error, some settings not set'
|
API_ERROR_SETTINGS = 'API error, some settings not set'
|
||||||
ARE_BOTH_REQUIRED = 'Arguments {0} and {1} are both required'
|
ARE_BOTH_REQUIRED = 'Arguments {0} and {1} are both required'
|
||||||
ARE_MUTUALLY_EXCLUSIVE = 'Arguments {0} and {1} are mutually exclusive'
|
ARE_MUTUALLY_EXCLUSIVE = 'Arguments {0} and {1} are mutually exclusive'
|
||||||
@@ -459,6 +459,7 @@ SERVICE_NOT_APPLICABLE = 'Service not applicable/Does not exist'
|
|||||||
SERVICE_NOT_APPLICABLE_THIS_ADDRESS = 'Service not applicable for this address: {0}'
|
SERVICE_NOT_APPLICABLE_THIS_ADDRESS = 'Service not applicable for this address: {0}'
|
||||||
SERVICE_NOT_ENABLED = '{0} Service/App not enabled'
|
SERVICE_NOT_ENABLED = '{0} Service/App not enabled'
|
||||||
SHORTCUT_TARGET_CAPABILITY_IS_FALSE = '{0} capability {1} is False'
|
SHORTCUT_TARGET_CAPABILITY_IS_FALSE = '{0} capability {1} is False'
|
||||||
|
SKU_HAS_NO_MATCHING_ARCHIVED_USER_SKU = 'SKU {0} has no matching Archived User SKU'
|
||||||
STARTING_THREAD = 'Starting thread'
|
STARTING_THREAD = 'Starting thread'
|
||||||
STATISTICS_COPY_FILE = 'Total: {0}, Copied: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Copy Failed: {5}, Not copyable: {6}, In skipids: {7}, Permissions Failed: {8}, Protected Ranges Failed: {9}'
|
STATISTICS_COPY_FILE = 'Total: {0}, Copied: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Copy Failed: {5}, Not copyable: {6}, In skipids: {7}, Permissions Failed: {8}, Protected Ranges Failed: {9}'
|
||||||
STATISTICS_COPY_FOLDER = 'Total: {0}, Copied: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Merged: {5}, Copy Failed: {6}, Not writable: {7}, Permissions Failed: {8}'
|
STATISTICS_COPY_FOLDER = 'Total: {0}, Copied: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Merged: {5}, Copy Failed: {6}, Not writable: {7}, Permissions Failed: {8}'
|
||||||
|
|||||||
@@ -182,6 +182,8 @@ _SKUS = {
|
|||||||
'product': 'Google-Chrome-Device-Management', 'aliases': ['chrome', 'cdm', 'googlechromedevicemanagement'], 'displayName': 'Google Chrome Device Management'}
|
'product': 'Google-Chrome-Device-Management', 'aliases': ['chrome', 'cdm', 'googlechromedevicemanagement'], 'displayName': 'Google Chrome Device Management'}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ARCHIVABLE_SKUS = {'1010020020', '1010020025', '1010020026', '1010020027', '1010020028', 'Google-Apps-Unlimited'}
|
||||||
|
|
||||||
def getProductAndSKU(sku):
|
def getProductAndSKU(sku):
|
||||||
l_sku = sku.lower().replace('-', '').replace(' ', '').replace('"', '').replace("'", '').strip()
|
l_sku = sku.lower().replace('-', '').replace(' ', '').replace('"', '').replace("'", '').strip()
|
||||||
if l_sku.startswith('nv:'):
|
if l_sku.startswith('nv:'):
|
||||||
|
|||||||
Reference in New Issue
Block a user